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.
1457 lines
69 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|