protected override void Initialize(EvaluationContext context) { _lhsKind = LhsKind.Assignment; var engine = context.Engine; if (_leftNode is VariableDeclaration variableDeclaration) { _lhsKind = variableDeclaration.Kind == VariableDeclarationKind.Var ? LhsKind.VarBinding : LhsKind.LexicalBinding; var variableDeclarationDeclaration = variableDeclaration.Declarations[0]; var id = variableDeclarationDeclaration.Id; if (_lhsKind == LhsKind.LexicalBinding) { _tdzNames = new List <string>(1); id.GetBoundNames(_tdzNames); } if (id is BindingPattern bindingPattern) { _destructuring = true; _assignmentPattern = bindingPattern; } else { var identifier = (Identifier)id; _expr = new JintIdentifierExpression(identifier); } } else if (_leftNode is BindingPattern bindingPattern) { _destructuring = true; _assignmentPattern = bindingPattern; } else if (_leftNode is MemberExpression memberExpression) { _expr = new JintMemberExpression(memberExpression); } else { _expr = new JintIdentifierExpression((Identifier)_leftNode); } _body = Build(_forBody); _right = JintExpression.Build(engine, _rightExpression); }
/// <summary> /// https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset /// </summary> private Completion BodyEvaluation( JintExpression lhs, JintStatement stmt, IIterator iteratorRecord, IterationKind iterationKind, LhsKind lhsKind, IteratorKind iteratorKind = IteratorKind.Sync) { var oldEnv = _engine.ExecutionContext.LexicalEnvironment; var v = Undefined.Instance; var destructuring = _destructuring; string lhsName = null; var completionType = CompletionType.Normal; var close = false; try { while (true) { LexicalEnvironment iterationEnv = null; if (!iteratorRecord.TryIteratorStep(out var nextResult)) { close = true; return(new Completion(CompletionType.Normal, v, null, Location)); } if (iteratorKind == IteratorKind.Async) { // nextResult = await nextResult; } var nextValue = nextResult.Get(CommonProperties.Value); close = true; Reference lhsRef = null; if (lhsKind != LhsKind.LexicalBinding) { if (!destructuring) { lhsRef = (Reference)lhs.Evaluate(); } } else { iterationEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, oldEnv); if (_tdzNames != null) { BindingInstantiation(iterationEnv); } _engine.UpdateLexicalEnvironment(iterationEnv); if (!destructuring) { if (lhsName == null) { lhsName = ((Identifier)((VariableDeclaration)_leftNode).Declarations[0].Id).Name; } lhsRef = _engine.ResolveBinding(lhsName); } } if (!destructuring) { // If lhsRef is an abrupt completion, then // Let status be lhsRef. if (lhsKind == LhsKind.LexicalBinding) { lhsRef.InitializeReferencedBinding(nextValue); } else { _engine.PutValue(lhsRef, nextValue); } } else { BindingPatternAssignmentExpression.ProcessPatterns( _engine, _assignmentPattern, nextValue, iterationEnv, checkObjectPatternPropertyReference: _lhsKind != LhsKind.VarBinding); if (lhsKind == LhsKind.Assignment) { // DestructuringAssignmentEvaluation of assignmentPattern using nextValue as the argument. } else if (lhsKind == LhsKind.VarBinding) { // BindingInitialization for lhs passing nextValue and undefined as the arguments. } else { // BindingInitialization for lhs passing nextValue and iterationEnv as arguments } } var result = stmt.Execute(); _engine.UpdateLexicalEnvironment(oldEnv); if (!ReferenceEquals(result.Value, null)) { v = result.Value; } if (result.Type == CompletionType.Break && (result.Identifier == null || result.Identifier == _statement?.LabelSet?.Name)) { return(new Completion(CompletionType.Normal, v, null, Location)); } if (result.Type != CompletionType.Continue || (result.Identifier != null && result.Identifier != _statement?.LabelSet?.Name)) { if (result.Type != CompletionType.Normal) { return(result); } } } } catch { completionType = CompletionType.Throw; throw; } finally { if (close) { iteratorRecord.Close(completionType); } _engine.UpdateLexicalEnvironment(oldEnv); } }
/// <summary> /// https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset /// </summary> private Completion BodyEvaluation( EvaluationContext context, JintExpression lhs, JintStatement stmt, IteratorInstance iteratorRecord, IterationKind iterationKind, LhsKind lhsKind, IteratorKind iteratorKind = IteratorKind.Sync) { var engine = context.Engine; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var v = Undefined.Instance; var destructuring = _destructuring; string lhsName = null; var completionType = CompletionType.Normal; var close = false; try { while (true) { EnvironmentRecord iterationEnv = null; if (!iteratorRecord.TryIteratorStep(out var nextResult)) { close = true; return(new Completion(CompletionType.Normal, v, null, Location)); } if (iteratorKind == IteratorKind.Async) { // nextResult = await nextResult; ExceptionHelper.ThrowNotImplementedException("await"); } var nextValue = nextResult.Get(CommonProperties.Value); close = true; var lhsRef = new ExpressionResult(); if (lhsKind != LhsKind.LexicalBinding) { if (!destructuring) { lhsRef = lhs.Evaluate(context); } } else { iterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); if (_tdzNames != null) { BindingInstantiation(iterationEnv); } engine.UpdateLexicalEnvironment(iterationEnv); if (!destructuring) { var identifier = (Identifier)((VariableDeclaration)_leftNode).Declarations[0].Id; lhsName ??= identifier.Name; lhsRef = new ExpressionResult(ExpressionCompletionType.Normal, engine.ResolveBinding(lhsName), identifier.Location); } } if (context.DebugMode) { context.Engine.DebugHandler.OnStep(_leftNode); } var status = new Completion(); if (!destructuring) { if (lhsRef.IsAbrupt()) { close = true; status = new Completion(lhsRef); } else if (lhsKind == LhsKind.LexicalBinding) { ((Reference)lhsRef.Value).InitializeReferencedBinding(nextValue); } else { engine.PutValue((Reference)lhsRef.Value, nextValue); } } else { status = BindingPatternAssignmentExpression.ProcessPatterns( context, _assignmentPattern, nextValue, iterationEnv, checkObjectPatternPropertyReference: _lhsKind != LhsKind.VarBinding); if (lhsKind == LhsKind.Assignment) { // DestructuringAssignmentEvaluation of assignmentPattern using nextValue as the argument. } else if (lhsKind == LhsKind.VarBinding) { // BindingInitialization for lhs passing nextValue and undefined as the arguments. } else { // BindingInitialization for lhs passing nextValue and iterationEnv as arguments } } if (status.IsAbrupt()) { engine.UpdateLexicalEnvironment(oldEnv); if (_iterationKind == IterationKind.AsyncIterate) { iteratorRecord.Close(status.Type); return(status); } if (iterationKind == IterationKind.Enumerate) { return(status); } iteratorRecord.Close(status.Type); return(status); } var result = stmt.Execute(context); engine.UpdateLexicalEnvironment(oldEnv); if (!ReferenceEquals(result.Value, null)) { v = result.Value; } if (result.Type == CompletionType.Break && (result.Target == null || result.Target == _statement?.LabelSet?.Name)) { completionType = CompletionType.Normal; return(new Completion(CompletionType.Normal, v, null, Location)); } if (result.Type != CompletionType.Continue || (result.Target != null && result.Target != _statement?.LabelSet?.Name)) { completionType = result.Type; if (result.IsAbrupt()) { close = true; return(result); } } } } catch { completionType = CompletionType.Throw; throw; } finally { if (close) { try { iteratorRecord.Close(completionType); } catch { // if we already have and exception, use it if (completionType != CompletionType.Throw) { throw; } } } engine.UpdateLexicalEnvironment(oldEnv); } }