JintSwitchBlock.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using Esprima.Ast;
  2. using Jint.Native;
  3. using Jint.Runtime.Environments;
  4. using Jint.Runtime.Interpreter.Expressions;
  5. namespace Jint.Runtime.Interpreter.Statements
  6. {
  7. internal sealed class JintSwitchBlock
  8. {
  9. private readonly NodeList<SwitchCase> _switchBlock;
  10. private JintSwitchCase[] _jintSwitchBlock = Array.Empty<JintSwitchCase>();
  11. private bool _initialized;
  12. public JintSwitchBlock(NodeList<SwitchCase> switchBlock)
  13. {
  14. _switchBlock = switchBlock;
  15. }
  16. private void Initialize()
  17. {
  18. _jintSwitchBlock = new JintSwitchCase[_switchBlock.Count];
  19. for (var i = 0; i < _jintSwitchBlock.Length; i++)
  20. {
  21. _jintSwitchBlock[i] = new JintSwitchCase(_switchBlock[i]);
  22. }
  23. }
  24. public Completion Execute(EvaluationContext context, JsValue input)
  25. {
  26. if (!_initialized)
  27. {
  28. Initialize();
  29. _initialized = true;
  30. }
  31. var v = JsValue.Undefined;
  32. var l = context.LastSyntaxElement;
  33. var hit = false;
  34. var defaultCaseIndex = -1;
  35. var i = 0;
  36. EnvironmentRecord? oldEnv = null;
  37. var temp = _jintSwitchBlock;
  38. start:
  39. for (; i < temp.Length; i++)
  40. {
  41. var clause = temp[i];
  42. if (clause.LexicalDeclarations is not null && oldEnv is null)
  43. {
  44. oldEnv = context.Engine.ExecutionContext.LexicalEnvironment;
  45. var blockEnv = JintEnvironment.NewDeclarativeEnvironment(context.Engine, oldEnv);
  46. JintStatementList.BlockDeclarationInstantiation(context.Engine, blockEnv, clause.LexicalDeclarations);
  47. context.Engine.UpdateLexicalEnvironment(blockEnv);
  48. }
  49. if (clause.Test == null)
  50. {
  51. defaultCaseIndex = i;
  52. if (!hit)
  53. {
  54. continue;
  55. }
  56. }
  57. var clauseSelector = clause.Test?.GetValue(context);
  58. if (clauseSelector == input)
  59. {
  60. hit = true;
  61. }
  62. if (!hit)
  63. {
  64. continue;
  65. }
  66. var r = clause.Consequent.Execute(context);
  67. if (r.Type != CompletionType.Normal)
  68. {
  69. if (oldEnv is not null)
  70. {
  71. context.Engine.UpdateLexicalEnvironment(oldEnv);
  72. }
  73. return r.UpdateEmpty(v);
  74. }
  75. l = r._source;
  76. v = r.Value.IsUndefined() ? v : r.Value;
  77. }
  78. // do we need to execute the default case ?
  79. if (!hit && defaultCaseIndex != -1)
  80. {
  81. // jump back to loop and start from default case
  82. hit = true;
  83. i = defaultCaseIndex;
  84. goto start;
  85. }
  86. if (oldEnv is not null)
  87. {
  88. context.Engine.UpdateLexicalEnvironment(oldEnv);
  89. }
  90. return new Completion(CompletionType.Normal, v, l);
  91. }
  92. private sealed class JintSwitchCase
  93. {
  94. internal readonly JintStatementList Consequent;
  95. internal readonly JintExpression? Test;
  96. internal readonly List<Declaration>? LexicalDeclarations;
  97. public JintSwitchCase(SwitchCase switchCase)
  98. {
  99. Consequent = new JintStatementList(statement: null, switchCase.Consequent);
  100. LexicalDeclarations = HoistingScope.GetLexicalDeclarations(switchCase);
  101. if (switchCase.Test != null)
  102. {
  103. Test = JintExpression.Build(switchCase.Test);
  104. }
  105. }
  106. }
  107. }
  108. }