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

  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 System;
  19.     using System.Collections;
  20.     using System.Reflection;
  21.     using System.Reflection.Emit;
  22.    
  23.     internal sealed class Switch : AST
  24.     {
  25.         private AST expression;
  26.         private ASTList cases;
  27.         private int default_case;
  28.         private Completion completion;
  29.        
  30.         internal Switch(Context context, AST expression, ASTList cases) : base(context)
  31.         {
  32.             this.expression = expression;
  33.             this.cases = cases;
  34.             this.default_case = -1;
  35.             for (int i = 0int n = this.cases.count; i < n; i++) {
  36.                 if (((SwitchCase)(this.cases[i])).IsDefault()) {
  37.                     this.default_case = i;
  38.                     break;
  39.                 }
  40.             }
  41.             this.completion = new Completion();
  42.         }
  43.        
  44.         internal override object Evaluate()
  45.         {
  46.             this.completion.Continue = 0;
  47.             this.completion.Exit = 0;
  48.             this.completion.value = null;
  49.             object val = this.expression.Evaluate();
  50.             Completion c = null;
  51.             int i;
  52.             int n = this.cases.count;
  53.             for (i = 0; i < n; i++) {
  54.                 if (i == this.default_case)
  55.                     continue;
  56.                 c = ((SwitchCase)(this.cases[i])).Evaluate(val);
  57.                 if (c != null)
  58.                     break;
  59.             }
  60.             if (c == null)
  61.                 if (this.default_case >= 0) {
  62.                     i = this.default_case;
  63.                     c = (Completion)((SwitchCase)(this.cases[i])).Evaluate();
  64.                 }
  65.                 else
  66.                     return this.completion;
  67.             while (true) {
  68.                 if (c.value != null)
  69.                     this.completion.value = c.value;
  70.                 if (c.Continue > 0) {
  71.                     this.completion.Continue = c.Continue - 1;
  72.                     break;
  73.                 }
  74.                 if (c.Exit > 0) {
  75.                     this.completion.Exit = c.Exit - 1;
  76.                     break;
  77.                 }
  78.                 if (c.Return)
  79.                     return c;
  80.                 if (i >= n - 1)
  81.                     return this.completion;
  82.                 c = (Completion)((SwitchCase)(this.cases[++i])).Evaluate();
  83.             }
  84.             return this.completion;
  85.         }
  86.        
  87.         internal override AST PartiallyEvaluate()
  88.         {
  89.             this.expression = this.expression.PartiallyEvaluate();
  90.             ScriptObject current_scope = Globals.ScopeStack.Peek();
  91.             while (current_scope is WithObject)
  92.                 current_scope = current_scope.GetParent();
  93.             if (current_scope is FunctionScope) {
  94.                 FunctionScope scope = (FunctionScope)current_scope;
  95.                 BitArray before = scope.DefinedFlags;
  96.                 for (int i = 0int n = this.cases.count; i < n; i++) {
  97.                     this.cases[i] = this.cases[i].PartiallyEvaluate();
  98.                     scope.DefinedFlags = before;
  99.                 }
  100.             }
  101.             else
  102.                 for (int i = 0int n = this.cases.count; i < n; i++)
  103.                     this.cases[i] = this.cases[i].PartiallyEvaluate();
  104.             return this;
  105.         }
  106.        
  107.         internal override void TranslateToIL(ILGenerator il, Type rtype)
  108.         {
  109.             //This assumes that rtype == Void.class
  110.             //compile the expression and store it in a local
  111.             Type etype = Convert.ToType(this.expression.InferType(null));
  112.             this.expression.context.EmitLineInfo(il);
  113.             this.expression.TranslateToIL(il, etype);
  114.             LocalBuilder exprval = il.DeclareLocal(etype);
  115.             il.Emit(OpCodes.Stloc, exprval);
  116.            
  117.             //compile a series of conditional branches to the bodies
  118.             int n = this.cases.count;
  119.             Label[] labels = new Label[this.cases.count];
  120.             for (int i = 0; i < n; i++) {
  121.                 labels[i] = il.DefineLabel();
  122.                 if (i == this.default_case)
  123.                     continue;
  124.                 il.Emit(OpCodes.Ldloc, exprval);
  125.                 ((SwitchCase)this.cases[i]).TranslateToConditionalBranch(il, etype, true, labels[i], false);
  126.             }
  127.             Label endOfSwitch = il.DefineLabel();
  128.             if (this.default_case >= 0)
  129.                 il.Emit(OpCodes.Br, labels[this.default_case]);
  130.             else
  131.                 il.Emit(OpCodes.Br, endOfSwitch);
  132.            
  133.             //push a break label on the stack
  134.             compilerGlobals.BreakLabelStack.Push(endOfSwitch);
  135.             compilerGlobals.ContinueLabelStack.Push(endOfSwitch);
  136.            
  137.             //compile the bodies
  138.             for (int i = 0; i < n; i++) {
  139.                 il.MarkLabel(labels[i]);
  140.                 this.cases[i].TranslateToIL(il, Typeob.Void);
  141.             }
  142.             il.MarkLabel(endOfSwitch);
  143.            
  144.             //pop the break label
  145.             compilerGlobals.BreakLabelStack.Pop();
  146.             compilerGlobals.ContinueLabelStack.Pop();
  147.         }
  148.        
  149.         internal override void TranslateToILInitializer(ILGenerator il)
  150.         {
  151.             this.expression.TranslateToILInitializer(il);
  152.             for (int i = 0int n = this.cases.count; i < n; i++)
  153.                 this.cases[i].TranslateToILInitializer(il);
  154.         }
  155.        
  156.         internal override Context GetFirstExecutableContext()
  157.         {
  158.             return this.expression.context;
  159.         }
  160.     }
  161. }

Developer Fusion