diff --git a/Libraries/LibJS/Runtime/Iterator.cpp b/Libraries/LibJS/Runtime/Iterator.cpp index a3be43801fd..228829e359f 100644 --- a/Libraries/LibJS/Runtime/Iterator.cpp +++ b/Libraries/LibJS/Runtime/Iterator.cpp @@ -203,13 +203,24 @@ ThrowCompletionOr iterator_value(VM& vm, Object& iterator_result) } // 7.4.9 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep -ThrowCompletionOr> iterator_step(VM& vm, IteratorRecord& iterator_record) +ThrowCompletionOr iterator_step(VM& vm, IteratorRecord& iterator_record) { + if (auto* builtin_iterator = iterator_record.iterator->as_builtin_iterator_if_next_is_not_redefined()) { + Value value; + bool done = false; + TRY(builtin_iterator->next(vm, done, value)); + if (done) { + iterator_record.done = true; + return ThrowCompletionOr { IterationDone {} }; + } + return ThrowCompletionOr { IterationResult { done, value } }; + } + // 1. Let result be ? IteratorNext(iteratorRecord). auto result = TRY(iterator_next(vm, iterator_record)); // 2. Let done be Completion(IteratorComplete(result)). - auto done = iterator_complete(vm, result); + auto done = result->get(vm.names.done); // 3. If done is a throw completion, then if (done.is_throw_completion()) { @@ -224,32 +235,32 @@ ThrowCompletionOr> iterator_step(VM& vm, IteratorRecord& iterato auto done_value = done.release_value(); // 5. If done is true, then - if (done_value) { + if (done_value.to_boolean()) { // a. Set iteratorRecord.[[Done]] to true. iterator_record.done = true; // b. Return DONE. - return nullptr; + return ThrowCompletionOr { IterationDone {} }; } // 6. Return result. - return result; + return ThrowCompletionOr { IterationResult { done_value, result->get(vm.names.value) } }; } // 7.4.10 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue ThrowCompletionOr> iterator_step_value(VM& vm, IteratorRecord& iterator_record) { // 1. Let result be ? IteratorStep(iteratorRecord). - auto result = TRY(iterator_step(vm, iterator_record)); + IterationResultOrDone result = TRY(iterator_step(vm, iterator_record)); // 2. If result is done, then - if (!result) { + if (result.has()) { // a. Return DONE. return OptionalNone {}; } // 3. Let value be Completion(IteratorValue(result)). - auto value = iterator_value(vm, *result); + auto& value = result.get().value; // 4. If value is a throw completion, then if (value.is_throw_completion()) { @@ -363,8 +374,10 @@ ThrowCompletionOr> iterator_to_list(VM& vm, IteratorRecord return values; } + auto value = next.release_value(); + // c. Append next to values. - values.append(next.release_value()); + values.append(value); } } diff --git a/Libraries/LibJS/Runtime/Iterator.h b/Libraries/LibJS/Runtime/Iterator.h index 3fd533fb186..b7c6598c78d 100644 --- a/Libraries/LibJS/Runtime/Iterator.h +++ b/Libraries/LibJS/Runtime/Iterator.h @@ -76,6 +76,13 @@ protected: bool m_next_method_was_redefined { false }; }; +struct IterationResult { + ThrowCompletionOr done; + ThrowCompletionOr value; +}; +struct IterationDone { }; +using IterationResultOrDone = Variant; + // 7.4.12 IfAbruptCloseIterator ( value, iteratorRecord ), https://tc39.es/ecma262/#sec-ifabruptcloseiterator #define TRY_OR_CLOSE_ITERATOR(vm, iterator_record, expression) \ ({ \ @@ -101,7 +108,7 @@ ThrowCompletionOr> get_iterator_flattenable(VM&, Value, ThrowCompletionOr> iterator_next(VM&, IteratorRecord&, Optional = {}); ThrowCompletionOr iterator_complete(VM&, Object& iterator_result); ThrowCompletionOr iterator_value(VM&, Object& iterator_result); -ThrowCompletionOr> iterator_step(VM&, IteratorRecord&); +ThrowCompletionOr iterator_step(VM&, IteratorRecord&); ThrowCompletionOr> iterator_step_value(VM&, IteratorRecord&); Completion iterator_close(VM&, IteratorRecord const&, Completion); Completion async_iterator_close(VM&, IteratorRecord const&, Completion); diff --git a/Libraries/LibJS/Runtime/IteratorPrototype.cpp b/Libraries/LibJS/Runtime/IteratorPrototype.cpp index e20b1819a0e..f2abb190991 100644 --- a/Libraries/LibJS/Runtime/IteratorPrototype.cpp +++ b/Libraries/LibJS/Runtime/IteratorPrototype.cpp @@ -128,10 +128,10 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop) iterator.increment_counter(); // ii. Let next be ? IteratorStep(iterated). - auto next = TRY(iterator_step(vm, iterated)); + IterationResultOrDone next = TRY(iterator_step(vm, iterated)); // iii. If next is DONE, return ReturnCompletion(undefined). - if (!next) + if (next.has()) return iterator.result(js_undefined()); } diff --git a/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Libraries/LibWeb/Animations/KeyframeEffect.cpp index 02518616261..c5dbcac6ede 100644 --- a/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -346,12 +346,12 @@ static WebIDL::ExceptionOr> process_a_keyframes_argument(JS auto next = TRY(JS::iterator_step(vm, iter)); // 3. If next is false abort this loop. - if (!next) + if (!next.has()) break; // 4. Let nextItem be IteratorValue(next). // 5. Check the completion record of nextItem. - auto next_item = TRY(JS::iterator_value(vm, *next)); + auto next_item = TRY(next.get().value); // 6. If Type(nextItem) is not Undefined, Null or Object, then throw a TypeError and abort these steps. if (!next_item.is_nullish() && !next_item.is_object()) diff --git a/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp b/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp index 29dbb229e49..6c4622687f9 100644 --- a/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp +++ b/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp @@ -89,11 +89,11 @@ static JS::ThrowCompletionOr> convert_value_to_sequence_of_string auto next = TRY(JS::iterator_step(vm, iterator)); // 2. If next is false, then return an IDL sequence value of type sequence of length i, where the value of the element at index j is Sj. - if (!next) + if (!next.has()) return sequence_of_strings; // 3. Let nextItem be ? IteratorValue(next). - auto next_item = TRY(JS::iterator_value(vm, *next)); + auto next_item = TRY(next.get().value); // 4. Initialize Si to the result of converting nextItem to an IDL value of type T. diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 039d03304b8..bdf842dbab0 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -1766,10 +1766,10 @@ void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& ge sequence_generator.append(R"~~~( for (;;) { auto next@recursion_depth@ = TRY(JS::iterator_step(vm, @iterable_cpp_name@_iterator@recursion_depth@)); - if (!next@recursion_depth@) + if (!next@recursion_depth@.has()) break; - auto next_item@recursion_depth@ = TRY(JS::iterator_value(vm, *next@recursion_depth@)); + auto next_item@recursion_depth@ = TRY(next@recursion_depth@.get().value); )~~~"); // FIXME: Sequences types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here.