internal static void AddEntriesFromIterable(ObjectInstance target, IIterator iterable, object adder) { if (!(adder is ICallable callable)) { ExceptionHelper.ThrowTypeError(target.Engine, "adder must be callable"); return; } var args = target.Engine._jsValueArrayPool.RentArray(2); var skipClose = true; try { do { if (!iterable.TryIteratorStep(out var nextItem)) { return; } var temp = nextItem.Get(CommonProperties.Value); skipClose = false; if (!(temp is ObjectInstance oi)) { ExceptionHelper.ThrowTypeError(target.Engine, "iterator's value must be an object"); return; } var k = oi.Get(JsString.NumberZeroString); var v = oi.Get(JsString.NumberOneString); args[0] = k; args[1] = v; callable.Call(target, args); } while (true); } catch { if (!skipClose) { iterable.Close(CompletionType.Throw); } throw; } finally { target.Engine._jsValueArrayPool.ReturnArray(args); } }
/// <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); } }
protected void IteratorClose(CompletionType completionType) { _iterator.Close(completionType); }
private static void HandleArrayPattern(Engine engine, ArrayPattern pattern, JsValue argument, LexicalEnvironment environment) { var obj = TypeConverter.ToObject(engine, argument); ArrayOperations arrayOperations = null; IIterator iterator = null; if (obj.IsArrayLike) { arrayOperations = ArrayOperations.For(obj); } else { if (!obj.TryGetIterator(engine, out iterator)) { ExceptionHelper.ThrowTypeError(engine); return; } } var completionType = CompletionType.Normal; var close = false; var done = false; uint i = 0; try { for (; i < pattern.Elements.Count; i++) { var left = pattern.Elements[(int)i]; if (left is null) { if (arrayOperations != null) { arrayOperations.TryGetValue(i, out _); } else { if (!ConsumeFromIterator(iterator, out _, out done)) { break; } } // skip assignment continue; } if (left is Identifier identifier) { JsValue value; if (arrayOperations != null) { arrayOperations.TryGetValue(i, out value); } else { if (!ConsumeFromIterator(iterator, out value, out done)) { break; } } AssignToIdentifier(engine, identifier.Name, value, environment); } else if (left is MemberExpression me) { close = true; var reference = GetReferenceFromMember(engine, me); JsValue value; if (arrayOperations != null) { arrayOperations.TryGetValue(i, out value); } else { ConsumeFromIterator(iterator, out value, out done); } AssignToReference(engine, reference, value, environment); } else if (left is BindingPattern bindingPattern) { JsValue value; if (arrayOperations != null) { arrayOperations.TryGetValue(i, out value); } else { iterator.TryIteratorStep(out var temp); value = temp; } ProcessPatterns(engine, bindingPattern, value, environment); } else if (left is RestElement restElement) { close = true; Reference reference = null; if (restElement.Argument is MemberExpression memberExpression) { reference = GetReferenceFromMember(engine, memberExpression); } ArrayInstance array; if (arrayOperations != null) { var length = arrayOperations.GetLength(); array = engine.Array.ConstructFast(length - i); for (uint j = i; j < length; ++j) { arrayOperations.TryGetValue(j, out var indexValue); array.SetIndexValue(j - i, indexValue, updateLength: false); } } else { array = engine.Array.ConstructFast(0); uint index = 0; done = true; do { if (!iterator.TryIteratorStep(out var item)) { done = true; break; } var value = item.Get(CommonProperties.Value); array.SetIndexValue(index++, value, updateLength: false); } while (true); array.SetLength(index); } if (restElement.Argument is Identifier leftIdentifier) { AssignToIdentifier(engine, leftIdentifier.Name, array, environment); } else if (restElement.Argument is BindingPattern bp) { ProcessPatterns(engine, bp, array, environment); } else { AssignToReference(engine, reference, array, environment); } } else if (left is AssignmentPattern assignmentPattern) { JsValue value; if (arrayOperations != null) { arrayOperations.TryGetValue(i, out value); } else { ConsumeFromIterator(iterator, out value, out done); } if (value.IsUndefined()) { var jintExpression = Build(engine, assignmentPattern.Right); value = jintExpression.GetValue(); } if (assignmentPattern.Left is Identifier leftIdentifier) { if (assignmentPattern.Right.IsFunctionWithName()) { ((FunctionInstance)value).SetFunctionName(new JsString(leftIdentifier.Name)); } AssignToIdentifier(engine, leftIdentifier.Name, value, environment); } else if (assignmentPattern.Left is BindingPattern bp) { ProcessPatterns(engine, bp, value, environment); } } else { ExceptionHelper.ThrowArgumentOutOfRangeException("pattern", "Unable to determine how to handle array pattern element " + left); break; } } close = true; } catch { completionType = CompletionType.Throw; throw; } finally { if (close && !done) { iterator?.Close(completionType); } } }