mirror of
https://github.com/SSCLI/sscli_20021101
synced 2026-06-08 12:28:57 +00:00
9fa3874800
Moved the original file to the archive subfolder.
325 lines
16 KiB
C#
325 lines
16 KiB
C#
// ==++==
|
|
//
|
|
//
|
|
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// The use and distribution terms for this software are contained in the file
|
|
// named license.txt, which can be found in the root of this distribution.
|
|
// By using this software in any fashion, you are agreeing to be bound by the
|
|
// terms of this license.
|
|
//
|
|
// You must not remove this notice, or any other, from this software.
|
|
//
|
|
//
|
|
// ==--==
|
|
namespace Microsoft.JScript
|
|
{
|
|
|
|
using Microsoft.JScript.Vsa;
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Text;
|
|
|
|
public sealed class FunctionDeclaration : AST{
|
|
internal FunctionObject func;
|
|
private Member declaringObject = null;
|
|
private TypeExpression ifaceId = null;
|
|
private String name;
|
|
internal bool isMethod;
|
|
private bool inFastScope = false;
|
|
private JSVariableField field = null;
|
|
internal JSProperty enclosingProperty = null;
|
|
private Completion completion = new Completion();
|
|
|
|
internal FunctionDeclaration(Context context, AST ifaceId, IdentifierLiteral id, ParameterDeclaration[] formal_parameters, TypeExpression return_type,
|
|
Block body, FunctionScope own_scope, FieldAttributes attributes,
|
|
bool isMethod, bool isGetter, bool isSetter, bool isAbstract, bool isFinal, CustomAttributeList customAttributes)
|
|
: base(context) {
|
|
MethodAttributes methodAttributes = (MethodAttributes)0;
|
|
if ((attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public)
|
|
methodAttributes = MethodAttributes.Public;
|
|
else if ((attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Private)
|
|
methodAttributes = MethodAttributes.Private;
|
|
else if ((attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Assembly)
|
|
methodAttributes = MethodAttributes.Assembly;
|
|
else if ((attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Family)
|
|
methodAttributes = MethodAttributes.Family;
|
|
else if ((attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamORAssem)
|
|
methodAttributes = MethodAttributes.FamORAssem;
|
|
else
|
|
methodAttributes = MethodAttributes.Public;
|
|
|
|
if ((attributes & FieldAttributes.Static) != 0 || !isMethod)
|
|
methodAttributes |= MethodAttributes.Static;
|
|
else
|
|
methodAttributes |= MethodAttributes.Virtual | MethodAttributes.NewSlot;
|
|
|
|
if (isAbstract)
|
|
methodAttributes |= MethodAttributes.Abstract;
|
|
if (isFinal)
|
|
methodAttributes |= MethodAttributes.Final;
|
|
|
|
this.name = id.ToString();
|
|
this.isMethod = isMethod;
|
|
if (ifaceId != null){
|
|
if (isMethod){
|
|
this.ifaceId = new TypeExpression(ifaceId);
|
|
methodAttributes &= ~MethodAttributes.MemberAccessMask;
|
|
methodAttributes |= MethodAttributes.Private|MethodAttributes.Final;
|
|
}else{
|
|
this.declaringObject = new Member(ifaceId.context, ifaceId, id);
|
|
this.name = this.declaringObject.ToString();
|
|
}
|
|
}
|
|
ScriptObject enclosingScope = Globals.ScopeStack.Peek();
|
|
if (attributes == 0 && !isAbstract && !isFinal){
|
|
if (enclosingScope is ClassScope)
|
|
attributes |= FieldAttributes.Public;
|
|
}else{
|
|
if (!(enclosingScope is ClassScope)){
|
|
this.context.HandleError(JSError.NotInsideClass);
|
|
attributes = (FieldAttributes)0;
|
|
methodAttributes = MethodAttributes.Public;
|
|
}
|
|
}
|
|
if (enclosingScope is ActivationObject){
|
|
this.inFastScope = ((ActivationObject)enclosingScope).fast;
|
|
// if later on originalName != this.name this is a property getter/setter
|
|
String originalName = this.name;
|
|
// mangle the name
|
|
if (isGetter){
|
|
methodAttributes |= MethodAttributes.SpecialName;
|
|
this.name = "get_" + this.name;
|
|
if (return_type == null)
|
|
return_type = new TypeExpression(new ConstantWrapper(Typeob.Object, context));
|
|
}else if (isSetter){
|
|
methodAttributes |= MethodAttributes.SpecialName;
|
|
this.name = "set_" + this.name;
|
|
return_type = new TypeExpression(new ConstantWrapper(Typeob.Void, context));
|
|
}
|
|
attributes &= FieldAttributes.FieldAccessMask;
|
|
// create the function object
|
|
this.func = new FunctionObject(this.name, formal_parameters, return_type, body, own_scope, enclosingScope, this.context,
|
|
methodAttributes, customAttributes, this.isMethod);
|
|
if (this.declaringObject != null) return;
|
|
// check whether the function name (possibly mangled) is in use already
|
|
String fieldName = this.name;
|
|
if (this.ifaceId != null) fieldName = ifaceId.ToString()+"."+fieldName;
|
|
JSVariableField localField = (JSVariableField)((ActivationObject)enclosingScope).name_table[fieldName];
|
|
if (localField != null && (!(localField is JSMemberField) || !(((JSMemberField)localField).value is FunctionObject) || this.func.isExpandoMethod)){
|
|
if (originalName != this.name)
|
|
localField.originalContext.HandleError(JSError.ClashWithProperty);
|
|
else{
|
|
id.context.HandleError(JSError.DuplicateName, this.func.isExpandoMethod);
|
|
if (localField.value is FunctionObject)
|
|
((FunctionObject)localField.value).suppressIL = true;
|
|
}
|
|
}
|
|
// create or update the proper field
|
|
if (this.isMethod){
|
|
if (!(localField is JSMemberField) || !(((JSMemberField)localField).value is FunctionObject) || originalName != this.name){
|
|
this.field = ((ActivationObject)enclosingScope).AddNewField(fieldName, this.func, attributes|FieldAttributes.Literal);
|
|
if (originalName == this.name) // if it is a property do not assign the type
|
|
((JSVariableField)this.field).type = new TypeExpression(new ConstantWrapper(Typeob.FunctionWrapper, this.context));
|
|
}else
|
|
this.field = ((JSMemberField)localField).AddOverload(this.func, attributes|FieldAttributes.Literal);
|
|
}else if (enclosingScope is FunctionScope){
|
|
if (this.inFastScope) attributes |= FieldAttributes.Literal;
|
|
this.field = ((FunctionScope)enclosingScope).AddNewField(this.name, attributes, this.func);
|
|
if (this.field is JSLocalField){
|
|
JSLocalField locField = (JSLocalField)this.field;
|
|
if (this.inFastScope){
|
|
locField.type = new TypeExpression(new ConstantWrapper(Typeob.ScriptFunction, this.context));
|
|
locField.attributeFlags |= FieldAttributes.Literal;
|
|
}
|
|
locField.debugOn = this.context.document.debugOn;
|
|
locField.isDefined = true;
|
|
}
|
|
}else if (this.inFastScope){
|
|
this.field = ((ActivationObject)enclosingScope).AddNewField(this.name, this.func, attributes|FieldAttributes.Literal);
|
|
((JSVariableField)this.field).type = new TypeExpression(new ConstantWrapper(Typeob.ScriptFunction, this.context));
|
|
//Do not use typeof(Closure) for the field, since that has the arguments and callee properties, which are not
|
|
//accessible in fast mode
|
|
}else //enclosingScope is GlobalObject
|
|
this.field = ((ActivationObject)enclosingScope).AddNewField(this.name, this.func, attributes|FieldAttributes.Static);
|
|
((JSVariableField)this.field).originalContext = context;
|
|
|
|
// if it is a property create/update the PropertyInfo and assign the getter/setter
|
|
if (originalName != this.name){
|
|
String propertyFieldName = originalName;
|
|
if (this.ifaceId != null) propertyFieldName = ifaceId.ToString()+"."+originalName;
|
|
FieldInfo prop = (FieldInfo)((ClassScope)enclosingScope).name_table[propertyFieldName];
|
|
if (prop != null){
|
|
// check whether a property was defined already
|
|
if (prop.IsLiteral){
|
|
Object val = ((JSVariableField)prop).value;
|
|
if (val is JSProperty)
|
|
this.enclosingProperty = (JSProperty)val;
|
|
}
|
|
if (this.enclosingProperty == null)
|
|
id.context.HandleError(JSError.DuplicateName, true); // the matching name was not a property
|
|
}
|
|
if (this.enclosingProperty == null){
|
|
this.enclosingProperty = new JSProperty(originalName);
|
|
prop = ((ActivationObject)enclosingScope).AddNewField(propertyFieldName, this.enclosingProperty, attributes|FieldAttributes.Literal);
|
|
((JSMemberField)prop).originalContext = this.context;
|
|
}else{
|
|
if ((isGetter && this.enclosingProperty.getter != null) || (isSetter && this.enclosingProperty.setter != null))
|
|
id.context.HandleError(JSError.DuplicateName, true); // duplicated setter or getter
|
|
}
|
|
if (isGetter)
|
|
this.enclosingProperty.getter = new JSFieldMethod(this.field, enclosingScope);
|
|
else
|
|
this.enclosingProperty.setter = new JSFieldMethod(this.field, enclosingScope);
|
|
}
|
|
}else{ //Might get here if function declaration is inside of an eval.
|
|
this.inFastScope = false;
|
|
this.func = new FunctionObject(this.name, formal_parameters, return_type, body, own_scope, enclosingScope, this.context, MethodAttributes.Public, null, false);
|
|
this.field = ((StackFrame)enclosingScope).AddNewField(this.name, new Closure(this.func), attributes|FieldAttributes.Static);
|
|
}
|
|
}
|
|
|
|
internal override Object Evaluate(){
|
|
if (this.declaringObject != null)
|
|
this.declaringObject.SetValue(this.func);
|
|
return this.completion;
|
|
}
|
|
|
|
public static Closure JScriptFunctionDeclaration(RuntimeTypeHandle handle, String name, String method_name, String[] formal_parameters,
|
|
JSLocalField[] fields, bool must_save_stack_locals, bool hasArgumentsObject, String text, Object declaringObject, VsaEngine engine){
|
|
Type t = Type.GetTypeFromHandle(handle);
|
|
FunctionObject func = new FunctionObject(t, name, method_name, formal_parameters, fields, must_save_stack_locals, hasArgumentsObject, text, engine);
|
|
return new Closure(func, declaringObject);
|
|
}
|
|
|
|
internal override Context GetFirstExecutableContext(){
|
|
return null;
|
|
}
|
|
|
|
internal override AST PartiallyEvaluate(){
|
|
if (this.ifaceId != null){
|
|
this.ifaceId.PartiallyEvaluate();
|
|
this.func.implementedIface = this.ifaceId.ToIReflect();
|
|
Type t = this.func.implementedIface as Type;
|
|
ClassScope csc = this.func.implementedIface as ClassScope;
|
|
if (t != null && !t.IsInterface || csc != null && !csc.owner.isInterface){
|
|
this.ifaceId.context.HandleError(JSError.NeedInterface);
|
|
this.func.implementedIface = null;
|
|
}
|
|
if ((this.func.attributes & MethodAttributes.Abstract) != 0)
|
|
this.func.funcContext.HandleError(JSError.AbstractCannotBePrivate);
|
|
}else if (this.declaringObject != null)
|
|
this.declaringObject.PartiallyEvaluateAsCallable();
|
|
this.func.PartiallyEvaluate();
|
|
if (this.inFastScope && this.func.isExpandoMethod && this.field != null && this.field.type != null)
|
|
this.field.type.expression = new ConstantWrapper(Typeob.ScriptFunction, null);
|
|
if ((this.func.attributes & MethodAttributes.Abstract) != 0 &&
|
|
!((ClassScope)this.func.enclosing_scope).owner.isAbstract){
|
|
((ClassScope)this.func.enclosing_scope).owner.attributes |= TypeAttributes.Abstract;
|
|
((ClassScope)this.func.enclosing_scope).owner.context.HandleError(JSError.CannotBeAbstract, this.name);
|
|
}
|
|
if (this.enclosingProperty != null)
|
|
if (!this.enclosingProperty.GetterAndSetterAreConsistent())
|
|
this.context.HandleError(JSError.GetAndSetAreInconsistent);
|
|
return this;
|
|
}
|
|
|
|
private void TranslateToILClosure(ILGenerator il){
|
|
if (!this.func.isStatic)
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Ldtoken, this.func.classwriter != null ? this.func.classwriter : compilerGlobals.classwriter);
|
|
il.Emit(OpCodes.Ldstr, this.name);
|
|
il.Emit(OpCodes.Ldstr, this.func.GetName());
|
|
int n = this.func.formal_parameters.Length;
|
|
ConstantWrapper.TranslateToILInt(il, n);
|
|
il.Emit(OpCodes.Newarr, Typeob.String);
|
|
for (int i = 0; i < n; i++){
|
|
il.Emit(OpCodes.Dup);
|
|
ConstantWrapper.TranslateToILInt(il, i);
|
|
il.Emit(OpCodes.Ldstr, this.func.formal_parameters[i]);
|
|
il.Emit(OpCodes.Stelem_Ref);
|
|
}
|
|
n = this.func.fields.Length;
|
|
ConstantWrapper.TranslateToILInt(il, n);
|
|
il.Emit(OpCodes.Newarr, CompilerGlobals.jsLocalFieldClass);
|
|
for (int i = 0; i < n; i++){
|
|
JSLocalField field = this.func.fields[i];
|
|
il.Emit(OpCodes.Dup);
|
|
ConstantWrapper.TranslateToILInt(il, i);
|
|
il.Emit(OpCodes.Ldstr, field.Name);
|
|
il.Emit(OpCodes.Ldtoken, field.FieldType);
|
|
ConstantWrapper.TranslateToILInt(il, field.slotNumber);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.jsLocalFieldConstructor);
|
|
il.Emit(OpCodes.Stelem_Ref);
|
|
}
|
|
if (this.func.must_save_stack_locals)
|
|
il.Emit(OpCodes.Ldc_I4_1);
|
|
else
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
if (this.func.hasArgumentsObject)
|
|
il.Emit(OpCodes.Ldc_I4_1);
|
|
else
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ldstr, this.func.ToString());
|
|
if (!this.func.isStatic)
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
else
|
|
il.Emit(OpCodes.Ldnull);
|
|
this.EmitILToLoadEngine(il);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.jScriptFunctionDeclarationMethod);
|
|
}
|
|
|
|
internal override void TranslateToIL(ILGenerator il, Type rtype){
|
|
Debug.PreCondition(rtype == Typeob.Void);
|
|
return;
|
|
}
|
|
|
|
internal override void TranslateToILInitializer(ILGenerator il){
|
|
if (this.func.suppressIL) return;
|
|
this.func.TranslateToIL(compilerGlobals);
|
|
if (this.declaringObject != null){
|
|
this.declaringObject.TranslateToILInitializer(il);
|
|
this.declaringObject.TranslateToILPreSet(il);
|
|
this.TranslateToILClosure(il);
|
|
this.declaringObject.TranslateToILSet(il);
|
|
return;
|
|
}
|
|
Object tok = ((JSVariableField)this.field).metaData;
|
|
if (this.func.isMethod){
|
|
if (tok is FunctionDeclaration){
|
|
((JSVariableField)this.field).metaData = null;
|
|
return;
|
|
}
|
|
this.TranslateToILSourceTextProvider();
|
|
return;
|
|
}
|
|
if (tok == null) return;
|
|
this.TranslateToILClosure(il);
|
|
if (tok is LocalBuilder)
|
|
il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
|
|
else if (this.func.isStatic)
|
|
il.Emit(OpCodes.Stsfld, (FieldInfo)tok);
|
|
else
|
|
il.Emit(OpCodes.Stfld, (FieldInfo)tok);
|
|
}
|
|
|
|
private void TranslateToILSourceTextProvider(){
|
|
if (this.Engine.doFast) return;
|
|
StringBuilder sb = new StringBuilder(this.func.ToString());
|
|
JSMemberField mf = ((JSMemberField)this.field).nextOverload;
|
|
while (mf != null){
|
|
mf.metaData = this;
|
|
sb.Append('\n');
|
|
sb.Append(mf.value.ToString());
|
|
mf = mf.nextOverload;
|
|
}
|
|
MethodAttributes attr = MethodAttributes.Public|MethodAttributes.Static;
|
|
MethodBuilder mb = ((ClassScope)(this.func.enclosing_scope)).GetTypeBuilder().DefineMethod(this.name+" source", attr, Typeob.String, new Type[0]);
|
|
ILGenerator il = mb.GetILGenerator();
|
|
il.Emit(OpCodes.Ldstr, sb.ToString());
|
|
il.Emit(OpCodes.Ret);
|
|
}
|
|
}
|
|
}
|