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

1457 lines
69 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.Collections;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
internal class Class : AST{
internal String name;
private TypeExpression superTypeExpression;
private TypeExpression[] interfaces;
internal Block body;
internal ScriptObject enclosingScope;
internal TypeAttributes attributes;
private bool hasAlreadyBeenAskedAboutExpando;
internal bool isAbstract;
private bool isAlreadyPartiallyEvaluated;
private bool isCooked;
private Type cookedType;
private bool isExpando;
internal bool isInterface;
internal bool isStatic;
protected bool needsEngine;
internal AttributeTargets validOn;
internal bool allowMultiple;
protected ClassScope classob;
private FunctionObject implicitDefaultConstructor;
private JSVariableField ownField;
protected JSMemberField[] fields;
private Class superClass;
private IReflect superIR;
private Object[] superMembers;
private SimpleHashtable firstIndex;
private MethodInfo fieldInitializer;
internal CustomAttributeList customAttributes;
internal CLSComplianceSpec clsCompliance;
// expando related fields
private bool generateCodeForExpando; // true if this class is the first expando class in a hierarchy chain
private PropertyBuilder expandoItemProp;
private MethodBuilder getHashTableMethod;
private MethodBuilder getItem;
private MethodBuilder setItem;
internal MethodBuilder deleteOpMethod;
internal Class(Context context, AST id, TypeExpression superTypeExpression, TypeExpression[] interfaces, Block body,
FieldAttributes attributes, bool isAbstract, bool isFinal, bool isStatic, bool isInterface, CustomAttributeList customAttributes)
: base(context) {
this.name = id.ToString();
this.superTypeExpression = superTypeExpression;
this.interfaces = interfaces;
this.body = body;
this.enclosingScope = (ScriptObject)Globals.ScopeStack.Peek(1);
this.attributes = TypeAttributes.Class|TypeAttributes.Serializable;
this.SetAccessibility(attributes);
if (isAbstract)
this.attributes |= TypeAttributes.Abstract;
this.isAbstract = isAbstract || isInterface;
this.isAlreadyPartiallyEvaluated = false;
if (isFinal)
this.attributes |= TypeAttributes.Sealed;
if (isInterface)
this.attributes |= TypeAttributes.Interface | TypeAttributes.Abstract;
this.isCooked = false;
this.cookedType = null;
this.isExpando = false;
this.isInterface = isInterface;
this.isStatic = isStatic;
this.needsEngine = !isInterface;
this.validOn = (AttributeTargets)0;
this.allowMultiple = true;
this.classob = (ClassScope)Globals.ScopeStack.Peek();
this.classob.name = this.name;
this.classob.owner = this;
this.implicitDefaultConstructor = null;
if (!isInterface && !(this is EnumDeclaration))
this.SetupConstructors();
this.EnterNameIntoEnclosingScopeAndGetOwnField(id, isStatic);
this.fields = this.classob.GetMemberFields();
this.superClass = null;
this.superIR = null;
this.superMembers = null;
this.firstIndex = null;
this.fieldInitializer = null;
this.customAttributes = customAttributes;
this.clsCompliance = CLSComplianceSpec.NotAttributed;
this.generateCodeForExpando = false;
this.expandoItemProp = null;
this.getHashTableMethod = null;
this.getItem = null;
this.setItem = null;
}
private void AddImplicitInterfaces(IReflect iface, IReflect[] explicitInterfaces, ArrayList implicitInterfaces){
Type ifaceT = iface as Type;
if (ifaceT != null){
Type[] implInterfaces = ifaceT.GetInterfaces();
foreach (Type implIface in implInterfaces){
if (Array.IndexOf(explicitInterfaces, implIface, 0) >= 0) return;
if (implicitInterfaces.IndexOf(implIface, 0) >= 0) return;
implicitInterfaces.Add(implIface);
}
return;
}
foreach (TypeExpression ifaceExpr in ((ClassScope)iface).owner.interfaces){
IReflect implIface = ifaceExpr.ToIReflect();
if (Array.IndexOf(explicitInterfaces, implIface, 0) >= 0) return;
if (implicitInterfaces.IndexOf(implIface, 0) >= 0) return;
implicitInterfaces.Add(implIface);
}
return;
}
private void AllocateImplicitDefaultConstructor(){
this.implicitDefaultConstructor = new FunctionObject(".ctor", new ParameterDeclaration[0], null, new Block(this.context),
new FunctionScope(this.classob, true), this.classob, this.context, MethodAttributes.Virtual|MethodAttributes.NewSlot|MethodAttributes.Public, null, true);
this.implicitDefaultConstructor.isImplicitCtor = true;
this.implicitDefaultConstructor.isConstructor = true;
this.implicitDefaultConstructor.proto = this.classob;
}
private bool CanSee(MemberInfo member){
switch (member.MemberType){
case MemberTypes.Method:
{MethodAttributes visibility = ((MethodBase)member).Attributes & MethodAttributes.MemberAccessMask;
if (visibility == MethodAttributes.Private || visibility == MethodAttributes.PrivateScope || visibility == MethodAttributes.FamANDAssem)
return false;
if (visibility == MethodAttributes.Assembly)
return IsInTheSamePackage(member);
return true;}
case MemberTypes.Field:
{FieldAttributes visibility = ((FieldInfo)member).Attributes & FieldAttributes.FieldAccessMask;
if (visibility == FieldAttributes.Private || visibility == FieldAttributes.PrivateScope || visibility == FieldAttributes.FamANDAssem)
return false;
if (visibility == FieldAttributes.Assembly)
return IsInTheSamePackage(member);
return true;}
case MemberTypes.Property:
{MethodBase propMethod = JSProperty.GetGetMethod((PropertyInfo)member, true);
if (propMethod == null)
propMethod = JSProperty.GetSetMethod((PropertyInfo)member, true);
if (propMethod == null)
return false;
else{
MethodAttributes visibility = propMethod.Attributes & MethodAttributes.MemberAccessMask;
if (visibility == MethodAttributes.Private || visibility == MethodAttributes.PrivateScope || visibility == MethodAttributes.FamANDAssem)
return false;
if (visibility == MethodAttributes.Assembly)
return IsInTheSamePackage(member);
}
return true;}
case MemberTypes.Event:
{MethodBase addMethod = ((EventInfo)member).GetAddMethod();
if (addMethod == null)
return false;
else{
MethodAttributes visibility = addMethod.Attributes & MethodAttributes.MemberAccessMask;
if (visibility == MethodAttributes.Private || visibility == MethodAttributes.PrivateScope || visibility == MethodAttributes.FamANDAssem)
return false;
if (visibility == MethodAttributes.Assembly)
return IsInTheSamePackage(member);
}
return true;}
case MemberTypes.TypeInfo:
case MemberTypes.NestedType:
{TypeAttributes visibility = ((Type)member).Attributes & TypeAttributes.VisibilityMask;
if (visibility == TypeAttributes.NestedPrivate || visibility == TypeAttributes.NestedFamANDAssem)
return false;
if (visibility == TypeAttributes.NestedAssembly)
return IsInTheSamePackage(member);
return true;}
}
return true;
}
private void CheckFieldDeclarationConsistency(JSMemberField field){
Object index = this.firstIndex[field.Name];
if (index == null) return; //There is no super class member with the same name as the field
for (int i = (int)index, n = this.superMembers.Length; i < n; i++){
Object supMem = this.superMembers[i];
if (!(supMem is MemberInfo)) return;
MemberInfo member = (MemberInfo)supMem;
if (!member.Name.Equals(field.Name)) return;
if (this.CanSee(member)){
String supMemberName = this.GetFullNameFor(member);
field.originalContext.HandleError(JSError.HidesParentMember, supMemberName, this.IsInTheSameCompilationUnit(member));
return;
}
}
}
private void CheckIfOKToGenerateCodeForExpando(bool superClassIsExpando){
if (superClassIsExpando){
this.context.HandleError(JSError.BaseClassIsExpandoAlready);
this.generateCodeForExpando = false;
return;
}
// make sure the current class does not define an Item property
if (this.classob.GetMember("Item", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly).Length > 0){
this.context.HandleError(JSError.ItemNotAllowedOnExpandoClass);
this.generateCodeForExpando = false;
return;
}
if (this.classob.GetMember("get_Item", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly).Length > 0 ||
this.classob.GetMember("set_Item", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly).Length > 0){
this.context.HandleError(JSError.MethodNotAllowedOnExpandoClass);
this.generateCodeForExpando = false;
return;
}
// make sure the current class does not implements IEnumerable
if (this.ImplementsInterface(Typeob.IEnumerable)){
this.context.HandleError(JSError.ExpandoClassShouldNotImpleEnumerable);
this.generateCodeForExpando = false;
return;
}
// make sure up in the hierarchy chain no property named 'Item' is defined
if (this.superIR.GetMember("Item", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance).Length > 0 ||
this.superIR.GetMember("get_Item", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance).Length > 0 ||
this.superIR.GetMember("set_Item", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance).Length > 0){
this.context.HandleError(JSError.MethodClashOnExpandoSuperClass);
this.generateCodeForExpando = false;
return;
}
// add an expando property to the current class for Binding to find
JSProperty itemProp = this.classob.itemProp = new JSProperty("Item");
itemProp.getter = new JSExpandoIndexerMethod(this.classob, true);
itemProp.setter = new JSExpandoIndexerMethod(this.classob, false);
this.classob.AddNewField("Item", itemProp, FieldAttributes.Literal);
}
private String GetFullName(){
String scopeName = ((ActivationObject)this.enclosingScope).GetName();
if (scopeName == null){
VsaEngine engine = this.context.document.engine;
if (engine != null && engine.genStartupClass)
scopeName = engine.RootNamespace;
}
if (scopeName != null)
return scopeName + "." + this.name;
else
return this.name;
}
protected void CheckMemberNamesForCLSCompliance(){
// Check top-level class name for CLS compliance.
if (!(this.enclosingScope is ClassScope))
this.Engine.CheckTypeNameForCLSCompliance(this.name, this.GetFullName(), this.context);
// Check is all member names are CLS compliant
Hashtable caseInsensitiveNameTable = new Hashtable(new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture), new CaseInsensitiveComparer(CultureInfo.InvariantCulture));
for (int i = 0, n = this.fields.Length; i < n; i++){
JSMemberField field = this.fields[i];
if (!VsaEngine.CheckIdentifierForCLSCompliance(field.Name))
field.originalContext.HandleError(JSError.NonCLSCompliantMember);
else{
if ((JSMemberField)caseInsensitiveNameTable[field.Name] == null)
caseInsensitiveNameTable.Add(field.Name, field);
else
field.originalContext.HandleError(JSError.NonCLSCompliantMember);
}
}
}
private void CheckIfValidExtensionOfSuperType(){
this.GetIRForSuperType();
ClassScope csc = this.superIR as ClassScope;
if (csc != null){
csc.owner.PartiallyEvaluate();
if (this.IsStatic){
if (!csc.owner.IsStatic){
this.superTypeExpression.context.HandleError(JSError.NestedInstanceTypeCannotBeExtendedByStatic);
this.superIR = Typeob.Object;
this.superTypeExpression = null;
}
}else{
if (!csc.owner.IsStatic && this.enclosingScope != csc.owner.enclosingScope){
this.superTypeExpression.context.HandleError(JSError.NestedInstanceTypeCannotBeExtendedByStatic);
this.superIR = Typeob.Object;
this.superTypeExpression = null;
}
}
}
this.GetSuperTypeMembers();
this.GetStartIndexForEachName();
bool checkCLSCompliance = this.NeedsToBeCheckedForCLSCompliance();
if (checkCLSCompliance)
this.CheckMemberNamesForCLSCompliance();
//First check only the methods the implement interfaces
for (int i = 0, n = this.fields.Length; i < n; i++){
JSMemberField field = this.fields[i];
if (field.IsLiteral){
Object value = field.value;
if (value is FunctionObject){
JSMemberField startMethod = field;
while(true){
FunctionObject func = (FunctionObject)value;
if (func.implementedIface == null) break;
this.CheckMethodDeclarationConsistency(func);
if (func.implementedIfaceMethod == null)
func.funcContext.HandleError(JSError.NoMethodInBaseToOverride);
if (field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly)
func.CheckCLSCompliance(checkCLSCompliance);
field = field.nextOverload;
if (field == null) break;
value = field.value;
}
continue;
}else if (value is JSProperty){
continue;
}
}
}
for (int i = 0, n = this.fields.Length; i < n; i++){
JSMemberField field = this.fields[i];
if (field.IsLiteral){
Object value = field.value;
if (value is FunctionObject){
JSMemberField startMethod = field;
while(true){
FunctionObject func = (FunctionObject)value;
if (func.implementedIface != null) break;
this.CheckMethodDeclarationConsistency(func);
if (field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly)
func.CheckCLSCompliance(checkCLSCompliance);
field = field.nextOverload;
if (field == null) break;
value = field.value;
}
continue;
}else if (value is JSProperty){
continue;
}
}
this.CheckFieldDeclarationConsistency(field);
if (field.IsPublic || field.IsFamily || field.IsFamilyOrAssembly)
field.CheckCLSCompliance(checkCLSCompliance);
}
}
private void CheckMethodDeclarationConsistency(FunctionObject func){
if (func.isStatic && !func.isExpandoMethod) return; //static methods do not clash with superclass methods
if (func.isConstructor) return; //Constructors cannot clash with superclass members
Object index = this.firstIndex[func.name];
if (index == null){
//There is no super class member with the same name as the function
this.CheckThatMethodIsNotMarkedWithOverrideOrHide(func);
if ((func.attributes & MethodAttributes.Final) != 0)
func.attributes &= ~(MethodAttributes.Virtual|MethodAttributes.NewSlot|MethodAttributes.Final);
return;
}
MemberInfo differentTypeOfMember = null;
for (int i = (int)index, n = this.superMembers.Length; i < n; i++){
MemberInfo member = this.superMembers[i] as MemberInfo;
if (member == null)
//if we do not get a MemberInfo we have already processed this superclass member and it matches another member of the current class
continue;
if (!member.Name.Equals(func.name)) break;
if (!this.CanSee(member)) continue;
if (member.MemberType != MemberTypes.Method){
//JScript does not allow overloading among different member types.
//Unless there is a superclass method with the same signature as the method, we have to give an error
differentTypeOfMember = member;
continue;
}
if (func.isExpandoMethod){
differentTypeOfMember = member;
break;
}
MethodInfo supmeth = (MethodInfo)member;
if (func.implementedIface != null){
//Skip superclass methods that do not come from the appropriate interface
if (supmeth is JSFieldMethod){
if (((JSFieldMethod)supmeth).EnclosingScope() != func.implementedIface) continue;
}else{
if (supmeth.DeclaringType != func.implementedIface) continue;
}
}
if (Class.ParametersMatch(supmeth.GetParameters(), func.parameter_declarations)){
if (supmeth is JSWrappedMethod)
supmeth = ((JSWrappedMethod)supmeth).method;
if (func.noVersionSafeAttributeSpecified || (func.attributes & MethodAttributes.VtableLayoutMask) != MethodAttributes.NewSlot){
//Check consistency of implicit or explicit override (a hiding method may be inconsistent)
this.CheckMatchingMethodForConsistency(supmeth, func, i, n);
}
return;
}
}
if (differentTypeOfMember != null){
//Did not find a superclass method with the same signature, but did find a member with same name that was not a method
//This is a no no for JScript unless the hide attribute has been specified
if (func.noVersionSafeAttributeSpecified ||
(func.attributes & MethodAttributes.VtableLayoutMask) != MethodAttributes.NewSlot && !func.isExpandoMethod){
String supMemberName = this.GetFullNameFor(differentTypeOfMember);
func.funcContext.HandleError(JSError.HidesParentMember, supMemberName, this.IsInTheSameCompilationUnit(differentTypeOfMember));
}
return;
}
//No matching method in superclass. Give an error if hide/override was specified
this.CheckThatMethodIsNotMarkedWithOverrideOrHide(func);
//Make final methods into non virtual
if ((func.attributes & MethodAttributes.Final) != 0)
func.attributes &= ~(MethodAttributes.Virtual|MethodAttributes.NewSlot|MethodAttributes.Final);
}
private void CheckMatchingMethodForConsistency(MethodInfo matchingMethod, FunctionObject func, int i, int n){
// return-type consistency - the return-type has to be the same
IReflect rir = func.ReturnType(null);
IReflect mrir = matchingMethod is JSFieldMethod ? ((JSFieldMethod)matchingMethod).func.ReturnType(null) : matchingMethod.ReturnType;
if (!rir.Equals(mrir)){
func.funcContext.HandleError(JSError.DifferentReturnTypeFromBase, func.name, true);
return;
}
//Special treatment for methods that implement interface methods
if (func.implementedIface != null){
func.implementedIfaceMethod = matchingMethod;
this.superMembers[i] = func.name; //obliterate it so that it does not show up as unimplemented
return;
}
// visibility consistency - the visibility specification has to be the same
MethodAttributes visibility = func.attributes & MethodAttributes.MemberAccessMask;
if ((matchingMethod.Attributes & MethodAttributes.MemberAccessMask) != visibility)
//Allow Family to match FamORAssem
if ((matchingMethod.Attributes & MethodAttributes.MemberAccessMask) != MethodAttributes.FamORAssem || visibility != MethodAttributes.Family)
func.funcContext.HandleError(JSError.CannotChangeVisibility);
// hiding, overriding and layout consistency
// if i >= 0 after this, the base method is an overridden abstract method and steps should be taken to prevent a not implemented error
if (func.noVersionSafeAttributeSpecified){ // current method does not specify any attribute (i.e. hide or override)
if (this.Engine.versionSafe){
//Give a message. The compiler option requires a method to say hide or override when there is a match.
if ((matchingMethod.Attributes & MethodAttributes.Abstract) != 0){ // base is abstract
func.funcContext.HandleError(JSError.HidesAbstractInBase, this.name + "." + func.name);
func.attributes &= ~MethodAttributes.NewSlot;
//Recover from error by overriding, it may be less bad than throwing a class load exception
}else{
func.funcContext.HandleError(JSError.NewNotSpecifiedInMethodDeclaration, this.IsInTheSameCompilationUnit(matchingMethod));
i = -1;
}
}else{
//No message, override if possible, otherwise hide
if ((matchingMethod.Attributes & MethodAttributes.Virtual) == 0 ||
(matchingMethod.Attributes & MethodAttributes.Final) != 0){ // base is non virtual or final, hide
i = -1;
}else{
func.attributes &= ~MethodAttributes.NewSlot; //override
if ((matchingMethod.Attributes & MethodAttributes.Abstract) == 0)
i = -1;
}
}
}else{ //Current method is marked override or hide
if ((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.ReuseSlot){ // current method specifies override
if ((matchingMethod.Attributes & MethodAttributes.Virtual) == 0 ||
(matchingMethod.Attributes & MethodAttributes.Final) != 0){ // base is non virtual or final, hide
func.funcContext.HandleError(JSError.MethodInBaseIsNotVirtual);
i = -1;
}else{
func.attributes &= ~MethodAttributes.NewSlot; //override
if ((matchingMethod.Attributes & MethodAttributes.Abstract) == 0)
i = -1;
}
}else{ // current method specifies hide
Debug.Assert((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.NewSlot);
if ((matchingMethod.Attributes & MethodAttributes.Abstract) != 0){ // base is abstract
func.funcContext.HandleError(JSError.HidesAbstractInBase, this.name + "." + func.name);
func.attributes &= ~MethodAttributes.NewSlot;
//Recover from error by overriding, it may be less bad than throwing a class load exception
}else
i = -1;
}
}
if (i >= 0){
//Overriding an abstract method. Take steps to prevent error messages.
Debug.Assert((matchingMethod.Attributes & MethodAttributes.Abstract) != 0);
this.superMembers[i] = func.name; //obliterate it so that it does not show up as unimplemented
//Do likewise for any matching abstract members declared in less derived base classes
for (int j = i+1; j < n; j++){ //Most derived class is always first
MemberInfo mem = this.superMembers[j] as MemberInfo;
if (mem == null) continue;
if (mem.Name != matchingMethod.Name) break;
MethodInfo meth2 = mem as MethodInfo;
if (meth2 == null) continue;
if (meth2.IsAbstract && Class.ParametersMatch(meth2.GetParameters(), matchingMethod.GetParameters())){
IReflect rt = matchingMethod is JSFieldMethod ? ((JSFieldMethod)matchingMethod).ReturnIR() : matchingMethod.ReturnType;
IReflect rt2 = meth2 is JSFieldMethod ? ((JSFieldMethod)meth2).ReturnIR() : meth2.ReturnType;
if (rt == rt2) this.superMembers[j] = func.name;
}
}
}
}
private void CheckThatAllAbstractSuperClassMethodsAreImplemented(){
//By the time we get here all abstract superclass members that are implemented by this class are already replaced by
//their names in superMembers. What remains is to weed out those that are implemented by more derived base classes
//and then to complain about any that are left over.
for (int i = 0, n = this.superMembers.Length; i < n; i++){
Object ob = this.superMembers[i];
MethodInfo meth = ob as MethodInfo;
if (meth != null){
if (!meth.IsAbstract) continue;
//Check to see if implemented by a more derived base class
for (int j = i-1; j >= 0; j--){
Object mem = this.superMembers[j];
if (mem is MethodInfo){
MethodInfo meth2 = (MethodInfo)mem;
if (meth2.Name != meth.Name) break;
if (!meth2.IsAbstract && Class.ParametersMatch(meth2.GetParameters(), meth.GetParameters())){
IReflect rt = meth is JSFieldMethod ? ((JSFieldMethod)meth).ReturnIR() : meth.ReturnType;
IReflect rt2 = meth2 is JSFieldMethod ? ((JSFieldMethod)meth2).ReturnIR() : meth2.ReturnType;
if (rt == rt2){
this.superMembers[i] = meth.Name;
goto noError;
}
}
}
}
//Nope, give an error (unless class is marked abstract, but not if the method comes from an interface)
if (!this.isAbstract || (!this.isInterface && Class.DefinedOnInterface(meth))){
StringBuilder sig = new StringBuilder(meth.DeclaringType.ToString());
sig.Append('.');
sig.Append(meth.Name);
sig.Append('(');
ParameterInfo[] pars = meth.GetParameters();
for (int j = 0, m = pars.Length; j < m; j++){
sig.Append(pars[j].ParameterType.FullName);
if (j < m-1)
sig.Append(", ");
}
sig.Append(")");
if (meth.ReturnType != Typeob.Void){
sig.Append(" : ");
sig.Append(meth.ReturnType.FullName);
}
this.context.HandleError(JSError.MustImplementMethod, sig.ToString());
this.attributes |= TypeAttributes.Abstract; //Make the class compilable
}
//If the super class method comes from an interface, emit an abstract method that implements it
}
noError:;
}
}
private void CheckThatMethodIsNotMarkedWithOverrideOrHide(FunctionObject func){
if (func.noVersionSafeAttributeSpecified) return;
//It is marked override or hide, give an appropriate error
if ((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.ReuseSlot) // current method specifies override
func.funcContext.HandleError(JSError.NoMethodInBaseToOverride);
else // current method specifies hide
func.funcContext.HandleError(JSError.NoMethodInBaseToNew);
}
private static bool DefinedOnInterface(MethodInfo meth){
JSFieldMethod jsmeth = meth as JSFieldMethod;
if (jsmeth != null) return ((ClassScope)jsmeth.func.enclosing_scope).owner.isInterface;
return meth.DeclaringType.IsInterface;
}
private void EmitILForINeedEngineMethods(){
if (!this.needsEngine)
return;
TypeBuilder classwriter = (TypeBuilder)this.classob.classwriter;
FieldBuilder backingField = classwriter.DefineField("vsa Engine", typeof(VsaEngine), FieldAttributes.Private | FieldAttributes.NotSerialized);
MethodBuilder getMeth = classwriter.DefineMethod("GetEngine", MethodAttributes.Private|MethodAttributes.Virtual, typeof(VsaEngine), null);
ILGenerator il = getMeth.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, backingField);
il.Emit(OpCodes.Ldnull);
Label endif = il.DefineLabel();
il.Emit(OpCodes.Bne_Un_S, endif);
il.Emit(OpCodes.Ldarg_0);
if (this.body.Engine.doCRS)
il.Emit(OpCodes.Ldsfld, CompilerGlobals.contextEngineField);
else {
if (this.context.document.engine.PEFileKind == PEFileKinds.Dll){
il.Emit(OpCodes.Ldtoken, classwriter);
il.Emit(OpCodes.Call, CompilerGlobals.createVsaEngineWithType);
}else
il.Emit(OpCodes.Call, CompilerGlobals.createVsaEngine);
}
il.Emit(OpCodes.Stfld, backingField);
il.MarkLabel(endif);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, backingField);
il.Emit(OpCodes.Ret);
classwriter.DefineMethodOverride(getMeth, CompilerGlobals.getEngineMethod);
MethodBuilder setMeth = classwriter.DefineMethod("SetEngine", MethodAttributes.Private|MethodAttributes.Virtual, Typeob.Void, new Type[]{typeof(VsaEngine)});
il = setMeth.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stfld, backingField);
il.Emit(OpCodes.Ret);
classwriter.DefineMethodOverride(setMeth, CompilerGlobals.setEngineMethod);
}
internal void EmitInitialCalls(ILGenerator il, MethodBase supcons, ParameterInfo[] pars, ASTList argAST, int callerParameterCount){
bool callFieldInitializer = true;
if (supcons != null){
il.Emit(OpCodes.Ldarg_0);
int n = pars.Length;
int m = argAST == null ? 0 : argAST.count;
Object[] tempArray = new Object[n];
for (int i = 0; i < n; i++){
AST actual = i < m ? argAST[i] : new ConstantWrapper(null, null);
if (pars[i].ParameterType.IsByRef)
tempArray[i] = actual.TranslateToILReference(il, pars[i].ParameterType.GetElementType());
else{
actual.TranslateToIL(il, pars[i].ParameterType);
tempArray[i] = null;
}
}
if (supcons is JSConstructor){
JSConstructor cons = (JSConstructor)supcons;
callFieldInitializer = cons.GetClassScope() != this.classob;
supcons = cons.GetConstructorInfo(this.compilerGlobals);
//if cons belongs to a nested instance class, load the outer class instance on the stack
if (cons.GetClassScope().outerClassField != null)
Convert.EmitLdarg(il, (short)callerParameterCount);
}
il.Emit(OpCodes.Call, (ConstructorInfo)supcons);
for (int i = 0; i < m; i++){
AST arg = argAST[i];
if (arg is AddressOf && tempArray[i] != null){
Type argType = Convert.ToType(arg.InferType(null));
arg.TranslateToILPreSet(il);
il.Emit(OpCodes.Ldloc, (LocalBuilder)tempArray[i]);
Convert.Emit(this, il, pars[i].ParameterType, argType);
arg.TranslateToILSet(il);
}
}
}
if (this.classob.outerClassField != null){
il.Emit(OpCodes.Ldarg_0);
Convert.EmitLdarg(il, (short)callerParameterCount);
il.Emit(OpCodes.Stfld, this.classob.outerClassField);
}
if (callFieldInitializer){
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, this.fieldInitializer);
((Block)(this.body)).TranslateToILInitOnlyInitializers(il);
}
}
private void EnterNameIntoEnclosingScopeAndGetOwnField(AST id, bool isStatic){
if (((IActivationObject)this.enclosingScope).GetLocalField(this.name) != null){
id.context.HandleError(JSError.DuplicateName, true);
this.name = this.name + " class";
}
FieldAttributes fieldAttrs = FieldAttributes.Literal;
switch (this.attributes & TypeAttributes.VisibilityMask){
case TypeAttributes.NestedAssembly : fieldAttrs |= FieldAttributes.Assembly; break;
case TypeAttributes.NestedFamANDAssem : fieldAttrs |= FieldAttributes.FamANDAssem; break;
case TypeAttributes.NestedFamily : fieldAttrs |= FieldAttributes.Family; break;
case TypeAttributes.NestedFamORAssem : fieldAttrs |= FieldAttributes.FamORAssem; break;
case TypeAttributes.NestedPrivate : fieldAttrs |= FieldAttributes.Private; break;
default: fieldAttrs |= FieldAttributes.Public; break;
}
ScriptObject enclScope = this.enclosingScope;
while (enclScope is BlockScope) enclScope = enclScope.GetParent();
if (!(enclScope is GlobalScope) && !(enclScope is PackageScope) && !(enclScope is ClassScope)){
isStatic = false;
if (this is EnumDeclaration)
this.context.HandleError(JSError.EnumNotAllowed);
else
this.context.HandleError(JSError.ClassNotAllowed);
}
if (isStatic) fieldAttrs |= FieldAttributes.Static;
if (this.enclosingScope is ActivationObject){
if (this.enclosingScope is ClassScope){
if (this.name == ((ClassScope)this.enclosingScope).name){
context.HandleError(JSError.CannotUseNameOfClass);
this.name = this.name + " nested class";
}
}
this.ownField = ((ActivationObject)this.enclosingScope).AddNewField(this.name, this.classob, fieldAttrs);
if (this.ownField is JSLocalField)
((JSLocalField)this.ownField).isDefined = true;
}else
this.ownField = ((StackFrame)this.enclosingScope).AddNewField(this.name, this.classob, fieldAttrs);
this.ownField.originalContext = id.context;
}
internal override Object Evaluate(){
this.Globals.ScopeStack.GuardedPush(this.classob);
try{
this.body.EvaluateStaticVariableInitializers();
}finally{
this.Globals.ScopeStack.Pop();
}
return new Completion();
}
// generate the field containing the expando hashtable and the default indexer
private void GenerateGetEnumerator(){
TypeBuilder classwriter = this.classob.GetTypeBuilder();
MethodBuilder getEnumerator = classwriter.DefineMethod("get enumerator", MethodAttributes.Private|MethodAttributes.Virtual, Typeob.IEnumerator, null);
ILGenerator il = getEnumerator.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, this.getHashTableMethod);
il.Emit(OpCodes.Call, CompilerGlobals.hashTableGetEnumerator);
il.Emit(OpCodes.Ret);
classwriter.DefineMethodOverride(getEnumerator, CompilerGlobals.getEnumeratorMethod);
}
// generate the field containing the expando hashtable and the default indexer
private void GetExpandoFieldGetter(TypeBuilder classwriter){
if (this.expandoItemProp == null){
this.expandoItemProp = classwriter.DefineProperty("Item", PropertyAttributes.None, Typeob.Object, new Type[]{Typeob.String});
// if it is an expando, generate a SimpleHashtable field called 'expando table'
FieldInfo expandoTableField = classwriter.DefineField("expando table", Typeob.SimpleHashtable, FieldAttributes.Private);
// generate code for a hashtable getter. It will initialize the hashtable if null
this.getHashTableMethod = classwriter.DefineMethod("get expando table", MethodAttributes.Private, Typeob.SimpleHashtable, null);
ILGenerator il = this.getHashTableMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, expandoTableField);
il.Emit(OpCodes.Ldnull);
Label endif = il.DefineLabel();
il.Emit(OpCodes.Bne_Un_S, endif);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4_8);
il.Emit(OpCodes.Newobj, CompilerGlobals.hashtableCtor);
il.Emit(OpCodes.Stfld, expandoTableField);
il.MarkLabel(endif);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, expandoTableField);
il.Emit(OpCodes.Ret);
}
}
// can be called from outside this class (JSExpandoIndexerMethod)
internal MethodInfo GetExpandoIndexerGetter(){
if (this.getItem == null){
TypeBuilder classwriter = this.classob.GetTypeBuilder();
this.GetExpandoFieldGetter(classwriter);
// create the getter
this.getItem = classwriter.DefineMethod("get_Item", MethodAttributes.Public|MethodAttributes.SpecialName, Typeob.Object, new Type[]{Typeob.String});
ILGenerator il = this.getItem.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, this.getHashTableMethod);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, CompilerGlobals.hashtableGetItem);
il.Emit(OpCodes.Dup);
Label endif = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, endif);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldsfld, CompilerGlobals.missingField);
il.MarkLabel(endif);
il.Emit(OpCodes.Ret);
this.expandoItemProp.SetGetMethod(this.getItem);
}
return this.getItem;
}
// can be called from outside this class (JSExpandoIndexerMethod)
internal MethodInfo GetExpandoIndexerSetter(){
if (this.setItem == null){
TypeBuilder classwriter = this.classob.GetTypeBuilder();
this.GetExpandoFieldGetter(classwriter);
// create the setter
this.setItem = classwriter.DefineMethod("set_Item", MethodAttributes.Public|MethodAttributes.SpecialName, Typeob.Void, new Type[2]{Typeob.String, Typeob.Object});
ILGenerator il = this.setItem.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, this.getHashTableMethod);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldsfld, CompilerGlobals.missingField);
Label endif = il.DefineLabel();
il.Emit(OpCodes.Beq_S, endif);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Call, CompilerGlobals.hashtableSetItem);
il.Emit(OpCodes.Ret);
il.MarkLabel(endif);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, CompilerGlobals.hashtableRemove);
il.Emit(OpCodes.Ret);
this.expandoItemProp.SetSetMethod(this.setItem);
}
return this.setItem;
}
private void GetExpandoDeleteMethod(){
TypeBuilder tb = this.classob.GetTypeBuilder();
MethodBuilder mb = this.deleteOpMethod = tb.DefineMethod("op_Delete", MethodAttributes.Public|MethodAttributes.Static|MethodAttributes.SpecialName,
Typeob.Boolean, new Type[2]{tb, typeof(Object[])});
ParameterBuilder pb = mb.DefineParameter(2, (ParameterAttributes)0, null);
pb.SetCustomAttribute(new CustomAttributeBuilder(Typeob.ParamArrayAttribute.GetConstructor(Type.EmptyTypes), new Object[]{}));
ILGenerator il = mb.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, this.getHashTableMethod);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Ldelem_Ref);
il.Emit(OpCodes.Call, CompilerGlobals.hashtableRemove);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ret);
}
private String GetFullNameFor(MemberInfo supMem){
String supMemberName;
if (supMem is JSField)
supMemberName = ((JSField)supMem).GetClassFullName();
else if (supMem is JSConstructor)
supMemberName = ((JSConstructor)supMem).GetClassFullName();
else if (supMem is JSMethod)
supMemberName = ((JSMethod)supMem).GetClassFullName();
else if (supMem is JSProperty)
supMemberName = ((JSProperty)supMem).GetClassFullName();
else if (supMem is JSWrappedProperty)
supMemberName = ((JSWrappedProperty)supMem).GetClassFullName();
else
supMemberName = ((MemberInfo)supMem).DeclaringType.FullName;
return supMemberName + "." + ((MemberInfo)supMem).Name;
}
internal MemberInfo[] GetInterfaceMember(String name){
this.PartiallyEvaluate();
MemberInfo[] result;
if (this.isInterface){
result = this.classob.GetMember(name, BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
if (result != null && result.Length > 0) return result;
}
foreach (TypeExpression ifaceExpr in this.interfaces){
IReflect ir = ifaceExpr.ToIReflect();
result = ir.GetMember(name, BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
if (result != null && result.Length > 0) return result;
}
return new MemberInfo[0];
}
private void GetIRForSuperType(){
IReflect supIR = this.superIR = Typeob.Object;
if (this.superTypeExpression != null){
this.superTypeExpression.PartiallyEvaluate();
supIR = this.superIR = this.superTypeExpression.ToIReflect();
}
Type supType = supIR as Type;
if (supType != null){
if (supType.IsSealed || supType.IsInterface || supType == typeof(ValueType) || supType == Typeob.ArrayObject){
if (this.superTypeExpression.Evaluate() is Namespace)
this.superTypeExpression.context.HandleError(JSError.NeedType);
else
this.superTypeExpression.context.HandleError(JSError.TypeCannotBeExtended, supType.FullName);
this.superTypeExpression = null;
this.superIR = Typeob.Object;
}else if (typeof(INeedEngine).IsAssignableFrom(supType))
this.needsEngine = false;
}else if (supIR is ClassScope){
if (((ClassScope)supIR).owner.IsASubClassOf(this)){
this.superTypeExpression.context.HandleError(JSError.CircularDefinition);
this.superTypeExpression = null;
this.superIR = Typeob.Object;
}else{
this.needsEngine = false;
this.superClass = ((ClassScope)supIR).owner;
if ((this.superClass.attributes & TypeAttributes.Sealed) != 0){
this.superTypeExpression.context.HandleError(JSError.TypeCannotBeExtended, this.superClass.name);
this.superClass.attributes &= ~TypeAttributes.Sealed;
this.superTypeExpression = null;
}else if (this.superClass.isInterface){
this.superTypeExpression.context.HandleError(JSError.TypeCannotBeExtended, this.superClass.name);
this.superIR = Typeob.Object;
this.superTypeExpression = null;
}
}
}else{
this.superTypeExpression.context.HandleError(JSError.TypeCannotBeExtended);
this.superIR = Typeob.Object;
this.superTypeExpression = null;
}
}
private void GetStartIndexForEachName(){
SimpleHashtable firstIndex = new SimpleHashtable(32);
String lastName = null;
for (int i = 0, n = this.superMembers.Length; i < n; i++){
String name = ((MemberInfo)this.superMembers[i]).Name;
if (name != lastName)
firstIndex[lastName = name] = i;
}
this.firstIndex = firstIndex;
}
internal ConstructorInfo GetSuperConstructor(IReflect[] argIRs){
Object val = null;
if (this.superTypeExpression != null)
val = this.superTypeExpression.Evaluate();
else
val = Typeob.Object;
if (val is ClassScope)
return JSBinder.SelectConstructor(((ClassScope)val).constructors, argIRs);
else
return JSBinder.SelectConstructor(((Type)val).GetConstructors(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance), argIRs);
}
private void GetSuperTypeMembers(){
SuperTypeMembersSorter sorter = new SuperTypeMembersSorter();
IReflect ir = this.superIR;
//Add members on superclasses
while (ir != null){
sorter.Add(ir.GetMembers(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly));
if (ir is Type){
ir = ((Type)ir).BaseType;
}else{
ir = ((ClassScope)ir).GetSuperType();
}
}
//Add any implicit interfaces to the end of the explicit list of interfaces
ArrayList implicitInterfaces = new ArrayList();
int n = this.interfaces.Length;
IReflect[] explicitInterfaces = new IReflect[n];
for (int i = 0; i < n; i++){
IReflect iface = explicitInterfaces[i] = this.interfaces[i].ToIReflect();
Type t = iface as Type;
bool isInterface;
if (t != null)
isInterface = t.IsInterface;
else{
ClassScope csc = (ClassScope)iface;
isInterface = csc.owner.isInterface;
}
if (!isInterface) this.interfaces[i].context.HandleError(JSError.NeedInterface);
}
foreach (IReflect iface in explicitInterfaces)
this.AddImplicitInterfaces(iface, explicitInterfaces, implicitInterfaces);
for (int i = 0; i < implicitInterfaces.Count; i++){
IReflect iface = (IReflect)implicitInterfaces[i];
this.AddImplicitInterfaces(iface, explicitInterfaces, implicitInterfaces);
}
int m = implicitInterfaces.Count;
if (m > 0){
TypeExpression[] newInterfaces = new TypeExpression[n + m];
for (int i = 0; i < n; i++) newInterfaces[i] = this.interfaces[i];
for (int i = 0; i < m; i++) newInterfaces[i+n] = new TypeExpression(new ConstantWrapper(implicitInterfaces[i], null));
this.interfaces = newInterfaces;
}
//Add members on interfaces implemented by the class. Also check for circular definition;
foreach (TypeExpression ifaceExpr in this.interfaces){
ClassScope ifcsc = ifaceExpr.ToIReflect() as ClassScope;
if (ifcsc != null && ifcsc.owner.ImplementsInterface(this.classob)){
this.context.HandleError(JSError.CircularDefinition);
this.interfaces = new TypeExpression[0];
break;
}
sorter.Add(ifaceExpr.ToIReflect().GetMembers(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance));
}
//Add unimplemented members on interfaces implemented by abstract superclasses
ir = this.superIR;
while (ir != null){
Type type = ir as Type;
if (type != null){
if (!type.IsAbstract) break;
Class.GetUnimplementedInferfaceMembersFor(type, sorter);
ir = type.BaseType;
}else{
ClassScope csc = (ClassScope)ir;
if (!csc.owner.isAbstract) break;
csc.owner.GetUnimplementedInferfaceMembers(sorter);
ir = null;
}
}
this.superMembers = sorter.GetMembers();
}
internal TypeBuilder GetTypeBuilder(){
return (TypeBuilder)this.GetTypeBuilderOrEnumBuilder();
}
internal virtual Type GetTypeBuilderOrEnumBuilder(){
if (this.classob.classwriter != null) return this.classob.classwriter;
if (!this.isAlreadyPartiallyEvaluated) this.PartiallyEvaluate();
Type superType = null;
if (this.superTypeExpression != null)
superType = this.superTypeExpression.ToType();
else
superType = this.isInterface ? null : Typeob.Object;
int offset = (this.needsEngine ? 1 : 0) + (this.generateCodeForExpando ? 1 : 0);
int n = this.interfaces.Length+offset;
Type[] interfaces = new Type[n];
for (int i = offset; i < n; i++)
interfaces[i] = this.interfaces[i-offset].ToType();
if (this.needsEngine)
interfaces[--offset] = typeof(INeedEngine);
if (this.generateCodeForExpando)
interfaces[--offset] = Typeob.IEnumerable;
TypeBuilder result;
if (this.enclosingScope is ClassScope){
if ((result = (TypeBuilder)this.classob.classwriter) == null){
TypeBuilder enclosingClass = ((ClassScope)this.enclosingScope).owner.GetTypeBuilder();
if (this.classob.classwriter != null) return this.classob.classwriter;
result = enclosingClass.DefineNestedType(this.name, this.attributes, superType, interfaces);
this.classob.classwriter = result;
if (!this.isStatic && !this.isInterface)
this.classob.outerClassField = result.DefineField("outer class instance", enclosingClass, FieldAttributes.Private);
}
}else{
String scopeName = ((ActivationObject)this.enclosingScope).GetName();
if (scopeName == null){
VsaEngine engine = this.context.document.engine;
if (engine != null && engine.genStartupClass)
scopeName = engine.RootNamespace;
}
if ((result = (TypeBuilder)this.classob.classwriter) == null){
if (scopeName != null)
result = compilerGlobals.module.DefineType(scopeName+"."+this.name, this.attributes, superType, interfaces);
else
result = compilerGlobals.module.DefineType(this.name, this.attributes, superType, interfaces);
this.classob.classwriter = result;
}
}
// deal with custom attributes
if (this.customAttributes != null){
CustomAttributeBuilder[] custAtt = this.customAttributes.GetCustomAttributeBuilders(false);
for (int j = 0; j < custAtt.Length; j++){
result.SetCustomAttribute(custAtt[j]);
}
}
if (this.clsCompliance == CLSComplianceSpec.CLSCompliant)
result.SetCustomAttribute(new CustomAttributeBuilder(CompilerGlobals.clsCompliantAttributeCtor, new Object[]{true}));
else if (this.clsCompliance == CLSComplianceSpec.NonCLSCompliant)
result.SetCustomAttribute(new CustomAttributeBuilder(CompilerGlobals.clsCompliantAttributeCtor, new Object[]{false}));
if (this.generateCodeForExpando)
result.SetCustomAttribute(new CustomAttributeBuilder(CompilerGlobals.defaultMemberAttributeCtor, new Object[]{"Item"}));
//Define the class fields
for (int i = 0, m = this.fields.Length; i < m; i++){
JSMemberField field = this.fields[i];
if (field.IsLiteral){
Object value = field.value;
if (value is JSProperty){
JSProperty prop = (JSProperty)value;
ParameterInfo[] pars = prop.GetIndexParameters();
int np = pars.Length;
Type[] ptypes = new Type[np];
for (int j = 0; j < np; j++)
ptypes[j] = pars[j].ParameterType;
PropertyBuilder pb = prop.metaData = result.DefineProperty(field.Name, prop.Attributes, prop.PropertyType, ptypes);
if (prop.getter != null){
CustomAttributeList cal = ((JSFieldMethod)prop.getter).func.customAttributes;
if (cal != null){
CustomAttributeBuilder[] custAttrs = cal.GetCustomAttributeBuilders(true);
foreach (CustomAttributeBuilder cb in custAttrs) pb.SetCustomAttribute(cb);
}
pb.SetGetMethod((MethodBuilder)prop.getter.GetMethodInfo(compilerGlobals));
}
if (prop.setter != null){
CustomAttributeList cal = ((JSFieldMethod)prop.setter).func.customAttributes;
if (cal != null){
CustomAttributeBuilder[] custAttrs = cal.GetCustomAttributeBuilders(true);
foreach (CustomAttributeBuilder cb in custAttrs) pb.SetCustomAttribute(cb);
}
pb.SetSetMethod((MethodBuilder)prop.setter.GetMethodInfo(compilerGlobals));
}
continue;
}else if (value is ClassScope){
((ClassScope)value).GetTypeBuilderOrEnumBuilder();
}else if (Convert.GetTypeCode(value) != TypeCode.Object){
FieldBuilder fb = result.DefineField(field.Name, field.FieldType, field.Attributes);
fb.SetConstant(field.value);
field.metaData = fb;
field.WriteCustomAttribute(this.Engine.doCRS);
continue;
}else if (value is FunctionObject){
FunctionObject func = (FunctionObject)value;
if (func.isExpandoMethod){
field.metaData = result.DefineField(field.Name, Typeob.ScriptFunction, field.Attributes&~(FieldAttributes.Literal|FieldAttributes.Static));
func.isStatic = false;
}
if (this.isInterface)
do{
func.GetMethodInfo(compilerGlobals);
field = field.nextOverload;
if (field == null) break;
func = (FunctionObject)field.value;
}while(true);
}
continue;
}
field.metaData = result.DefineField(field.Name, field.FieldType, field.Attributes);
field.WriteCustomAttribute(this.Engine.doCRS);
}
return result;
}
private void GetUnimplementedInferfaceMembers(SuperTypeMembersSorter sorter){
for (int i = 0, n = this.superMembers.Length; i < n; i++){
MethodInfo meth = this.superMembers[i] as MethodInfo;
if (meth != null && meth.DeclaringType.IsInterface)
sorter.Add(meth);
}
return;
}
private static void GetUnimplementedInferfaceMembersFor(Type type, SuperTypeMembersSorter sorter){
foreach (Type iface in type.GetInterfaces()){
InterfaceMapping imap = type.GetInterfaceMap(iface);
MethodInfo[] interfaceMethods = imap.InterfaceMethods;
MethodInfo[] targetMethods = imap.TargetMethods;
for (int i = 0, n = interfaceMethods.Length; i < n; i++)
if (targetMethods[i] == null || targetMethods[i].IsAbstract) sorter.Add(interfaceMethods[i]);
}
}
internal bool ImplementsInterface(IReflect iface){
foreach (TypeExpression t in this.interfaces){
IReflect ir = t.ToIReflect();
if (ir == iface) return true;
if (ir is ClassScope && ((ClassScope)ir).ImplementsInterface(iface)) return true;
if (ir is Type && iface is Type && ((Type)iface).IsAssignableFrom((Type)ir)) return true;
}
return false;
}
private bool IsASubClassOf(Class cl){
if (this.superTypeExpression != null){
this.superTypeExpression.PartiallyEvaluate();
IReflect supertype = this.superTypeExpression.ToIReflect();
if (supertype is ClassScope){
Class superclass = ((ClassScope)supertype).owner;
if (superclass == cl)
return true;
else
return superclass.IsASubClassOf(cl);
}
}
return false;
}
internal bool IsCustomAttribute(){
this.GetIRForSuperType();
if (this.superIR != typeof(System.Attribute)) return false;
if (this.customAttributes == null) return false;
this.customAttributes.PartiallyEvaluate();
if (this.validOn == 0) return false;
return true;
}
internal bool IsExpando(){
if (this.hasAlreadyBeenAskedAboutExpando)
return this.isExpando;
if (this.customAttributes != null){
this.customAttributes.PartiallyEvaluate();
if (this.customAttributes.GetAttribute(Typeob.Expando) != null)
this.generateCodeForExpando = this.isExpando = true;
}
bool superClassIsExpando = false;
this.GetIRForSuperType();
if (this.superIR is ClassScope){
if (((ClassScope)this.superIR).owner.IsExpando())
this.isExpando = superClassIsExpando = true;
}else{
if (((Type)this.superIR).IsDefined(Typeob.Expando, true))
this.isExpando = superClassIsExpando = true;
}
this.hasAlreadyBeenAskedAboutExpando = true;
if (this.generateCodeForExpando)
this.CheckIfOKToGenerateCodeForExpando(superClassIsExpando);
if (this.isExpando){
this.classob.noExpando = false;
return true;
}
return false;
}
private bool IsInTheSameCompilationUnit(MemberInfo member){
return member is JSField || member is JSMethod;
}
private bool IsInTheSamePackage(MemberInfo member){
if (member is JSMethod || member is JSField){
PackageScope memberPackage = null;
if (member is JSMethod)
memberPackage = ((JSMethod)member).GetPackage();
else if (member is JSConstructor)
memberPackage = ((JSConstructor)member).GetPackage();
else
memberPackage = ((JSField)member).GetPackage();
PackageScope currentPackage = this.classob.GetPackage();
return currentPackage == memberPackage;
}else
return false;
}
internal bool IsStatic{
get{
return (this.isStatic || !(this.enclosingScope is ClassScope));
}
}
protected bool NeedsToBeCheckedForCLSCompliance(){
bool result = false;
this.clsCompliance = CLSComplianceSpec.NotAttributed;
if (this.customAttributes != null){
CustomAttribute clsAttr = this.customAttributes.GetAttribute(Typeob.CLSCompliantAttribute);
if (clsAttr != null){
this.clsCompliance = clsAttr.GetCLSComplianceValue();
result = this.clsCompliance == CLSComplianceSpec.CLSCompliant;
this.customAttributes.Remove(clsAttr);
}
}
if (this.clsCompliance == CLSComplianceSpec.CLSCompliant && !this.Engine.isCLSCompliant)
this.context.HandleError(JSError.TypeAssemblyCLSCompliantMismatch);
if (this.clsCompliance == CLSComplianceSpec.NotAttributed && (this.attributes & TypeAttributes.Public) != 0)
result = Engine.isCLSCompliant;
return result;
}
internal static bool ParametersMatch(ParameterInfo[] suppars, ParameterInfo[] pars){
if (suppars.Length != pars.Length) return false;
for (int i = 0, n = pars.Length; i < n; i++){
IReflect spir = suppars[i] is ParameterDeclaration ? ((ParameterDeclaration)suppars[i]).ParameterIReflect : suppars[i].ParameterType;
IReflect pir = pars[i] is ParameterDeclaration ? ((ParameterDeclaration)pars[i]).ParameterIReflect : pars[i].ParameterType;
if (!pir.Equals(spir))
return false;
}
return true;
}
internal override AST PartiallyEvaluate(){
if (this.isAlreadyPartiallyEvaluated) return this;
this.isAlreadyPartiallyEvaluated = true;
this.IsExpando(); //Evaluate the custom attributes, run up the inheritance chain and add expando property if necessary
this.classob.SetParent(new WithObject(this.enclosingScope, this.superIR, true));
Globals.ScopeStack.Push(this.classob);
try{
this.body.PartiallyEvaluate();
if (this.implicitDefaultConstructor != null)
this.implicitDefaultConstructor.PartiallyEvaluate();
}finally{
Globals.ScopeStack.Pop();
}
foreach (JSMemberField field in this.fields) field.CheckOverloadsForDuplicates();
this.CheckIfValidExtensionOfSuperType();
this.CheckThatAllAbstractSuperClassMethodsAreImplemented();
return this;
}
private void SetAccessibility(FieldAttributes attributes){
FieldAttributes accessibility = attributes & FieldAttributes.FieldAccessMask;
if (this.enclosingScope is ClassScope){
if (accessibility == FieldAttributes.Public)
this.attributes |= TypeAttributes.NestedPublic;
else if (accessibility == FieldAttributes.Family)
this.attributes |= TypeAttributes.NestedFamily;
else if (accessibility == FieldAttributes.Assembly)
this.attributes |= TypeAttributes.NestedAssembly;
else if (accessibility == FieldAttributes.Private)
this.attributes |= TypeAttributes.NestedPrivate;
else if (accessibility == FieldAttributes.FamORAssem)
this.attributes |= TypeAttributes.NestedFamORAssem;
else
this.attributes |= TypeAttributes.NestedPublic;
}else{
if (accessibility == FieldAttributes.Public || 0 == (int)accessibility)
this.attributes |= TypeAttributes.Public;
}
}
private void SetupConstructors(){
MemberInfo[] consmem = classob.GetMember(this.name,
BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static|BindingFlags.DeclaredOnly); //See if the class has a member with the name of the class
if (consmem == null){
this.AllocateImplicitDefaultConstructor();
FieldInfo field = this.classob.AddNewField(this.name, this.implicitDefaultConstructor, FieldAttributes.Literal);
this.classob.constructors = new ConstructorInfo[]{new JSConstructor(this.implicitDefaultConstructor)};
}else{
MemberInfo cmem0 = null;
foreach (MemberInfo cmem in consmem){
if (cmem is JSFieldMethod){
FunctionObject cons = ((JSFieldMethod)cmem).func;
if (cmem0 == null) cmem0 = cmem;
if (cons.return_type_expr != null)
cons.return_type_expr.context.HandleError(JSError.ConstructorMayNotHaveReturnType);
if ((cons.attributes & MethodAttributes.Abstract) != 0 || (cons.attributes & MethodAttributes.Static) != 0){
cons.isStatic = false;
JSVariableField f = (JSVariableField)((JSFieldMethod)cmem).field;
f.attributeFlags &= ~FieldAttributes.Static;
f.originalContext.HandleError(JSError.NotValidForConstructor);
}
cons.return_type_expr = new TypeExpression(new ConstantWrapper(Typeob.Void, context));
cons.own_scope.AddReturnValueField();
}
//The else case can only happen if there is an error in the source code. Messages are generated elsewhere.
}
if (cmem0 != null)
this.classob.constructors = ((JSMemberField)((JSFieldMethod)cmem0).field).GetAsConstructors(this.classob);
else{
this.AllocateImplicitDefaultConstructor();
this.classob.constructors = new ConstructorInfo[]{new JSConstructor(this.implicitDefaultConstructor)};
}
}
}
internal override void TranslateToIL(ILGenerator il, Type rtype){
this.GetTypeBuilderOrEnumBuilder();
this.TranslateToCOMPlusClass();
Debug.Assert(rtype == Typeob.Void);
Object tok = ((JSVariableField)this.ownField).GetMetaData();
if (tok != null){
//This case is here to make classes defined in the global scope accessible to eval
il.Emit(OpCodes.Ldtoken, this.classob.classwriter);
il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
if (tok is LocalBuilder)
il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
else
il.Emit(OpCodes.Stsfld, (FieldInfo)tok);
}
}
internal override void TranslateToILInitializer(ILGenerator il){
}
private void EmitUsingNamespaces(ILGenerator il){
if (this.body.Engine.GenerateDebugInfo){
ScriptObject ns = this.enclosingScope;
while (ns != null){
if (ns is PackageScope)
il.UsingNamespace(((PackageScope)ns).name);
else if (ns is WrappedNamespace && !((WrappedNamespace)ns).name.Equals(""))
il.UsingNamespace(((WrappedNamespace)ns).name);
ns = ns.GetParent();
}
}
}
private void TranslateToCOMPlusClass(){
if (this.isCooked) return;
this.isCooked = true;
if (this is EnumDeclaration){
if (!(this.enclosingScope is ClassScope))
this.TranslateToCreateTypeCall();
return;
}
if (this.superClass != null)
this.superClass.TranslateToCOMPlusClass();
for (int i = 0, n = this.interfaces.Length; i < n; i++){
IReflect iface = this.interfaces[i].ToIReflect();
if (iface is ClassScope)
((ClassScope)iface).owner.TranslateToCOMPlusClass();
}
Globals.ScopeStack.Push(this.classob);
TypeBuilder savedClasswriter = compilerGlobals.classwriter;
compilerGlobals.classwriter = (TypeBuilder)this.classob.classwriter;
if (!this.isInterface){
//Emit the class initializer
ConstructorBuilder ccons = compilerGlobals.classwriter.DefineTypeInitializer();
ILGenerator il = ccons.GetILGenerator();
((Block)(this.body)).TranslateToILStaticInitializers(il);
il.Emit(OpCodes.Ret);
// Emit all the namespaces used by the class initializer
this.EmitUsingNamespaces(il);
//Emit the instance field initializer (this also emits the method bodies)
MethodBuilder initializer = compilerGlobals.classwriter.DefineMethod(".init", MethodAttributes.Private, Typeob.Void, new Type[0]);
this.fieldInitializer = initializer;
il = initializer.GetILGenerator();
((Block)(this.body)).TranslateToILInstanceInitializers(il);
il.Emit(OpCodes.Ret);
// Emit all the namespaces used by the instance initializer
this.EmitUsingNamespaces(il);
//Emit the default constructor
if (this.implicitDefaultConstructor != null)
this.implicitDefaultConstructor.TranslateToIL(compilerGlobals);
//Emit the expando code
if (this.generateCodeForExpando){
this.GetExpandoIndexerGetter();
this.GetExpandoIndexerSetter();
this.GetExpandoDeleteMethod();
this.GenerateGetEnumerator();
}
this.EmitILForINeedEngineMethods();
}
if (!(this.enclosingScope is ClassScope))
this.TranslateToCreateTypeCall();
compilerGlobals.classwriter = savedClasswriter;
Globals.ScopeStack.Pop();
}
private void TranslateToCreateTypeCall(){
if (this.cookedType != null) return;
if (this is EnumDeclaration){
EnumBuilder eb = this.classob.classwriter as EnumBuilder;
if (eb != null)
this.cookedType = eb.CreateType();
else
this.cookedType =((TypeBuilder)this.classob.classwriter).CreateType();
return;
}
if (this.superClass != null)
this.superClass.TranslateToCreateTypeCall();
AppDomain currentDomain = System.Threading.Thread.GetDomain();
ResolveEventHandler resolveHandler = new ResolveEventHandler(this.ResolveEnum);
currentDomain.TypeResolve += resolveHandler;
this.cookedType = ((TypeBuilder)this.classob.classwriter).CreateType();
currentDomain.TypeResolve -= resolveHandler;
foreach (JSMemberField field in this.fields){
ClassScope csc = field.value as ClassScope;
if (csc == null) continue;
csc.owner.TranslateToCreateTypeCall();
}
}
private Assembly ResolveEnum(Object sender, ResolveEventArgs args){
FieldInfo f = this.classob.GetField(args.Name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static);
if (f != null && f.IsLiteral){
ClassScope csc = f.GetValue(null) as ClassScope;
if (csc != null) csc.owner.TranslateToCreateTypeCall();
}
return this.compilerGlobals.assemblyBuilder;
}
internal override Context GetFirstExecutableContext(){
return null;
}
}
}