2
0

JintSwitchBlock.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using Jint.Native;
  2. using Jint.Runtime.Environments;
  3. using Jint.Runtime.Interpreter.Expressions;
  4. using Environment = Jint.Runtime.Environments.Environment;
  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. Environment? oldEnv = null;
  37. var temp = _jintSwitchBlock;
  38. DeclarativeEnvironment? blockEnv = null;
  39. start:
  40. for (; i < temp.Length; i++)
  41. {
  42. var clause = temp[i];
  43. if (clause.LexicalDeclarations is not null && oldEnv is null)
  44. {
  45. oldEnv = context.Engine.ExecutionContext.LexicalEnvironment;
  46. blockEnv ??= JintEnvironment.NewDeclarativeEnvironment(context.Engine, oldEnv);
  47. blockEnv.Clear();
  48. JintStatementList.BlockDeclarationInstantiation(blockEnv, clause.LexicalDeclarations);
  49. context.Engine.UpdateLexicalEnvironment(blockEnv);
  50. }
  51. if (clause.Test == null)
  52. {
  53. defaultCaseIndex = i;
  54. if (!hit)
  55. {
  56. continue;
  57. }
  58. }
  59. var clauseSelector = clause.Test?.GetValue(context);
  60. if (clauseSelector == input)
  61. {
  62. hit = true;
  63. }
  64. if (!hit)
  65. {
  66. if (oldEnv is not null)
  67. {
  68. context.Engine.UpdateLexicalEnvironment(oldEnv);
  69. oldEnv = null;
  70. }
  71. continue;
  72. }
  73. var r = clause.Consequent.Execute(context);
  74. if (r.Type != CompletionType.Normal)
  75. {
  76. if (oldEnv is not null)
  77. {
  78. context.Engine.UpdateLexicalEnvironment(oldEnv);
  79. }
  80. return r.UpdateEmpty(v);
  81. }
  82. l = r._source;
  83. v = r.Value.IsUndefined() ? v : r.Value;
  84. }
  85. // do we need to execute the default case ?
  86. if (!hit && defaultCaseIndex != -1)
  87. {
  88. // jump back to loop and start from default case
  89. hit = true;
  90. i = defaultCaseIndex;
  91. goto start;
  92. }
  93. if (oldEnv is not null)
  94. {
  95. context.Engine.UpdateLexicalEnvironment(oldEnv);
  96. }
  97. return new Completion(CompletionType.Normal, v, l);
  98. }
  99. private sealed class JintSwitchCase
  100. {
  101. internal readonly JintStatementList Consequent;
  102. internal readonly JintExpression? Test;
  103. internal readonly List<Declaration>? LexicalDeclarations;
  104. public JintSwitchCase(SwitchCase switchCase)
  105. {
  106. Consequent = new JintStatementList(statement: null, switchCase.Consequent);
  107. LexicalDeclarations = HoistingScope.GetLexicalDeclarations(switchCase);
  108. if (switchCase.Test != null)
  109. {
  110. Test = JintExpression.Build(switchCase.Test);
  111. }
  112. }
  113. }
  114. }
  115. }