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

  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.Collections;
  21.     using System.Reflection;
  22.     using System.Reflection.Emit;
  23.    
  24.     public sealed class ForIn : AST
  25.     {
  26.         private AST var;
  27.         private AST initializer;
  28.         private AST collection;
  29.         private AST body;
  30.         private Completion completion;
  31.         private Context inExpressionContext;
  32.        
  33.         internal ForIn(Context context, AST var, AST initializer, AST collection, AST body) : base(context)
  34.         {
  35.             if (var != null) {
  36.                 this.var = var;
  37.                 this.inExpressionContext = this.var.context.Clone();
  38.             }
  39.             else {
  40.                 VariableDeclaration decl = (VariableDeclaration)initializer;
  41.                 this.var = decl.identifier;
  42.                 if (decl.initializer == null)
  43.                     decl.initializer = new ConstantWrapper(null, null);
  44.                 //Suppress warning
  45.                 this.inExpressionContext = initializer.context.Clone();
  46.             }
  47.             this.initializer = initializer;
  48.             this.collection = collection;
  49.             this.inExpressionContext.UpdateWith(this.collection.context);
  50.             this.body = body;
  51.             this.completion = new Completion();
  52.         }
  53.        
  54.         internal override object Evaluate()
  55.         {
  56.             AST r = this.var;
  57.             if (this.initializer != null)
  58.                 this.initializer.Evaluate();
  59.             this.completion.Continue = 0;
  60.             this.completion.Exit = 0;
  61.             this.completion.value = null;
  62.             object coll = Convert.ToForInObject(this.collection.Evaluate(), this.Engine);
  63.             bool isScriptObject = coll is ScriptObject;
  64.             IEnumerator e = null;
  65.             try {
  66.                 e = JScriptGetEnumerator(coll);
  67.             }
  68.             catch (JScriptException x) {
  69.                 x.context = this.collection.context;
  70.                 throw x;
  71.             }
  72.             while (e.MoveNext()) {
  73.                 r.SetValue(e.Current);
  74.                 Completion c = (Completion)this.body.Evaluate();
  75.                 this.completion.value = c.value;
  76.                 if (c.Continue > 1) {
  77.                     this.completion.Continue = c.Continue - 1;
  78.                     break;
  79.                 }
  80.                 if (c.Exit > 0) {
  81.                     this.completion.Exit = c.Exit - 1;
  82.                     break;
  83.                 }
  84.                 if (c.Return)
  85.                     return c;
  86.             }
  87.             return this.completion;
  88.         }
  89.        
  90.         public static IEnumerator JScriptGetEnumerator(object coll)
  91.         {
  92.             if (coll is IEnumerator)
  93.                 return (IEnumerator)coll;
  94.             if (coll is ScriptObject)
  95.                 return new ScriptObjectPropertyEnumerator((ScriptObject)coll);
  96.             if (coll is Array) {
  97.                 Array arr = (Array)coll;
  98.                 return new RangeEnumerator(arr.GetLowerBound(0), arr.GetUpperBound(0));
  99.             }
  100.             if (coll is IEnumerable) {
  101.                 IEnumerator result = ((IEnumerable)coll).GetEnumerator();
  102.                 if (result != null)
  103.                     return result;
  104.                 return new ScriptObjectPropertyEnumerator(new JSObject());
  105.             }
  106.             throw new JScriptException(JSError.NotCollection);
  107.         }
  108.        
  109.         internal override AST PartiallyEvaluate()
  110.         {
  111.             this.var = this.var.PartiallyEvaluateAsReference();
  112.             this.var.SetPartialValue(new ConstantWrapper(null, null));
  113.             if (this.initializer != null)
  114.                 this.initializer = this.initializer.PartiallyEvaluate();
  115.             this.collection = this.collection.PartiallyEvaluate();
  116.             IReflect ctype = this.collection.InferType(null);
  117.             if ((ctype is ClassScope && ((ClassScope)ctype).noExpando && !((ClassScope)ctype).ImplementsInterface(Typeob.IEnumerable)) || (ctype != Typeob.Object && ctype is Type && !(Typeob.ScriptObject.IsAssignableFrom((Type)ctype)) && !Typeob.IEnumerable.IsAssignableFrom((Type)ctype) && !Typeob.IConvertible.IsAssignableFrom((Type)ctype)) && !Typeob.IEnumerator.IsAssignableFrom((Type)ctype))
  118.                 this.collection.context.HandleError(JSError.NotCollection);
  119.             ScriptObject current_scope = Globals.ScopeStack.Peek();
  120.             while (current_scope is WithObject)
  121.                 current_scope = current_scope.GetParent();
  122.             if (current_scope is FunctionScope) {
  123.                 FunctionScope scope = (FunctionScope)current_scope;
  124.                 BitArray before = scope.DefinedFlags;
  125.                 this.body = this.body.PartiallyEvaluate();
  126.                 scope.DefinedFlags = before;
  127.             }
  128.             else
  129.                 this.body = this.body.PartiallyEvaluate();
  130.             return this;
  131.         }
  132.        
  133.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  134.         {
  135.             //This assumes that rtype == Void.class
  136.             Label loop_start = il.DefineLabel();
  137.             Label loop_end = il.DefineLabel();
  138.             Label body = il.DefineLabel();
  139.             compilerGlobals.BreakLabelStack.Push(loop_end);
  140.             compilerGlobals.ContinueLabelStack.Push(loop_start);
  141.             if (this.initializer != null) {
  142.                 this.initializer.TranslateToIL(il, Typeob.Void);
  143.             }
  144.             this.inExpressionContext.EmitLineInfo(il);
  145.             this.collection.TranslateToIL(il, Typeob.Object);
  146.             this.EmitILToLoadEngine(il);
  147.             il.Emit(OpCodes.Call, CompilerGlobals.toForInObjectMethod);
  148.             il.Emit(OpCodes.Call, CompilerGlobals.jScriptGetEnumeratorMethod);
  149.             LocalBuilder enumerator = il.DeclareLocal(Typeob.IEnumerator);
  150.             il.Emit(OpCodes.Stloc, enumerator);
  151.             il.Emit(OpCodes.Br, loop_start);
  152.             il.MarkLabel(body);
  153.             this.body.TranslateToIL(il, Typeob.Void);
  154.             il.MarkLabel(loop_start);
  155.             this.context.EmitLineInfo(il);
  156.             il.Emit(OpCodes.Ldloc, enumerator);
  157.             il.Emit(OpCodes.Callvirt, CompilerGlobals.moveNextMethod);
  158.             il.Emit(OpCodes.Brfalse, loop_end);
  159.             il.Emit(OpCodes.Ldloc, enumerator);
  160.             il.Emit(OpCodes.Callvirt, CompilerGlobals.getCurrentMethod);
  161.             Type vt = Convert.ToType(this.var.InferType(null));
  162.             LocalBuilder val = il.DeclareLocal(vt);
  163.             Convert.Emit(this, il, Typeob.Object, vt);
  164.             il.Emit(OpCodes.Stloc, val);
  165.             this.var.TranslateToILPreSet(il);
  166.             il.Emit(OpCodes.Ldloc, val);
  167.             this.var.TranslateToILSet(il);
  168.             il.Emit(OpCodes.Br, body);
  169.             il.MarkLabel(loop_end);
  170.             compilerGlobals.BreakLabelStack.Pop();
  171.             compilerGlobals.ContinueLabelStack.Pop();
  172.         }
  173.        
  174.         internal override void TranslateToILInitializer(ILGenerator il)
  175.         {
  176.             this.var.TranslateToILInitializer(il);
  177.             if (this.initializer != null)
  178.                 this.initializer.TranslateToILInitializer(il);
  179.             this.collection.TranslateToILInitializer(il);
  180.             this.body.TranslateToILInitializer(il);
  181.         }
  182.     }
  183. }

Developer Fusion