JintForStatement.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using System.Collections.Generic;
  2. using Esprima.Ast;
  3. using Jint.Native;
  4. using Jint.Runtime.Environments;
  5. using Jint.Runtime.Interpreter.Expressions;
  6. namespace Jint.Runtime.Interpreter.Statements
  7. {
  8. /// <summary>
  9. /// https://tc39.es/ecma262/#sec-forbodyevaluation
  10. /// </summary>
  11. internal sealed class JintForStatement : JintStatement<ForStatement>
  12. {
  13. private JintVariableDeclaration _initStatement;
  14. private JintExpression _initExpression;
  15. private JintExpression _test;
  16. private JintExpression _increment;
  17. private JintStatement _body;
  18. private List<string> _boundNames;
  19. private bool _shouldCreatePerIterationEnvironment;
  20. public JintForStatement(ForStatement statement) : base(statement)
  21. {
  22. }
  23. protected override void Initialize(EvaluationContext context)
  24. {
  25. var engine = context.Engine;
  26. _body = Build(_statement.Body);
  27. if (_statement.Init != null)
  28. {
  29. if (_statement.Init.Type == Nodes.VariableDeclaration)
  30. {
  31. var d = (VariableDeclaration) _statement.Init;
  32. if (d.Kind != VariableDeclarationKind.Var)
  33. {
  34. _boundNames = new List<string>();
  35. d.GetBoundNames(_boundNames);
  36. }
  37. _initStatement = new JintVariableDeclaration(d);
  38. _shouldCreatePerIterationEnvironment = d.Kind == VariableDeclarationKind.Let;
  39. }
  40. else
  41. {
  42. _initExpression = JintExpression.Build(engine, (Expression) _statement.Init);
  43. }
  44. }
  45. if (_statement.Test != null)
  46. {
  47. _test = JintExpression.Build(engine, _statement.Test);
  48. }
  49. if (_statement.Update != null)
  50. {
  51. _increment = JintExpression.Build(engine, _statement.Update);
  52. }
  53. }
  54. protected override Completion ExecuteInternal(EvaluationContext context)
  55. {
  56. EnvironmentRecord oldEnv = null;
  57. EnvironmentRecord loopEnv = null;
  58. var engine = context.Engine;
  59. if (_boundNames != null)
  60. {
  61. oldEnv = engine.ExecutionContext.LexicalEnvironment;
  62. loopEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv);
  63. var loopEnvRec = loopEnv;
  64. var kind = _initStatement._statement.Kind;
  65. for (var i = 0; i < _boundNames.Count; i++)
  66. {
  67. var name = _boundNames[i];
  68. if (kind == VariableDeclarationKind.Const)
  69. {
  70. loopEnvRec.CreateImmutableBinding(name, true);
  71. }
  72. else
  73. {
  74. loopEnvRec.CreateMutableBinding(name, false);
  75. }
  76. }
  77. engine.UpdateLexicalEnvironment(loopEnv);
  78. }
  79. try
  80. {
  81. if (_initExpression != null)
  82. {
  83. _initExpression?.GetValue(context);
  84. }
  85. else
  86. {
  87. _initStatement?.Execute(context);
  88. }
  89. return ForBodyEvaluation(context);
  90. }
  91. finally
  92. {
  93. if (oldEnv is not null)
  94. {
  95. engine.UpdateLexicalEnvironment(oldEnv);
  96. }
  97. }
  98. }
  99. /// <summary>
  100. /// https://tc39.es/ecma262/#sec-forbodyevaluation
  101. /// </summary>
  102. private Completion ForBodyEvaluation(EvaluationContext context)
  103. {
  104. var v = Undefined.Instance;
  105. if (_shouldCreatePerIterationEnvironment)
  106. {
  107. CreatePerIterationEnvironment(context);
  108. }
  109. while (true)
  110. {
  111. if (_test != null)
  112. {
  113. if (context.DebugMode)
  114. {
  115. context.Engine.DebugHandler.OnStep(_test._expression);
  116. }
  117. if (!TypeConverter.ToBoolean(_test.GetValue(context).Value))
  118. {
  119. return NormalCompletion(v);
  120. }
  121. }
  122. var result = _body.Execute(context);
  123. if (!ReferenceEquals(result.Value, null))
  124. {
  125. v = result.Value;
  126. }
  127. if (result.Type == CompletionType.Break && (result.Target == null || result.Target == _statement?.LabelSet?.Name))
  128. {
  129. return NormalCompletion(result.Value);
  130. }
  131. if (result.Type != CompletionType.Continue || (result.Target != null && result.Target != _statement?.LabelSet?.Name))
  132. {
  133. if (result.Type != CompletionType.Normal)
  134. {
  135. return result;
  136. }
  137. }
  138. if (_shouldCreatePerIterationEnvironment)
  139. {
  140. CreatePerIterationEnvironment(context);
  141. }
  142. if (_increment != null)
  143. {
  144. if (context.DebugMode)
  145. {
  146. context.Engine.DebugHandler.OnStep(_increment._expression);
  147. }
  148. _increment.GetValue(context);
  149. }
  150. }
  151. }
  152. private void CreatePerIterationEnvironment(EvaluationContext context)
  153. {
  154. if (_boundNames == null || _boundNames.Count == 0)
  155. {
  156. return;
  157. }
  158. var engine = context.Engine;
  159. var lastIterationEnv = engine.ExecutionContext.LexicalEnvironment;
  160. var lastIterationEnvRec = lastIterationEnv;
  161. var outer = lastIterationEnv._outerEnv;
  162. var thisIterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, outer);
  163. for (var j = 0; j < _boundNames.Count; j++)
  164. {
  165. var bn = _boundNames[j];
  166. var lastValue = lastIterationEnvRec.GetBindingValue(bn, true);
  167. thisIterationEnv.CreateMutableBindingAndInitialize(bn, false, lastValue);
  168. }
  169. engine.UpdateLexicalEnvironment(thisIterationEnv);
  170. }
  171. }
  172. }