diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index bb0066d5f3..aa34dd939e 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -3264,7 +3264,7 @@ void generate_constructor_implementation(IDL::Interface const& interface, String #include #include #include -#include +#include #include #include #include @@ -3651,7 +3651,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu #include #include #include -#include +#include #include #include #include @@ -3954,7 +3954,7 @@ void generate_global_mixin_implementation(IDL::Interface const& interface, Strin #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 99f1161238..c0c6e48cba 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 6152b5f61c..52d5d835bc 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 7a54522dff..e111aaf7e9 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index 0f249e9f37..3e0d8e5f5f 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -147,7 +147,6 @@ set(SOURCES Runtime/IteratorConstructor.cpp Runtime/IteratorHelper.cpp Runtime/IteratorHelperPrototype.cpp - Runtime/IteratorOperations.cpp Runtime/IteratorPrototype.cpp Runtime/JSONObject.cpp Runtime/JobCallback.cpp diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h index 153a03f6d6..bbf1e93eee 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/AggregateErrorConstructor.cpp b/Userland/Libraries/LibJS/Runtime/AggregateErrorConstructor.cpp index f14965c9eb..1b8cbf50fc 100644 --- a/Userland/Libraries/LibJS/Runtime/AggregateErrorConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/AggregateErrorConstructor.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/ArrayConstructor.cpp b/Userland/Libraries/LibJS/Runtime/ArrayConstructor.cpp index fa6110bf8c..075b4b3511 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayConstructor.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp index 89498d7560..b1f0b85a9c 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayIteratorPrototype.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp index 8d9aed3627..a261a9a3b6 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncFromSyncIteratorPrototype.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/AsyncGeneratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/AsyncGeneratorPrototype.cpp index 0fad0e3c1b..096142d9a8 100644 --- a/Userland/Libraries/LibJS/Runtime/AsyncGeneratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/AsyncGeneratorPrototype.cpp @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp index 39ab4e66fc..63b3a55446 100644 --- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp index 1b16be66a4..7f0d62f4d9 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/ListFormat.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include namespace JS::Intl { diff --git a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp index b1f1877694..41f98a7edd 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/SegmentIteratorPrototype.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace JS::Intl { diff --git a/Userland/Libraries/LibJS/Runtime/Iterator.cpp b/Userland/Libraries/LibJS/Runtime/Iterator.cpp index dc49d57021..f33b6090a7 100644 --- a/Userland/Libraries/LibJS/Runtime/Iterator.cpp +++ b/Userland/Libraries/LibJS/Runtime/Iterator.cpp @@ -1,10 +1,15 @@ /* + * Copyright (c) 2020, Matthew Olsson + * Copyright (c) 2022-2023, Linus Groh * Copyright (c) 2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #include +#include +#include +#include #include #include @@ -26,6 +31,66 @@ Iterator::Iterator(Object& prototype) { } +// 7.4.2 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod +ThrowCompletionOr get_iterator_from_method(VM& vm, Value object, NonnullGCPtr method) +{ + // 1. Let iterator be ? Call(method, obj). + auto iterator = TRY(call(vm, *method, object)); + + // 2. If iterator is not an Object, throw a TypeError exception. + if (!iterator.is_object()) + return vm.throw_completion(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects())); + + // 3. Let nextMethod be ? Get(iterator, "next"). + auto next_method = TRY(iterator.get(vm, vm.names.next)); + + // 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }. + auto iterator_record = IteratorRecord { .iterator = &iterator.as_object(), .next_method = next_method, .done = false }; + + // 5. Return iteratorRecord. + return iterator_record; +} + +// 7.4.3 GetIterator ( obj, kind ), https://tc39.es/ecma262/#sec-getiterator +ThrowCompletionOr get_iterator(VM& vm, Value object, IteratorHint kind) +{ + JS::GCPtr method; + + // 1. If kind is async, then + if (kind == IteratorHint::Async) { + // a. Let method be ? GetMethod(obj, @@asyncIterator). + method = TRY(object.get_method(vm, vm.well_known_symbol_async_iterator())); + + // b. If method is undefined, then + if (!method) { + // i. Let syncMethod be ? GetMethod(obj, @@iterator). + auto sync_method = TRY(object.get_method(vm, vm.well_known_symbol_iterator())); + + // ii. If syncMethod is undefined, throw a TypeError exception. + if (!sync_method) + return vm.throw_completion(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects())); + + // iii. Let syncIteratorRecord be ? GetIteratorFromMethod(obj, syncMethod). + auto sync_iterator_record = TRY(get_iterator_from_method(vm, object, *sync_method)); + + // iv. Return CreateAsyncFromSyncIterator(syncIteratorRecord). + return create_async_from_sync_iterator(vm, sync_iterator_record); + } + } + // 2. Else, + else { + // a. Let method be ? GetMethod(obj, @@iterator). + method = TRY(object.get_method(vm, vm.well_known_symbol_iterator())); + } + + // 3. If method is undefined, throw a TypeError exception. + if (!method) + return vm.throw_completion(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects())); + + // 4. Return ? GetIteratorFromMethod(obj, method). + return TRY(get_iterator_from_method(vm, object, *method)); +} + // 2.1.1 GetIteratorDirect ( obj ), https://tc39.es/proposal-iterator-helpers/#sec-getiteratorflattenable ThrowCompletionOr get_iterator_direct(VM& vm, Object& object) { @@ -73,4 +138,183 @@ ThrowCompletionOr get_iterator_flattenable(VM& vm, Value object, return TRY(get_iterator_direct(vm, iterator.as_object())); } +// 7.4.4 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext +ThrowCompletionOr> iterator_next(VM& vm, IteratorRecord const& iterator_record, Optional value) +{ + Value result; + + // 1. If value is not present, then + if (!value.has_value()) { + // a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). + result = TRY(call(vm, iterator_record.next_method, iterator_record.iterator)); + } else { + // a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « value »). + result = TRY(call(vm, iterator_record.next_method, iterator_record.iterator, *value)); + } + + // 3. If Type(result) is not Object, throw a TypeError exception. + if (!result.is_object()) + return vm.throw_completion(ErrorType::IterableNextBadReturn); + + // 4. Return result. + return result.as_object(); +} + +// 7.4.5 IteratorComplete ( iterResult ), https://tc39.es/ecma262/#sec-iteratorcomplete +ThrowCompletionOr iterator_complete(VM& vm, Object& iterator_result) +{ + // 1. Return ToBoolean(? Get(iterResult, "done")). + return TRY(iterator_result.get(vm.names.done)).to_boolean(); +} + +// 7.4.6 IteratorValue ( iterResult ), https://tc39.es/ecma262/#sec-iteratorvalue +ThrowCompletionOr iterator_value(VM& vm, Object& iterator_result) +{ + // 1. Return ? Get(iterResult, "value"). + return TRY(iterator_result.get(vm.names.value)); +} + +// 7.4.7 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep +ThrowCompletionOr> iterator_step(VM& vm, IteratorRecord const& iterator_record) +{ + // 1. Let result be ? IteratorNext(iteratorRecord). + auto result = TRY(iterator_next(vm, iterator_record)); + + // 2. Let done be ? IteratorComplete(result). + auto done = TRY(iterator_complete(vm, result)); + + // 3. If done is true, return false. + if (done) + return nullptr; + + // 4. Return result. + return result; +} + +// 7.4.8 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose +// 7.4.10 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose +// NOTE: These only differ in that async awaits the inner value after the call. +static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_record, Completion completion, IteratorHint iterator_hint) +{ + // 1. Assert: Type(iteratorRecord.[[Iterator]]) is Object. + + // 2. Let iterator be iteratorRecord.[[Iterator]]. + auto iterator = iterator_record.iterator; + + // 3. Let innerResult be Completion(GetMethod(iterator, "return")). + auto inner_result = ThrowCompletionOr { js_undefined() }; + auto get_method_result = Value(iterator).get_method(vm, vm.names.return_); + if (get_method_result.is_error()) + inner_result = get_method_result.release_error(); + + // 4. If innerResult.[[Type]] is normal, then + if (!inner_result.is_error()) { + // a. Let return be innerResult.[[Value]]. + auto return_method = get_method_result.value(); + + // b. If return is undefined, return ? completion. + if (!return_method) + return completion; + + // c. Set innerResult to Completion(Call(return, iterator)). + inner_result = call(vm, return_method, iterator); + + // Note: If this is AsyncIteratorClose perform one extra step. + if (iterator_hint == IteratorHint::Async && !inner_result.is_error()) { + // d. If innerResult.[[Type]] is normal, set innerResult to Completion(Await(innerResult.[[Value]])). + inner_result = await(vm, inner_result.value()); + } + } + + // 5. If completion.[[Type]] is throw, return ? completion. + if (completion.is_error()) + return completion; + + // 6. If innerResult.[[Type]] is throw, return ? innerResult. + if (inner_result.is_throw_completion()) + return inner_result; + + // 7. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. + if (!inner_result.value().is_object()) + return vm.throw_completion(ErrorType::IterableReturnBadReturn); + + // 8. Return ? completion. + return completion; +} + +// 7.4.8 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose +Completion iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion) +{ + return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Sync); +} + +// 7.4.10 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose +Completion async_iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion) +{ + return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Async); +} + +// 7.4.11 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject +NonnullGCPtr create_iterator_result_object(VM& vm, Value value, bool done) +{ + auto& realm = *vm.current_realm(); + + // 1. Let obj be OrdinaryObjectCreate(%Object.prototype%). + auto object = Object::create(realm, realm.intrinsics().object_prototype()); + + // 2. Perform ! CreateDataPropertyOrThrow(obj, "value", value). + MUST(object->create_data_property_or_throw(vm.names.value, value)); + + // 3. Perform ! CreateDataPropertyOrThrow(obj, "done", done). + MUST(object->create_data_property_or_throw(vm.names.done, Value(done))); + + // 4. Return obj. + return object; +} + +// 7.4.13 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist +ThrowCompletionOr> iterator_to_list(VM& vm, IteratorRecord const& iterator_record) +{ + // 1. Let values be a new empty List. + MarkedVector values(vm.heap()); + + // 2. Let next be true. + GCPtr next; + + // 3. Repeat, while next is not false, + do { + // a. Set next to ? IteratorStep(iteratorRecord). + next = TRY(iterator_step(vm, iterator_record)); + + // b. If next is not false, then + if (next) { + // i. Let nextValue be ? IteratorValue(next). + auto next_value = TRY(iterator_value(vm, *next)); + + // ii. Append nextValue to values. + TRY_OR_THROW_OOM(vm, values.try_append(next_value)); + } + } while (next); + + // 4. Return values. + return values; +} + +// Non-standard +Completion get_iterator_values(VM& vm, Value iterable, IteratorValueCallback callback) +{ + auto iterator_record = TRY(get_iterator(vm, iterable, IteratorHint::Sync)); + + while (true) { + auto next_object = TRY(iterator_step(vm, iterator_record)); + if (!next_object) + return {}; + + auto next_value = TRY(iterator_value(vm, *next_object)); + + if (auto completion = callback(next_value); completion.has_value()) + return iterator_close(vm, iterator_record, completion.release_value()); + } +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Iterator.h b/Userland/Libraries/LibJS/Runtime/Iterator.h index 27ca5f3117..f826ca3876 100644 --- a/Userland/Libraries/LibJS/Runtime/Iterator.h +++ b/Userland/Libraries/LibJS/Runtime/Iterator.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2022, Linus Groh + * Copyright (c) 2020, Matthew Olsson + * Copyright (c) 2022-2023, Linus Groh * Copyright (c) 2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause @@ -7,6 +8,8 @@ #pragma once +#include +#include #include #include #include @@ -35,12 +38,30 @@ private: IteratorRecord m_iterated; // [[Iterated]] }; +enum class IteratorHint { + Sync, + Async, +}; + enum class StringHandling { IterateStrings, RejectStrings, }; +ThrowCompletionOr get_iterator_from_method(VM&, Value, NonnullGCPtr); +ThrowCompletionOr get_iterator(VM&, Value, IteratorHint); ThrowCompletionOr get_iterator_direct(VM&, Object&); ThrowCompletionOr get_iterator_flattenable(VM&, Value, StringHandling); +ThrowCompletionOr> iterator_next(VM&, IteratorRecord const&, Optional = {}); +ThrowCompletionOr> iterator_step(VM&, IteratorRecord const&); +ThrowCompletionOr iterator_complete(VM&, Object& iterator_result); +ThrowCompletionOr iterator_value(VM&, Object& iterator_result); +Completion iterator_close(VM&, IteratorRecord const&, Completion); +Completion async_iterator_close(VM&, IteratorRecord const&, Completion); +NonnullGCPtr create_iterator_result_object(VM&, Value, bool done); +ThrowCompletionOr> iterator_to_list(VM&, IteratorRecord const&); + +using IteratorValueCallback = Function(Value)>; +Completion get_iterator_values(VM&, Value iterable, IteratorValueCallback callback); } diff --git a/Userland/Libraries/LibJS/Runtime/IteratorHelper.cpp b/Userland/Libraries/LibJS/Runtime/IteratorHelper.cpp index 04cab652e3..011e1439b8 100644 --- a/Userland/Libraries/LibJS/Runtime/IteratorHelper.cpp +++ b/Userland/Libraries/LibJS/Runtime/IteratorHelper.cpp @@ -5,8 +5,8 @@ */ #include +#include #include -#include #include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp b/Userland/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp index cd406e7510..f3f7128b73 100644 --- a/Userland/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/IteratorHelperPrototype.cpp @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include -#include #include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp b/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp deleted file mode 100644 index b71171f38e..0000000000 --- a/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2020, Matthew Olsson - * Copyright (c) 2022-2023, Linus Groh - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -namespace JS { - -// 7.4.2 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod -ThrowCompletionOr get_iterator_from_method(VM& vm, Value object, NonnullGCPtr method) -{ - // 1. Let iterator be ? Call(method, obj). - auto iterator = TRY(call(vm, *method, object)); - - // 2. If iterator is not an Object, throw a TypeError exception. - if (!iterator.is_object()) - return vm.throw_completion(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects())); - - // 3. Let nextMethod be ? Get(iterator, "next"). - auto next_method = TRY(iterator.get(vm, vm.names.next)); - - // 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }. - auto iterator_record = IteratorRecord { .iterator = &iterator.as_object(), .next_method = next_method, .done = false }; - - // 5. Return iteratorRecord. - return iterator_record; -} - -// 7.4.3 GetIterator ( obj, kind ), https://tc39.es/ecma262/#sec-getiterator -ThrowCompletionOr get_iterator(VM& vm, Value object, IteratorHint kind) -{ - JS::GCPtr method; - - // 1. If kind is async, then - if (kind == IteratorHint::Async) { - // a. Let method be ? GetMethod(obj, @@asyncIterator). - method = TRY(object.get_method(vm, vm.well_known_symbol_async_iterator())); - - // b. If method is undefined, then - if (!method) { - // i. Let syncMethod be ? GetMethod(obj, @@iterator). - auto sync_method = TRY(object.get_method(vm, vm.well_known_symbol_iterator())); - - // ii. If syncMethod is undefined, throw a TypeError exception. - if (!sync_method) - return vm.throw_completion(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects())); - - // iii. Let syncIteratorRecord be ? GetIteratorFromMethod(obj, syncMethod). - auto sync_iterator_record = TRY(get_iterator_from_method(vm, object, *sync_method)); - - // iv. Return CreateAsyncFromSyncIterator(syncIteratorRecord). - return create_async_from_sync_iterator(vm, sync_iterator_record); - } - } - // 2. Else, - else { - // a. Let method be ? GetMethod(obj, @@iterator). - method = TRY(object.get_method(vm, vm.well_known_symbol_iterator())); - } - - // 3. If method is undefined, throw a TypeError exception. - if (!method) - return vm.throw_completion(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects())); - - // 4. Return ? GetIteratorFromMethod(obj, method). - return TRY(get_iterator_from_method(vm, object, *method)); -} - -// 7.4.4 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext -ThrowCompletionOr> iterator_next(VM& vm, IteratorRecord const& iterator_record, Optional value) -{ - Value result; - - // 1. If value is not present, then - if (!value.has_value()) { - // a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). - result = TRY(call(vm, iterator_record.next_method, iterator_record.iterator)); - } else { - // a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « value »). - result = TRY(call(vm, iterator_record.next_method, iterator_record.iterator, *value)); - } - - // 3. If Type(result) is not Object, throw a TypeError exception. - if (!result.is_object()) - return vm.throw_completion(ErrorType::IterableNextBadReturn); - - // 4. Return result. - return result.as_object(); -} - -// 7.4.5 IteratorComplete ( iterResult ), https://tc39.es/ecma262/#sec-iteratorcomplete -ThrowCompletionOr iterator_complete(VM& vm, Object& iterator_result) -{ - // 1. Return ToBoolean(? Get(iterResult, "done")). - return TRY(iterator_result.get(vm.names.done)).to_boolean(); -} - -// 7.4.6 IteratorValue ( iterResult ), https://tc39.es/ecma262/#sec-iteratorvalue -ThrowCompletionOr iterator_value(VM& vm, Object& iterator_result) -{ - // 1. Return ? Get(iterResult, "value"). - return TRY(iterator_result.get(vm.names.value)); -} - -// 7.4.7 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep -ThrowCompletionOr> iterator_step(VM& vm, IteratorRecord const& iterator_record) -{ - // 1. Let result be ? IteratorNext(iteratorRecord). - auto result = TRY(iterator_next(vm, iterator_record)); - - // 2. Let done be ? IteratorComplete(result). - auto done = TRY(iterator_complete(vm, result)); - - // 3. If done is true, return false. - if (done) - return nullptr; - - // 4. Return result. - return result; -} - -// 7.4.8 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose -// 7.4.10 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose -// NOTE: These only differ in that async awaits the inner value after the call. -static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_record, Completion completion, IteratorHint iterator_hint) -{ - // 1. Assert: Type(iteratorRecord.[[Iterator]]) is Object. - - // 2. Let iterator be iteratorRecord.[[Iterator]]. - auto iterator = iterator_record.iterator; - - // 3. Let innerResult be Completion(GetMethod(iterator, "return")). - auto inner_result = ThrowCompletionOr { js_undefined() }; - auto get_method_result = Value(iterator).get_method(vm, vm.names.return_); - if (get_method_result.is_error()) - inner_result = get_method_result.release_error(); - - // 4. If innerResult.[[Type]] is normal, then - if (!inner_result.is_error()) { - // a. Let return be innerResult.[[Value]]. - auto return_method = get_method_result.value(); - - // b. If return is undefined, return ? completion. - if (!return_method) - return completion; - - // c. Set innerResult to Completion(Call(return, iterator)). - inner_result = call(vm, return_method, iterator); - - // Note: If this is AsyncIteratorClose perform one extra step. - if (iterator_hint == IteratorHint::Async && !inner_result.is_error()) { - // d. If innerResult.[[Type]] is normal, set innerResult to Completion(Await(innerResult.[[Value]])). - inner_result = await(vm, inner_result.value()); - } - } - - // 5. If completion.[[Type]] is throw, return ? completion. - if (completion.is_error()) - return completion; - - // 6. If innerResult.[[Type]] is throw, return ? innerResult. - if (inner_result.is_throw_completion()) - return inner_result; - - // 7. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. - if (!inner_result.value().is_object()) - return vm.throw_completion(ErrorType::IterableReturnBadReturn); - - // 8. Return ? completion. - return completion; -} - -// 7.4.8 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose -Completion iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion) -{ - return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Sync); -} - -// 7.4.10 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose -Completion async_iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion) -{ - return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Async); -} - -// 7.4.11 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject -NonnullGCPtr create_iterator_result_object(VM& vm, Value value, bool done) -{ - auto& realm = *vm.current_realm(); - - // 1. Let obj be OrdinaryObjectCreate(%Object.prototype%). - auto object = Object::create(realm, realm.intrinsics().object_prototype()); - - // 2. Perform ! CreateDataPropertyOrThrow(obj, "value", value). - MUST(object->create_data_property_or_throw(vm.names.value, value)); - - // 3. Perform ! CreateDataPropertyOrThrow(obj, "done", done). - MUST(object->create_data_property_or_throw(vm.names.done, Value(done))); - - // 4. Return obj. - return object; -} - -// 7.4.13 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist -ThrowCompletionOr> iterator_to_list(VM& vm, IteratorRecord const& iterator_record) -{ - // 1. Let values be a new empty List. - MarkedVector values(vm.heap()); - - // 2. Let next be true. - GCPtr next; - - // 3. Repeat, while next is not false, - do { - // a. Set next to ? IteratorStep(iteratorRecord). - next = TRY(iterator_step(vm, iterator_record)); - - // b. If next is not false, then - if (next) { - // i. Let nextValue be ? IteratorValue(next). - auto next_value = TRY(iterator_value(vm, *next)); - - // ii. Append nextValue to values. - TRY_OR_THROW_OOM(vm, values.try_append(next_value)); - } - } while (next); - - // 4. Return values. - return values; -} - -// Non-standard -Completion get_iterator_values(VM& vm, Value iterable, IteratorValueCallback callback) -{ - auto iterator_record = TRY(get_iterator(vm, iterable, IteratorHint::Sync)); - - while (true) { - auto next_object = TRY(iterator_step(vm, iterator_record)); - if (!next_object) - return {}; - - auto next_value = TRY(iterator_value(vm, *next_object)); - - if (auto completion = callback(next_value); completion.has_value()) - return iterator_close(vm, iterator_record, completion.release_value()); - } -} - -} diff --git a/Userland/Libraries/LibJS/Runtime/IteratorOperations.h b/Userland/Libraries/LibJS/Runtime/IteratorOperations.h deleted file mode 100644 index 6b6a6b2eb3..0000000000 --- a/Userland/Libraries/LibJS/Runtime/IteratorOperations.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020, Matthew Olsson - * Copyright (c) 2022-2023, Linus Groh - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace JS { - -// 7.4 Operations on Iterator Objects, https://tc39.es/ecma262/#sec-operations-on-iterator-objects - -enum class IteratorHint { - Sync, - Async, -}; - -ThrowCompletionOr get_iterator_from_method(VM&, Value, NonnullGCPtr); -ThrowCompletionOr get_iterator(VM&, Value, IteratorHint); -ThrowCompletionOr> iterator_next(VM&, IteratorRecord const&, Optional = {}); -ThrowCompletionOr> iterator_step(VM&, IteratorRecord const&); -ThrowCompletionOr iterator_complete(VM&, Object& iterator_result); -ThrowCompletionOr iterator_value(VM&, Object& iterator_result); -Completion iterator_close(VM&, IteratorRecord const&, Completion); -Completion async_iterator_close(VM&, IteratorRecord const&, Completion); -NonnullGCPtr create_iterator_result_object(VM&, Value, bool done); -ThrowCompletionOr> iterator_to_list(VM&, IteratorRecord const&); - -using IteratorValueCallback = Function(Value)>; -Completion get_iterator_values(VM&, Value iterable, IteratorValueCallback callback); - -} diff --git a/Userland/Libraries/LibJS/Runtime/IteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/IteratorPrototype.cpp index dda30cca57..2600d94fd0 100644 --- a/Userland/Libraries/LibJS/Runtime/IteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/IteratorPrototype.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include #include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/MapConstructor.cpp b/Userland/Libraries/LibJS/Runtime/MapConstructor.cpp index d9681d26ec..1a88ad81df 100644 --- a/Userland/Libraries/LibJS/Runtime/MapConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/MapConstructor.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/MapIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/MapIteratorPrototype.cpp index f6ec485482..258385303e 100644 --- a/Userland/Libraries/LibJS/Runtime/MapIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/MapIteratorPrototype.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp index f6ca78dfa2..b741c62f11 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp b/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp index 864deccaad..6cc318e835 100644 --- a/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp index d697751204..36d0a78b1b 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpStringIteratorPrototype.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/SetConstructor.cpp b/Userland/Libraries/LibJS/Runtime/SetConstructor.cpp index 21354b22a5..684aa70804 100644 --- a/Userland/Libraries/LibJS/Runtime/SetConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/SetConstructor.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/SetIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/SetIteratorPrototype.cpp index e40cfc74e9..321d9482a5 100644 --- a/Userland/Libraries/LibJS/Runtime/SetIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/SetIteratorPrototype.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace JS { diff --git a/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp b/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp index d17758b751..cfa13dc335 100644 --- a/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/SetPrototype.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp index 28a7691e63..e9f2d3c43a 100644 --- a/Userland/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringIteratorPrototype.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/SuppressedErrorConstructor.cpp b/Userland/Libraries/LibJS/Runtime/SuppressedErrorConstructor.cpp index ac199d7fc6..184cc86c24 100644 --- a/Userland/Libraries/LibJS/Runtime/SuppressedErrorConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/SuppressedErrorConstructor.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index f15c4f83af..977b71b738 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp index 5edcf64f7b..02df08c175 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/CalendarPrototype.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp index bc3ace1f53..7f8c3ef1a6 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/TimeZone.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.cpp b/Userland/Libraries/LibJS/Runtime/TypedArray.cpp index e810603c80..6ed2025ce9 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayConstructor.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayConstructor.cpp index 7fd7da49f1..bfd178d463 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayConstructor.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 7df48f5100..8aadf050a6 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp b/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp index 85516bb3cb..9512ca8b31 100644 --- a/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/WeakMapConstructor.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/WeakSetConstructor.cpp b/Userland/Libraries/LibJS/Runtime/WeakSetConstructor.cpp index 07ecf796f5..d897db4dc2 100644 --- a/Userland/Libraries/LibJS/Runtime/WeakSetConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/WeakSetConstructor.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/Userland/Libraries/LibJS/Runtime/WrapForValidIteratorPrototype.cpp b/Userland/Libraries/LibJS/Runtime/WrapForValidIteratorPrototype.cpp index 167c164695..28beeae0e5 100644 --- a/Userland/Libraries/LibJS/Runtime/WrapForValidIteratorPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/WrapForValidIteratorPrototype.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include namespace JS { diff --git a/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp index 145137c8b0..0de77519ec 100644 --- a/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp +++ b/Userland/Libraries/LibWeb/Fetch/HeadersIterator.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp b/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp index 2b2bccf418..193b9936b7 100644 --- a/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp +++ b/Userland/Libraries/LibWeb/HTML/CustomElements/CustomElementRegistry.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp index ec719813cf..515b0d10be 100644 --- a/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp +++ b/Userland/Libraries/LibWeb/Streams/ReadableStreamDefaultReader.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/URL/URLSearchParamsIterator.cpp b/Userland/Libraries/LibWeb/URL/URLSearchParamsIterator.cpp index 0e83251970..fcb4c7af9c 100644 --- a/Userland/Libraries/LibWeb/URL/URLSearchParamsIterator.cpp +++ b/Userland/Libraries/LibWeb/URL/URLSearchParamsIterator.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index 1ce0edb9f5..8654e3bc51 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp b/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp index 4cea9cdcbd..95ae5af304 100644 --- a/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp +++ b/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include