123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- using Esprima.Ast;
- using Jint.Native;
- using Jint.Native.Iterator;
- using Jint.Runtime.Interpreter.Expressions;
- using Jint.Runtime.References;
- namespace Jint.Runtime.Interpreter.Statements
- {
- /// <summary>
- /// https://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements
- /// </summary>
- internal sealed class JintForOfStatement : JintStatement<ForOfStatement>
- {
- private JintStatement _body;
- private JintExpression _identifier;
- private BindingPattern _leftPattern;
- private JintExpression _right;
- public JintForOfStatement(Engine engine, ForOfStatement statement) : base(engine, statement)
- {
- _initialized = false;
- }
- protected override void Initialize()
- {
- if (_statement.Left is VariableDeclaration variableDeclaration)
- {
- var element = variableDeclaration.Declarations[0].Id;
- if (element is BindingPattern bindingPattern)
- {
- _leftPattern = bindingPattern;
- }
- else
- {
- _identifier = JintExpression.Build(_engine, (Identifier) element);
- }
- }
- else if (_statement.Left is BindingPattern bindingPattern)
- {
- _leftPattern = bindingPattern;
- }
- else
- {
- _identifier = JintExpression.Build(_engine, (Expression) _statement.Left);
- }
- _body = Build(_engine, _statement.Body);
- _right = JintExpression.Build(_engine, _statement.Right);
- }
- protected override Completion ExecuteInternal()
- {
- var experValue = _right.GetValue();
- if (!(experValue is IIterator iterator))
- {
- var obj = TypeConverter.ToObject(_engine, experValue);
- obj.TryGetIterator(_engine, out iterator);
- }
- if (iterator is null)
- {
- return ExceptionHelper.ThrowTypeError<Completion>(_engine, _identifier + " is not iterable");
- }
- var completionType = CompletionType.Normal;
- var v = JsValue.Undefined;
- var close = false;
- try
- {
- do
- {
- iterator.TryIteratorStep(out var item);
- var done = item.Get(CommonProperties.Done);
- if (TypeConverter.ToBoolean(done))
- {
- // we can close after checks pass
- close = true;
- break;
- }
- var currentValue = item.Get(CommonProperties.Value);
- // we can close after checks pass
- close = true;
- if (_leftPattern != null)
- {
- BindingPatternAssignmentExpression.ProcessPatterns(
- _engine,
- _leftPattern,
- currentValue,
- checkReference: !(_statement.Left is VariableDeclaration));
- }
- else
- {
- var varRef = (Reference) _identifier.Evaluate();
- _engine.PutValue(varRef, currentValue);
- }
- var stmt = _body.Execute();
- if (!ReferenceEquals(stmt.Value, null))
- {
- v = stmt.Value;
- }
- if (stmt.Type == CompletionType.Break && (stmt.Identifier == null || stmt.Identifier == _statement?.LabelSet?.Name))
- {
- return new Completion(CompletionType.Normal, stmt.Value, null, Location);
- }
- if (stmt.Type != CompletionType.Continue || ((stmt.Identifier != null) && stmt.Identifier != _statement?.LabelSet?.Name))
- {
- if (stmt.Type != CompletionType.Normal)
- {
- return stmt;
- }
- }
-
- } while (true);
- }
- catch
- {
- completionType = CompletionType.Throw;
- throw;
- }
- finally
- {
- if (close)
- {
- iterator.Close(completionType);
- }
- }
- return new Completion(CompletionType.Normal, v, null, Location);
- }
- }
- }
|