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