JintSwitchBlock.cs 4.2 KB

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