JintSwitchBlock.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System.Collections.Generic;
  2. using Esprima;
  3. using Esprima.Ast;
  4. using Jint.Native;
  5. using Jint.Runtime.Environments;
  6. using Jint.Runtime.Interpreter.Expressions;
  7. namespace Jint.Runtime.Interpreter.Statements
  8. {
  9. internal sealed class JintSwitchBlock
  10. {
  11. private readonly Engine _engine;
  12. private readonly NodeList<SwitchCase> _switchBlock;
  13. private JintSwitchCase[] _jintSwitchBlock;
  14. private bool _initialized;
  15. public JintSwitchBlock(Engine engine, NodeList<SwitchCase> switchBlock)
  16. {
  17. _engine = engine;
  18. _switchBlock = switchBlock;
  19. }
  20. private void Initialize()
  21. {
  22. _jintSwitchBlock = new JintSwitchCase[_switchBlock.Count];
  23. for (var i = 0; i < _jintSwitchBlock.Length; i++)
  24. {
  25. _jintSwitchBlock[i] = new JintSwitchCase(_engine, _switchBlock[i]);
  26. }
  27. }
  28. public Completion Execute(JsValue input)
  29. {
  30. if (!_initialized)
  31. {
  32. Initialize();
  33. _initialized = true;
  34. }
  35. JsValue v = Undefined.Instance;
  36. Location l = _engine._lastSyntaxNode.Location;
  37. JintSwitchCase defaultCase = null;
  38. bool hit = false;
  39. for (var i = 0; i < (uint) _jintSwitchBlock.Length; i++)
  40. {
  41. var clause = _jintSwitchBlock[i];
  42. LexicalEnvironment oldEnv = null;
  43. if (clause.LexicalDeclarations != null)
  44. {
  45. oldEnv = _engine.ExecutionContext.LexicalEnvironment;
  46. var blockEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, oldEnv);
  47. JintStatementList.BlockDeclarationInstantiation(blockEnv, clause.LexicalDeclarations);
  48. _engine.UpdateLexicalEnvironment(blockEnv);
  49. }
  50. if (clause.Test == null)
  51. {
  52. defaultCase = clause;
  53. }
  54. else
  55. {
  56. var clauseSelector = clause.Test.GetValue();
  57. if (JintBinaryExpression.StrictlyEqual(clauseSelector, input))
  58. {
  59. hit = true;
  60. }
  61. }
  62. if (hit && clause.Consequent != null)
  63. {
  64. var r = clause.Consequent.Execute();
  65. if (oldEnv != null)
  66. {
  67. _engine.UpdateLexicalEnvironment(oldEnv);
  68. }
  69. if (r.Type != CompletionType.Normal)
  70. {
  71. return r;
  72. }
  73. l = r.Location;
  74. v = r.Value ?? Undefined.Instance;
  75. }
  76. }
  77. // do we need to execute the default case ?
  78. if (hit == false && defaultCase != null)
  79. {
  80. LexicalEnvironment oldEnv = null;
  81. if (defaultCase.LexicalDeclarations != null)
  82. {
  83. oldEnv = _engine.ExecutionContext.LexicalEnvironment;
  84. var blockEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, oldEnv);
  85. JintStatementList.BlockDeclarationInstantiation(blockEnv, defaultCase.LexicalDeclarations);
  86. _engine.UpdateLexicalEnvironment(blockEnv);
  87. }
  88. var r = defaultCase.Consequent.Execute();
  89. if (oldEnv != null)
  90. {
  91. _engine.UpdateLexicalEnvironment(oldEnv);
  92. }
  93. if (r.Type != CompletionType.Normal)
  94. {
  95. return r;
  96. }
  97. l = r.Location;
  98. v = r.Value ?? Undefined.Instance;
  99. }
  100. return new Completion(CompletionType.Normal, v, null, l);
  101. }
  102. private sealed class JintSwitchCase
  103. {
  104. internal readonly JintStatementList Consequent;
  105. internal readonly JintExpression Test;
  106. internal readonly List<VariableDeclaration> LexicalDeclarations;
  107. public JintSwitchCase(Engine engine, SwitchCase switchCase)
  108. {
  109. Consequent = new JintStatementList(engine, null, switchCase.Consequent);
  110. LexicalDeclarations = HoistingScope.GetLexicalDeclarations(switchCase);
  111. if (switchCase.Test != null)
  112. {
  113. Test = JintExpression.Build(engine, switchCase.Test);
  114. }
  115. }
  116. }
  117. }
  118. }