Files
yallie 9fa3874800 Added the contents of the archive.
Moved the original file to the archive subfolder.
2017-11-20 16:11:42 +03:00

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);
}
}
}