From 2b96e732dd548409cd1721b724aa96feec5154ad Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Thu, 1 Feb 2024 14:52:07 -0500 Subject: [PATCH] LibJS: Implement the IteratorStepValue AO This is an editorial change in the ECMA-262 spec. See: https://github.com/tc39/ecma262/commit/12d3687 This AO is meant to replace usages of IteratorNext followed by IteratorValue with a single operation. --- Userland/Libraries/LibJS/Runtime/Iterator.cpp | 67 +++++++++++++++++-- Userland/Libraries/LibJS/Runtime/Iterator.h | 1 + 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Iterator.cpp b/Userland/Libraries/LibJS/Runtime/Iterator.cpp index 664efc1bdd..fb029e8c3e 100644 --- a/Userland/Libraries/LibJS/Runtime/Iterator.cpp +++ b/Userland/Libraries/LibJS/Runtime/Iterator.cpp @@ -195,8 +195,63 @@ ThrowCompletionOr> iterator_step(VM& vm, IteratorRecord const& ite 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 +// 7.4.8 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue +ThrowCompletionOr> iterator_step_value(VM& vm, IteratorRecord& iterator_record) +{ + // 1. Let result be Completion(IteratorNext(iteratorRecord)). + auto result = iterator_next(vm, iterator_record); + + // 2. If result is a throw completion, then + if (result.is_throw_completion()) { + // a. Set iteratorRecord.[[Done]] to true. + iterator_record.done = true; + + // b. Return ? result. + return result.release_error(); + } + + // 3. Set result to ! result. + auto result_value = result.release_value(); + + // 4. Let done be Completion(IteratorComplete(result)). + auto done = iterator_complete(vm, result_value); + + // 5. If done is a throw completion, then + if (done.is_throw_completion()) { + // a. Set iteratorRecord.[[Done]] to true. + iterator_record.done = true; + + // b. Return ? done. + return done.release_error(); + } + + // 6. Set done to ! done. + auto done_value = done.release_value(); + + // 7. If done is true, then + if (done_value) { + // a. Set iteratorRecord.[[Done]] to true. + iterator_record.done = true; + + // b. Return DONE. + return OptionalNone {}; + } + + // 8. Let value be Completion(Get(result, "value")). + auto value = result_value->get(vm.names.value); + + // 9. If value is a throw completion, then + if (value.is_throw_completion()) { + // a. Set iteratorRecord.[[Done]] to true. + iterator_record.done = true; + } + + // 10. Return ? value. + return TRY(value); +} + +// 7.4.9 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose +// 7.4.11 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) { @@ -246,19 +301,19 @@ static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_rec return completion; } -// 7.4.8 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose +// 7.4.9 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 +// 7.4.11 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 +// 7.4.12 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(); @@ -276,7 +331,7 @@ NonnullGCPtr create_iterator_result_object(VM& vm, Value value, bool don return object; } -// 7.4.13 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist +// 7.4.14 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. diff --git a/Userland/Libraries/LibJS/Runtime/Iterator.h b/Userland/Libraries/LibJS/Runtime/Iterator.h index 1c4fd4f80e..7d8a56f79a 100644 --- a/Userland/Libraries/LibJS/Runtime/Iterator.h +++ b/Userland/Libraries/LibJS/Runtime/Iterator.h @@ -76,6 +76,7 @@ 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_step_value(VM&, IteratorRecord&); ThrowCompletionOr iterator_complete(VM&, Object& iterator_result); ThrowCompletionOr iterator_value(VM&, Object& iterator_result); Completion iterator_close(VM&, IteratorRecord const&, Completion);