The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ Lookup

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using Microsoft.JScript.Vsa;
  19.     using System;
  20.     using System.Reflection;
  21.     using System.Reflection.Emit;
  22.    
  23.     internal sealed class Lookup : Binding
  24.     {
  25.         private int lexLevel;
  26.         //Keeps track of the number of frames on the explicit scope stack that needs to be searched for a late binding
  27.         private int evalLexLevel;
  28.         //Keeps track of the number of frames to GetObject should skip
  29.         private LocalBuilder fieldLoc;
  30.         private LocalBuilder refLoc;
  31.         private LateBinding lateBinding;
  32.         private bool thereIsAnObjectOnTheStack;
  33.        
  34.         // this is the typical Lookup constructor. The context points to the identifier
  35.         internal Lookup(Context context) : base(context, context.GetCode())
  36.         {
  37.             this.lexLevel = 0;
  38.             this.evalLexLevel = 0;
  39.             this.fieldLoc = null;
  40.             this.refLoc = null;
  41.             this.lateBinding = null;
  42.             this.thereIsAnObjectOnTheStack = false;
  43.         }
  44.        
  45.         // this constructor is invoked when there has been a parse error. The typical scenario is a missing identifier.
  46.         internal Lookup(string name, Context context) : this(context)
  47.         {
  48.             this.name = name;
  49.         }
  50.        
  51.         internal string Name {
  52.             get { return this.name; }
  53.         }
  54.        
  55.         private void BindName()
  56.         {
  57.             int lexLevel = 0;
  58.             int evalLexLevel = 0;
  59.             ScriptObject scope = Globals.ScopeStack.Peek();
  60.             BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
  61.             bool staticClassFound = false;
  62.             // is there a static class on the scope chain
  63.             bool enclosingClassForStaticClassFound = false;
  64.             // has the class enclosing a static nested class been found
  65.             while (scope != null) {
  66.                 MemberInfo[] members = null;
  67.                 WithObject withScope = scope as WithObject;
  68.                 if (withScope != null && enclosingClassForStaticClassFound)
  69.                     members = withScope.GetMember(this.name, flags, false);
  70.                 else
  71.                     members = scope.GetMember(this.name, flags);
  72.                 this.members = members;
  73.                 if (members.Length > 0)
  74.                     break;
  75.                 if (scope is WithObject) {
  76.                     this.isFullyResolved = this.isFullyResolved && ((WithObject)scope).isKnownAtCompileTime;
  77.                     lexLevel++;
  78.                 }
  79.                 else if (scope is ActivationObject) {
  80.                     this.isFullyResolved = this.isFullyResolved && ((ActivationObject)scope).isKnownAtCompileTime;
  81.                     if (scope is BlockScope || (scope is FunctionScope && ((FunctionScope)scope).mustSaveStackLocals))
  82.                         lexLevel++;
  83.                     if (scope is ClassScope) {
  84.                         if (staticClassFound)
  85.                             enclosingClassForStaticClassFound = true;
  86.                         if (((ClassScope)scope).owner.isStatic) {
  87.                             flags &= ~BindingFlags.Instance;
  88.                             staticClassFound = true;
  89.                         }
  90.                     }
  91.                 }
  92.                 else if (scope is StackFrame)
  93.                     lexLevel++;
  94.                 evalLexLevel++;
  95.                 scope = scope.GetParent();
  96.             }
  97.             if (this.members.Length > 0) {
  98.                 this.lexLevel = lexLevel;
  99.                 this.evalLexLevel = evalLexLevel;
  100.             }
  101.         }
  102.        
  103.         internal bool CanPlaceAppropriateObjectOnStack(object ob)
  104.         {
  105.             if (ob is LenientGlobalObject)
  106.                 return true;
  107.             ScriptObject scope = Globals.ScopeStack.Peek();
  108.             int lexLev = this.lexLevel;
  109.             while (lexLev > 0 && (scope is WithObject || scope is BlockScope)) {
  110.                 if (scope is WithObject)
  111.                     lexLev--;
  112.                 scope = scope.GetParent();
  113.             }
  114.             return scope is WithObject || scope is GlobalScope;
  115.         }
  116.        
  117.         internal override void CheckIfOKToUseInSuperConstructorCall()
  118.         {
  119.             FieldInfo f = this.member as FieldInfo;
  120.             if (f != null) {
  121.                 if (!f.IsStatic)
  122.                     this.context.HandleError(JSError.NotAllowedInSuperConstructorCall);
  123.                 return;
  124.             }
  125.             MethodInfo m = this.member as MethodInfo;
  126.             if (m != null) {
  127.                 if (!m.IsStatic)
  128.                     this.context.HandleError(JSError.NotAllowedInSuperConstructorCall);
  129.                 return;
  130.             }
  131.             PropertyInfo p = this.member as PropertyInfo;
  132.             if (p != null) {
  133.                 m = JSProperty.GetGetMethod(p, true);
  134.                 if (m != null && !m.IsStatic)
  135.                     this.context.HandleError(JSError.NotAllowedInSuperConstructorCall);
  136.                 else {
  137.                     m = JSProperty.GetSetMethod(p, true);
  138.                     if (m != null && !m.IsStatic)
  139.                         this.context.HandleError(JSError.NotAllowedInSuperConstructorCall);
  140.                 }
  141.             }
  142.         }
  143.        
  144.         internal override object Evaluate()
  145.         {
  146.             object result = null;
  147.             ScriptObject scope = Globals.ScopeStack.Peek();
  148.             if (!this.isFullyResolved) {
  149.                 result = ((IActivationObject)scope).GetMemberValue(this.name, this.evalLexLevel);
  150.                 if (!(result is Missing))
  151.                     return result;
  152.             }
  153.             if (this.members == null && !VsaEngine.executeForJSEE) {
  154.                 this.BindName();
  155.                 this.ResolveRHValue();
  156.             }
  157.             result = base.Evaluate();
  158.             if (result is Missing)
  159.                 throw new JScriptException(JSError.UndefinedIdentifier, this.context);
  160.             return result;
  161.         }
  162.        
  163.         internal override LateBinding EvaluateAsLateBinding()
  164.         {
  165.             if (!this.isFullyResolved) {
  166.                 this.BindName();
  167.                 //Doing this at runtime. Binding is now final (for this call). Do it here so that scope chain logic works as at compile time.
  168.                 this.isFullyResolved = false;
  169.             }
  170.             if (this.defaultMember == this.member)
  171.                 this.defaultMember = null;
  172.             object ob = this.GetObject();
  173.             LateBinding lb = this.lateBinding;
  174.             if (lb == null)
  175.                 lb = this.lateBinding = new LateBinding(this.name, ob, VsaEngine.executeForJSEE);
  176.             lb.obj = ob;
  177.             lb.last_object = ob;
  178.             lb.last_members = this.members;
  179.             lb.last_member = this.member;
  180.             if (!this.isFullyResolved)
  181.                 this.members = null;
  182.             return lb;
  183.         }
  184.        
  185.         internal override WrappedNamespace EvaluateAsWrappedNamespace(bool giveErrorIfNameInUse)
  186.         {
  187.             Namespace ns = Namespace.GetNamespace(this.name, this.Engine);
  188.             GlobalScope scope = ((IActivationObject)Globals.ScopeStack.Peek()).GetGlobalScope();
  189.             FieldInfo field = giveErrorIfNameInUse ? scope.GetLocalField(this.name) : scope.GetField(this.name, BindingFlags.Public | BindingFlags.Static);
  190.             if (field != null) {
  191.                 if (giveErrorIfNameInUse && (!field.IsLiteral || !(field.GetValue(null) is Namespace)))
  192.                     this.context.HandleError(JSError.DuplicateName, true);
  193.             }
  194.             else {
  195.                 field = scope.AddNewField(this.name, ns, FieldAttributes.Literal | FieldAttributes.Public);
  196.                 ((JSVariableField)field).type = new TypeExpression(new ConstantWrapper(Typeob.Namespace, this.context));
  197.                 ((JSVariableField)field).originalContext = this.context;
  198.             }
  199.             return new WrappedNamespace(this.name, this.Engine);
  200.         }
  201.        
  202.         protected override object GetObject()
  203.         {
  204.             object result;
  205.             ScriptObject scope = Globals.ScopeStack.Peek();
  206.             if (this.member is JSMemberField) {
  207.                 while (scope != null) {
  208.                     StackFrame sf = scope as StackFrame;
  209.                     if (sf != null) {
  210.                         result = sf.closureInstance;
  211.                         goto finish;
  212.                     }
  213.                     scope = scope.GetParent();
  214.                 }
  215.                 return null;
  216.             }
  217.             for (int i = this.evalLexLevel; i > 0; i--)
  218.                 scope = scope.GetParent();
  219.             result = scope;
  220.             finish:
  221.             if (this.defaultMember != null)
  222.                 switch (this.defaultMember.MemberType) {
  223.                     case MemberTypes.Field:
  224.                         return ((FieldInfo)this.defaultMember).GetValue(result);
  225.                     case MemberTypes.Method:
  226.                         return ((MethodInfo)this.defaultMember).Invoke(result, new object[0]);
  227.                     case MemberTypes.Property:
  228.                         return ((PropertyInfo)this.defaultMember).GetValue(result, null);
  229.                     case MemberTypes.Event:
  230.                         return null;
  231.                     case MemberTypes.NestedType:
  232.                         return member;
  233.                 }
  234.             return result;
  235.         }
  236.        
  237.         protected override void HandleNoSuchMemberError()
  238.         {
  239.             if (!this.isFullyResolved)
  240.                 return;
  241.             this.context.HandleError(JSError.UndeclaredVariable, this.Engine.doFast);
  242.         }
  243.        
  244.         internal override IReflect InferType(JSField inference_target)
  245.         {
  246.             if (!this.isFullyResolved)
  247.                 return Typeob.Object;
  248.             return base.InferType(inference_target);
  249.         }
  250.        
  251.         internal bool InFunctionNestedInsideInstanceMethod()
  252.         {
  253.             ScriptObject scope = this.Globals.ScopeStack.Peek();
  254.             while (scope is WithObject || scope is BlockScope)
  255.                 scope = scope.GetParent();
  256.             FunctionScope fscope = scope as FunctionScope;
  257.             while (fscope != null) {
  258.                 if (fscope.owner.isMethod)
  259.                     return !fscope.owner.isStatic;
  260.                 scope = fscope.owner.enclosing_scope;
  261.                 while (scope is WithObject || scope is BlockScope)
  262.                     scope = scope.GetParent();
  263.                 fscope = scope as FunctionScope;
  264.             }
  265.             return false;
  266.         }
  267.        
  268.         internal bool InStaticCode()
  269.         {
  270.             ScriptObject scope = this.Globals.ScopeStack.Peek();
  271.             while (scope is WithObject || scope is BlockScope)
  272.                 scope = scope.GetParent();
  273.             FunctionScope fscope = scope as FunctionScope;
  274.             if (fscope != null)
  275.                 return fscope.isStatic;
  276.             StackFrame sframe = scope as StackFrame;
  277.             //Might be a StackFrame if called from an eval
  278.             if (sframe != null)
  279.                 return sframe.thisObject is Type;
  280.             ClassScope cscope = scope as ClassScope;
  281.             //Happens when the initializers of variable declarations are partially evaluated
  282.             if (cscope != null)
  283.                 return cscope.inStaticInitializerCode;
  284.             return true;
  285.         }
  286.        
  287.         internal override AST PartiallyEvaluate()
  288.         {
  289.             this.BindName();
  290.             if (this.members == null || this.members.Length == 0) {
  291.                 //Give a warning, unless inside a with statement
  292.                 ScriptObject scope = Globals.ScopeStack.Peek();
  293.                 while (scope is FunctionScope)
  294.                     scope = scope.GetParent();
  295.                 if (!(scope is WithObject) || this.isFullyResolved)
  296.                     this.context.HandleError(JSError.UndeclaredVariable, this.isFullyResolved && this.Engine.doFast);
  297.             }
  298.             else {
  299.                 this.ResolveRHValue();
  300.                 MemberInfo member = this.member;
  301.                 if (member is FieldInfo) {
  302.                     FieldInfo field = (FieldInfo)member;
  303.                     if (field is JSLocalField && !((JSLocalField)field).isDefined) {
  304.                         ((JSLocalField)field).isUsedBeforeDefinition = true;
  305.                         this.context.HandleError(JSError.VariableMightBeUnitialized);
  306.                     }
  307.                     if (field.IsLiteral) {
  308.                         object val = field is JSVariableField ? ((JSVariableField)field).value : TypeReferences.GetConstantValue(field);
  309.                         if (val is AST) {
  310.                             AST pval = ((AST)val).PartiallyEvaluate();
  311.                             if (pval is ConstantWrapper && this.isFullyResolved)
  312.                                 return pval;
  313.                             val = null;
  314.                         }
  315.                         if (!(val is FunctionObject) && this.isFullyResolved)
  316.                             return new ConstantWrapper(val, this.context);
  317.                     }
  318.                     else if (field.IsInitOnly && field.IsStatic && field.DeclaringType == Typeob.GlobalObject && this.isFullyResolved)
  319.                         return new ConstantWrapper(field.GetValue(null), this.context);
  320.                 }
  321.                 else if (member is PropertyInfo) {
  322.                     PropertyInfo prop = (PropertyInfo)member;
  323.                     if (!prop.CanWrite && !(prop is JSProperty) && prop.DeclaringType == Typeob.GlobalObject && this.isFullyResolved)
  324.                         return new ConstantWrapper(prop.GetValue(null, null), this.context);
  325.                 }
  326.                 if (member is Type && this.isFullyResolved)
  327.                     return new ConstantWrapper(member, this.context);
  328.             }
  329.             return this;
  330.         }
  331.        
  332.         internal override AST PartiallyEvaluateAsCallable()
  333.         {
  334.             this.BindName();
  335.             return this;
  336.         }
  337.        
  338.         internal override AST PartiallyEvaluateAsReference()
  339.         {
  340.             this.BindName();
  341.             if (this.members == null || this.members.Length == 0) {
  342.                 //Give a warning, unless inside a with statement
  343.                 ScriptObject scope = Globals.ScopeStack.Peek();
  344.                 if (!(scope is WithObject) || this.isFullyResolved)
  345.                     this.context.HandleError(JSError.UndeclaredVariable, this.isFullyResolved && this.Engine.doFast);
  346.             }
  347.             else
  348.                 this.ResolveLHValue();
  349.             return this;
  350.         }
  351.        
  352.        
  353.         internal override object ResolveCustomAttribute(ASTList args, IReflect[] argIRs, AST target)
  354.         {
  355.             if (this.name == "expando")
  356.                 this.members = Typeob.Expando.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
  357.             else if (this.name == "override")
  358.                 this.members = Typeob.Override.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
  359.             else if (this.name == "hide")
  360.                 this.members = Typeob.Hide.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
  361.             else if (this.name == "...")
  362.                 this.members = Typeob.ParamArrayAttribute.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
  363.             else {
  364.                 this.name = this.name + "Attribute";
  365.                 this.BindName();
  366.                 if (this.members == null || this.members.Length == 0) {
  367.                     this.name = this.name.Substring(0, this.name.Length - 9);
  368.                     this.BindName();
  369.                 }
  370.             }
  371.             return base.ResolveCustomAttribute(args, argIRs, target);
  372.         }
  373.        
  374.         internal override void SetPartialValue(AST partial_value)
  375.         {
  376.             //ResolveLHValue has already been called and has already checked if the target is accessible and assignable
  377.             if (this.members == null || this.members.Length == 0)
  378.                 return;
  379.             //Assignment to an undeclared variable. Nothing further to do.
  380.             if (this.member is JSLocalField) {
  381.                 //If we are dealing with an assignment to an untyped local variable, we need to tell the type inferencer about the assignment
  382.                 JSLocalField lfield = (JSLocalField)this.member;
  383.                 if (lfield.type == null) {
  384.                     IReflect ir = partial_value.InferType(lfield);
  385.                     if (ir == Typeob.String && partial_value is Plus)
  386.                         lfield.SetInferredType(Typeob.Object, partial_value);
  387.                     else
  388.                         lfield.SetInferredType(ir, partial_value);
  389.                     //but then we are done
  390.                     return;
  391.                 }
  392.                 lfield.isDefined = true;
  393.             }
  394.             Binding.AssignmentCompatible(this.InferType(null), partial_value, partial_value.InferType(null), this.isFullyResolved);
  395.         }
  396.        
  397.         internal override void SetValue(object value)
  398.         {
  399.             if (!this.isFullyResolved) {
  400.                 this.EvaluateAsLateBinding().SetValue(value);
  401.                 return;
  402.             }
  403.             base.SetValue(value);
  404.         }
  405.        
  406.         internal void SetWithValue(WithObject scope, object value)
  407.         {
  408.             Debug.Assert(!this.isFullyResolved);
  409.             FieldInfo withField = scope.GetField(this.name, this.lexLevel);
  410.             if (withField != null) {
  411.                 withField.SetValue(scope, value);
  412.                 return;
  413.             }
  414.         }
  415.        
  416.         //code in parser relies on this.name being returned from here
  417.         public override string ToString()
  418.         {
  419.             return this.name;
  420.         }
  421.        
  422.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  423.         {
  424.             if (this.isFullyResolved) {
  425.                 base.TranslateToIL(il, rtype);
  426.                 return;
  427.             }
  428.             //Need to do a dynamic lookup to see if there is a dynamically introduced (by eval or with) hiding definition.
  429.             Label done = il.DefineLabel();
  430.             this.EmitILToLoadEngine(il);
  431.             il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  432.             il.Emit(OpCodes.Castclass, Typeob.IActivationObject);
  433.             il.Emit(OpCodes.Ldstr, this.name);
  434.             ConstantWrapper.TranslateToILInt(il, this.lexLevel);
  435.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getMemberValueMethod);
  436.             il.Emit(OpCodes.Dup);
  437.             il.Emit(OpCodes.Call, CompilerGlobals.isMissingMethod);
  438.             il.Emit(OpCodes.Brfalse, done);
  439.             //dynamic lookup succeeded, do not use the value from the early bound location.
  440.             il.Emit(OpCodes.Pop);
  441.             //The dynamic lookup returned Missing.Value, discard it and go on to use the value from the early bound location.
  442.             base.TranslateToIL(il, Typeob.Object);
  443.             il.MarkLabel(done);
  444.             Convert.Emit(this, il, Typeob.Object, rtype);
  445.         }
  446.        
  447.         internal override void TranslateToILCall(ILGenerator il, Type rtype, ASTList argList, bool construct, bool brackets)
  448.         {
  449.             if (this.isFullyResolved) {
  450.                 base.TranslateToILCall(il, rtype, argList, construct, brackets);
  451.                 return;
  452.             }
  453.             //Need to do a dynamic lookup to see if there is a dynamically introduced (by eval or with) hiding definition.
  454.             Label lateBoundCall = il.DefineLabel();
  455.             Label done = il.DefineLabel();
  456.             this.EmitILToLoadEngine(il);
  457.             il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  458.             il.Emit(OpCodes.Castclass, Typeob.IActivationObject);
  459.             il.Emit(OpCodes.Ldstr, this.name);
  460.             ConstantWrapper.TranslateToILInt(il, this.lexLevel);
  461.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getMemberValueMethod);
  462.             il.Emit(OpCodes.Dup);
  463.             il.Emit(OpCodes.Call, CompilerGlobals.isMissingMethod);
  464.             il.Emit(OpCodes.Brfalse, lateBoundCall);
  465.             //dynamic lookup succeeded, do not call early bound method
  466.             il.Emit(OpCodes.Pop);
  467.             //The dynamic lookup returned Missing.Value, discard it and go on to use the value from the early bound location.
  468.             base.TranslateToILCall(il, Typeob.Object, argList, construct, brackets);
  469.             il.Emit(OpCodes.Br, done);
  470.             //Skip over the latebound call sequence
  471.             il.MarkLabel(lateBoundCall);
  472.             this.TranslateToILDefaultThisObject(il);
  473.             argList.TranslateToIL(il, Typeob.ArrayOfObject);
  474.             if (construct)
  475.                 il.Emit(OpCodes.Ldc_I4_1);
  476.             else
  477.                 il.Emit(OpCodes.Ldc_I4_0);
  478.             if (brackets)
  479.                 il.Emit(OpCodes.Ldc_I4_1);
  480.             else
  481.                 il.Emit(OpCodes.Ldc_I4_0);
  482.             this.EmitILToLoadEngine(il);
  483.             il.Emit(OpCodes.Call, CompilerGlobals.callValue2Method);
  484.             il.MarkLabel(done);
  485.             Convert.Emit(this, il, Typeob.Object, rtype);
  486.         }
  487.        
  488.         internal void TranslateToILDefaultThisObject(ILGenerator il)
  489.         {
  490.             this.TranslateToILDefaultThisObject(il, 0);
  491.         }
  492.        
  493.         private void TranslateToILDefaultThisObject(ILGenerator il, int lexLevel)
  494.         {
  495.             this.EmitILToLoadEngine(il);
  496.             il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  497.             while (lexLevel-- > 0)
  498.                 il.Emit(OpCodes.Call, CompilerGlobals.getParentMethod);
  499.             il.Emit(OpCodes.Castclass, Typeob.IActivationObject);
  500.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getDefaultThisObjectMethod);
  501.         }
  502.        
  503.         internal override void TranslateToILInitializer(ILGenerator il)
  504.         {
  505.             if (this.defaultMember != null)
  506.                 return;
  507.             if (this.member != null)
  508.                 switch (this.member.MemberType) {
  509.                     case MemberTypes.Constructor:
  510.                     case MemberTypes.Method:
  511.                     case MemberTypes.NestedType:
  512.                     case MemberTypes.Property:
  513.                     case MemberTypes.TypeInfo:
  514.                         return;
  515.                     case MemberTypes.Field:
  516.                         if (this.member is JSExpandoField) {
  517.                             this.member = null;
  518.                             break;
  519.                         }
  520.                         return;
  521.                 }
  522.             this.refLoc = il.DeclareLocal(Typeob.LateBinding);
  523.             il.Emit(OpCodes.Ldstr, this.name);
  524.            
  525.             if (this.isFullyResolved && this.member == null && this.IsBoundToMethodInfos()) {
  526.                 MethodInfo method = this.members[0] as MethodInfo;
  527.                 if (method.IsStatic) {
  528.                     il.Emit(OpCodes.Ldtoken, method.DeclaringType);
  529.                     il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
  530.                 }
  531.                 else
  532.                     this.TranslateToILObjectForMember(il, method.DeclaringType, false, method);
  533.             }
  534.             else {
  535.                 this.EmitILToLoadEngine(il);
  536.                 il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  537.             }
  538.             il.Emit(OpCodes.Newobj, CompilerGlobals.lateBindingConstructor2);
  539.             il.Emit(OpCodes.Stloc, this.refLoc);
  540.         }
  541.        
  542.         private bool IsBoundToMethodInfos()
  543.         {
  544.             if (this.members == null || this.members.Length == 0)
  545.                 return false;
  546.             for (int i = 0; i < this.members.Length; i++)
  547.                 if (!(this.members[i] is MethodInfo))
  548.                     return false;
  549.             return true;
  550.         }
  551.        
  552.         protected override void TranslateToILObject(ILGenerator il, Type obType, bool noValue)
  553.         {
  554.             this.TranslateToILObjectForMember(il, obType, noValue, this.member);
  555.         }
  556.        
  557.         private void TranslateToILObjectForMember(ILGenerator il, Type obType, bool noValue, MemberInfo mem)
  558.         {
  559.             this.thereIsAnObjectOnTheStack = true;
  560.             if (mem is IWrappedMember) {
  561.                 object obj = ((IWrappedMember)mem).GetWrappedObject();
  562.                 if (obj is LenientGlobalObject) {
  563.                     this.EmitILToLoadEngine(il);
  564.                     il.Emit(OpCodes.Call, CompilerGlobals.getLenientGlobalObjectMethod);
  565.                 }
  566.                 else if (obj is Type || obj is ClassScope) {
  567.                     if (obType.IsAssignableFrom(Typeob.Type)) {
  568.                         (new ConstantWrapper(obj, null)).TranslateToIL(il, Typeob.Type);
  569.                         return;
  570.                     }
  571.                     //this.name is the name of an instance member of the superclass of the class (or an outer class) in which this expression appears
  572.                     //get class instance on stack
  573.                     ScriptObject scope = Globals.ScopeStack.Peek();
  574.                     while (scope is WithObject || scope is BlockScope)
  575.                         scope = scope.GetParent();
  576.                     if (scope is FunctionScope) {
  577.                         FunctionObject func = ((FunctionScope)scope).owner;
  578.                         if (func.isMethod)
  579.                             il.Emit(OpCodes.Ldarg_0);
  580.                         else {
  581.                             //Need to get the StackFrame.closureInstance on the stack
  582.                             this.EmitILToLoadEngine(il);
  583.                             il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  584.                             scope = this.Globals.ScopeStack.Peek();
  585.                             while (scope is WithObject || scope is BlockScope) {
  586.                                 il.Emit(OpCodes.Call, CompilerGlobals.getParentMethod);
  587.                                 scope = scope.GetParent();
  588.                             }
  589.                             il.Emit(OpCodes.Castclass, Typeob.StackFrame);
  590.                             il.Emit(OpCodes.Ldfld, CompilerGlobals.closureInstanceField);
  591.                         }
  592.                     }
  593.                     else if (scope is ClassScope) {
  594.                         il.Emit(OpCodes.Ldarg_0);
  595.                         //Inside instance initializer
  596.                     }
  597.                    
  598.                     //If dealing with a member of an outer class, get the outer class instance on the stack
  599.                     scope = Globals.ScopeStack.Peek();
  600.                     while (scope != null) {
  601.                         ClassScope csc = scope as ClassScope;
  602.                         if (csc != null) {
  603.                             //Might be dealing with a reference from within a nested class to an instance member of an outer class
  604.                             if (csc.IsSameOrDerivedFrom(obType))
  605.                                 break;
  606.                             il.Emit(OpCodes.Ldfld, csc.outerClassField);
  607.                         }
  608.                         scope = scope.GetParent();
  609.                     }
  610.                 }
  611.                 else {
  612.                     this.TranslateToILDefaultThisObject(il, this.lexLevel);
  613.                     Convert.Emit(this, il, Typeob.Object, obType);
  614.                 }
  615.             }
  616.             else {
  617.                 ScriptObject scope = Globals.ScopeStack.Peek();
  618.                 while (scope is WithObject || scope is BlockScope)
  619.                     scope = scope.GetParent();
  620.                 if (scope is FunctionScope) {
  621.                     FunctionObject func = ((FunctionScope)scope).owner;
  622.                     if (!func.isMethod) {
  623.                         //Need to get the StackFrame.closureInstance on the stack
  624.                         this.EmitILToLoadEngine(il);
  625.                         il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  626.                         scope = this.Globals.ScopeStack.Peek();
  627.                         while (scope is WithObject || scope is BlockScope) {
  628.                             il.Emit(OpCodes.Call, CompilerGlobals.getParentMethod);
  629.                             scope = scope.GetParent();
  630.                         }
  631.                         il.Emit(OpCodes.Castclass, Typeob.StackFrame);
  632.                         il.Emit(OpCodes.Ldfld, CompilerGlobals.closureInstanceField);
  633.                         while (scope != null) {
  634.                             if (scope is ClassScope) {
  635.                                 //Might be dealing with a reference from within a nested class to an instance member of an outer class
  636.                                 ClassScope csc = (ClassScope)scope;
  637.                                 if (csc.IsSameOrDerivedFrom(obType))
  638.                                     break;
  639.                                 il.Emit(OpCodes.Castclass, csc.GetTypeBuilder());
  640.                                 il.Emit(OpCodes.Ldfld, csc.outerClassField);
  641.                             }
  642.                             scope = scope.GetParent();
  643.                         }
  644.                         il.Emit(OpCodes.Castclass, obType);
  645.                         return;
  646.                     }
  647.                 }
  648.                 il.Emit(OpCodes.Ldarg_0);
  649.                 while (scope != null) {
  650.                     if (scope is ClassScope) {
  651.                         //Might be dealing with a reference from within a nested class to an instance member of an outer class
  652.                         ClassScope csc = (ClassScope)scope;
  653.                         if (csc.IsSameOrDerivedFrom(obType))
  654.                             break;
  655.                         il.Emit(OpCodes.Ldfld, csc.outerClassField);
  656.                     }
  657.                     scope = scope.GetParent();
  658.                 }
  659.             }
  660.         }
  661.        
  662.         internal override void TranslateToILPreSet(ILGenerator il)
  663.         {
  664.             this.TranslateToILPreSet(il, false);
  665.         }
  666.        
  667.         internal void TranslateToILPreSet(ILGenerator il, bool doBoth)
  668.         {
  669.             if (this.isFullyResolved) {
  670.                 base.TranslateToILPreSet(il);
  671.                 return;
  672.             }
  673.             //Need to do a dynamic lookup to see if there is a dynamically introduced (by eval or with) hiding definition.
  674.             //Leave a FieldInfo on the stack if there is such a member, otherwise leave null on the stack
  675.             Label done = il.DefineLabel();
  676.             LocalBuilder fieldLoc = this.fieldLoc = il.DeclareLocal(Typeob.FieldInfo);
  677.             this.EmitILToLoadEngine(il);
  678.             il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  679.             il.Emit(OpCodes.Castclass, Typeob.IActivationObject);
  680.             il.Emit(OpCodes.Ldstr, this.name);
  681.             ConstantWrapper.TranslateToILInt(il, this.lexLevel);
  682.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getFieldMethod);
  683.             il.Emit(OpCodes.Stloc, fieldLoc);
  684.             if (!doBoth) {
  685.                 il.Emit(OpCodes.Ldloc, fieldLoc);
  686.                 il.Emit(OpCodes.Ldnull);
  687.                 il.Emit(OpCodes.Bne_Un_S, done);
  688.             }
  689.             base.TranslateToILPreSet(il);
  690.             if (this.thereIsAnObjectOnTheStack) {
  691.                 Label reallyDone = il.DefineLabel();
  692.                 il.Emit(OpCodes.Br_S, reallyDone);
  693.                 il.MarkLabel(done);
  694.                 il.Emit(OpCodes.Ldnull);
  695.                 //Push a dummy object so that both latebound and early bound code paths leave an object on the stack
  696.                 il.MarkLabel(reallyDone);
  697.             }
  698.             else
  699.                 il.MarkLabel(done);
  700.         }
  701.        
  702.         internal override void TranslateToILPreSetPlusGet(ILGenerator il)
  703.         {
  704.             if (this.isFullyResolved) {
  705.                 base.TranslateToILPreSetPlusGet(il);
  706.                 return;
  707.             }
  708.             //Need to do a dynamic lookup to see if there is a dynamically introduced (by eval or with) hiding definition.
  709.             //Leave a FieldInfo on the stack if there is such a member, otherwise leave null on the stack
  710.             Label done = il.DefineLabel();
  711.             Label latebound = il.DefineLabel();
  712.             LocalBuilder fieldTok = this.fieldLoc = il.DeclareLocal(Typeob.FieldInfo);
  713.             this.EmitILToLoadEngine(il);
  714.             il.Emit(OpCodes.Call, CompilerGlobals.scriptObjectStackTopMethod);
  715.             il.Emit(OpCodes.Castclass, Typeob.IActivationObject);
  716.             il.Emit(OpCodes.Ldstr, this.name);
  717.             ConstantWrapper.TranslateToILInt(il, this.lexLevel);
  718.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getFieldMethod);
  719.             il.Emit(OpCodes.Stloc, fieldTok);
  720.             il.Emit(OpCodes.Ldloc, fieldTok);
  721.             il.Emit(OpCodes.Ldnull);
  722.             il.Emit(OpCodes.Bne_Un_S, latebound);
  723.             base.TranslateToILPreSetPlusGet(il);
  724.             il.Emit(OpCodes.Br_S, done);
  725.             il.MarkLabel(latebound);
  726.             if (this.thereIsAnObjectOnTheStack)
  727.                 il.Emit(OpCodes.Ldnull);
  728.             //Push a dummy object so that both latebound and early bound code paths leave an object on the stack
  729.             il.Emit(OpCodes.Ldloc, this.fieldLoc);
  730.             il.Emit(OpCodes.Ldnull);
  731.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getFieldValueMethod);
  732.             il.MarkLabel(done);
  733.         }
  734.        
  735.         internal override void TranslateToILSet(ILGenerator il, AST rhvalue)
  736.         {
  737.             this.TranslateToILSet(il, false, rhvalue);
  738.         }
  739.        
  740.         internal void TranslateToILSet(ILGenerator il, bool doBoth, AST rhvalue)
  741.         {
  742.             if (this.isFullyResolved) {
  743.                 base.TranslateToILSet(il, rhvalue);
  744.                 return;
  745.             }
  746.             if (rhvalue != null)
  747.                 rhvalue.TranslateToIL(il, Typeob.Object);
  748.             if (this.fieldLoc == null) {
  749.                 //There is a callable value plus parameters on the stack
  750.                 il.Emit(OpCodes.Call, CompilerGlobals.setIndexedPropertyValueStaticMethod);
  751.                 return;
  752.             }
  753.             LocalBuilder temp = il.DeclareLocal(Typeob.Object);
  754.             if (doBoth) {
  755.                 //save copy of rh value
  756.                 il.Emit(OpCodes.Dup);
  757.                 il.Emit(OpCodes.Stloc, temp);
  758.                 //store it in early bound location
  759.                 this.isFullyResolved = true;
  760.                 Convert.Emit(this, il, Typeob.Object, Convert.ToType(this.InferType(null)));
  761.                 base.TranslateToILSet(il, null);
  762.             }
  763.             //See if there is a late bound field
  764.             Label earlyBound = il.DefineLabel();
  765.             il.Emit(OpCodes.Ldloc, this.fieldLoc);
  766.             il.Emit(OpCodes.Ldnull);
  767.             il.Emit(OpCodes.Beq_S, earlyBound);
  768.             //No late bound field
  769.             //store it in the late bound field
  770.             Label done = il.DefineLabel();
  771.             if (!doBoth) {
  772.                 il.Emit(OpCodes.Stloc, temp);
  773.                 if (this.thereIsAnObjectOnTheStack)
  774.                     il.Emit(OpCodes.Pop);
  775.             }
  776.             il.Emit(OpCodes.Ldloc, this.fieldLoc);
  777.             il.Emit(OpCodes.Ldnull);
  778.             il.Emit(OpCodes.Ldloc, temp);
  779.             il.Emit(OpCodes.Callvirt, CompilerGlobals.setFieldValueMethod);
  780.             il.Emit(OpCodes.Br_S, done);
  781.            
  782.             //Alternative store it in the early bound location
  783.             il.MarkLabel(earlyBound);
  784.             if (!doBoth) {
  785.                 this.isFullyResolved = true;
  786.                 Convert.Emit(this, il, Typeob.Object, Convert.ToType(this.InferType(null)));
  787.                 base.TranslateToILSet(il, null);
  788.             }
  789.             il.MarkLabel(done);
  790.         }
  791.        
  792.         protected override void TranslateToILWithDupOfThisOb(ILGenerator il)
  793.         {
  794.             this.TranslateToILDefaultThisObject(il);
  795.             this.TranslateToIL(il, Typeob.Object);
  796.         }
  797.        
  798.         internal void TranslateToLateBinding(ILGenerator il)
  799.         {
  800.             this.thereIsAnObjectOnTheStack = true;
  801.             il.Emit(OpCodes.Ldloc, this.refLoc);
  802.         }
  803.     }
  804. }

Developer Fusion