JintForStatement.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. /// <summary>
  7. /// https://tc39.es/ecma262/#sec-forbodyevaluation
  8. /// </summary>
  9. internal sealed class JintForStatement : JintStatement<ForStatement>
  10. {
  11. private JintVariableDeclaration? _initStatement;
  12. private JintExpression? _initExpression;
  13. private JintExpression? _test;
  14. private JintExpression? _increment;
  15. private ProbablyBlockStatement _body;
  16. private List<Key>? _boundNames;
  17. private bool _shouldCreatePerIterationEnvironment;
  18. public JintForStatement(ForStatement statement) : base(statement)
  19. {
  20. }
  21. protected override void Initialize(EvaluationContext context)
  22. {
  23. var engine = context.Engine;
  24. _body = new ProbablyBlockStatement(_statement.Body);
  25. if (_statement.Init != null)
  26. {
  27. if (_statement.Init.Type == NodeType.VariableDeclaration)
  28. {
  29. var d = (VariableDeclaration) _statement.Init;
  30. if (d.Kind != VariableDeclarationKind.Var)
  31. {
  32. _boundNames = new List<Key>();
  33. d.GetBoundNames(_boundNames);
  34. }
  35. _initStatement = new JintVariableDeclaration(d);
  36. _shouldCreatePerIterationEnvironment = d.Kind == VariableDeclarationKind.Let;
  37. }
  38. else
  39. {
  40. _initExpression = JintExpression.Build((Expression) _statement.Init);
  41. }
  42. }
  43. if (_statement.Test != null)
  44. {
  45. _test = JintExpression.Build(_statement.Test);
  46. }
  47. if (_statement.Update != null)
  48. {
  49. _increment = JintExpression.Build(_statement.Update);
  50. }
  51. }
  52. protected override Completion ExecuteInternal(EvaluationContext context)
  53. {
  54. Environment? oldEnv = null;
  55. Environment? loopEnv = null;
  56. var engine = context.Engine;
  57. if (_boundNames != null)
  58. {
  59. oldEnv = engine.ExecutionContext.LexicalEnvironment;
  60. loopEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv);
  61. var loopEnvRec = loopEnv;
  62. var kind = _initStatement!._statement.Kind;
  63. for (var i = 0; i < _boundNames.Count; i++)
  64. {
  65. var name = _boundNames[i];
  66. if (kind == VariableDeclarationKind.Const)
  67. {
  68. loopEnvRec.CreateImmutableBinding(name);
  69. }
  70. else
  71. {
  72. loopEnvRec.CreateMutableBinding(name);
  73. }
  74. }
  75. engine.UpdateLexicalEnvironment(loopEnv);
  76. }
  77. try
  78. {
  79. if (_initExpression != null)
  80. {
  81. _initExpression?.GetValue(context);
  82. }
  83. else
  84. {
  85. _initStatement?.Execute(context);
  86. }
  87. return ForBodyEvaluation(context);
  88. }
  89. finally
  90. {
  91. if (oldEnv is not null)
  92. {
  93. engine.UpdateLexicalEnvironment(oldEnv);
  94. }
  95. }
  96. }
  97. /// <summary>
  98. /// https://tc39.es/ecma262/#sec-forbodyevaluation
  99. /// </summary>
  100. private Completion ForBodyEvaluation(EvaluationContext context)
  101. {
  102. var v = JsValue.Undefined;
  103. if (_shouldCreatePerIterationEnvironment)
  104. {
  105. CreatePerIterationEnvironment(context);
  106. }
  107. var debugHandler = context.DebugMode ? context.Engine.Debugger : null;
  108. while (true)
  109. {
  110. if (_test != null)
  111. {
  112. debugHandler?.OnStep(_test._expression);
  113. if (!TypeConverter.ToBoolean(_test.GetValue(context)))
  114. {
  115. return new Completion(CompletionType.Normal, v, ((JintStatement) this)._statement);
  116. }
  117. }
  118. var result = _body.Execute(context);
  119. if (!result.Value.IsEmpty)
  120. {
  121. v = result.Value;
  122. }
  123. if (result.Type == CompletionType.Break && (context.Target == null || string.Equals(context.Target, _statement?.LabelSet?.Name, StringComparison.Ordinal)))
  124. {
  125. return new Completion(CompletionType.Normal, result.Value, ((JintStatement) this)._statement);
  126. }
  127. if (result.Type != CompletionType.Continue || (context.Target != null && !string.Equals(context.Target, _statement?.LabelSet?.Name, StringComparison.Ordinal)))
  128. {
  129. if (result.Type != CompletionType.Normal)
  130. {
  131. return result;
  132. }
  133. }
  134. if (_shouldCreatePerIterationEnvironment)
  135. {
  136. CreatePerIterationEnvironment(context);
  137. }
  138. if (_increment != null)
  139. {
  140. debugHandler?.OnStep(_increment._expression);
  141. _increment.Evaluate(context);
  142. }
  143. }
  144. }
  145. private void CreatePerIterationEnvironment(EvaluationContext context)
  146. {
  147. var engine = context.Engine;
  148. var lastIterationEnv = (DeclarativeEnvironment) engine.ExecutionContext.LexicalEnvironment;
  149. var thisIterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, lastIterationEnv._outerEnv);
  150. lastIterationEnv.TransferTo(_boundNames!, thisIterationEnv);
  151. engine.UpdateLexicalEnvironment(thisIterationEnv);
  152. }
  153. }