From b3699029e2d91ae3bb2e023e8e83d3afc6c19232 Mon Sep 17 00:00:00 2001 From: davidot Date: Tue, 23 Nov 2021 15:56:12 +0100 Subject: [PATCH] LibJS: Implement the async versions of iterator operations Since AsyncIteratorClose and IteratorClose differ only in that the async version awaits the inner value we just implement them with an enum flag to switch just that behavior. --- .../LibJS/Runtime/IteratorOperations.cpp | 46 +++++++++++++++---- .../LibJS/Runtime/IteratorOperations.h | 1 + 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp b/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp index 543ed6b641..75febaa11a 100644 --- a/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -18,10 +19,17 @@ ThrowCompletionOr get_iterator(GlobalObject& global_object, Value value { auto& vm = global_object.vm(); if (method.is_empty()) { - if (hint == IteratorHint::Async) - TODO(); - - method = TRY(value.get_method(global_object, *vm.well_known_symbol_iterator())); + if (hint == IteratorHint::Async) { + auto* async_method = TRY(value.get_method(global_object, *vm.well_known_symbol_async_iterator())); + if (async_method == nullptr) { + auto* sync_method = TRY(value.get_method(global_object, *vm.well_known_symbol_iterator())); + auto* sync_iterator_record = TRY(get_iterator(global_object, value, IteratorHint::Sync, sync_method)); + return TRY(create_async_from_sync_iterator(global_object, *sync_iterator_record)); + } + method = Value(async_method); + } else { + method = TRY(value.get_method(global_object, *vm.well_known_symbol_iterator())); + } } if (!method.is_function()) @@ -88,7 +96,9 @@ ThrowCompletionOr iterator_step(GlobalObject& global_object, Object& it } // 7.4.6 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose -Completion iterator_close(Object& iterator, Completion completion) +// 7.4.8 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_(Object& iterator, Completion completion, IteratorHint iterator_hint) { auto& vm = iterator.vm(); auto& global_object = iterator.global_object(); @@ -114,10 +124,16 @@ Completion iterator_close(Object& iterator, Completion completion) // c. Set innerResult to Call(return, iterator). auto result_or_error = vm.call(*return_method, &iterator); - if (result_or_error.is_error()) + if (result_or_error.is_error()) { inner_result_or_error = result_or_error.release_error(); - else + } else { inner_result = result_or_error.release_value(); + // Note: If this is AsyncIteratorClose perform one extra step. + if (iterator_hint == IteratorHint::Async) { + // d. If innerResult.[[Type]] is normal, set innerResult to Await(innerResult.[[Value]]). + inner_result = TRY(await(global_object, inner_result)); + } + } } // 5. If completion.[[Type]] is throw, return Completion(completion). @@ -136,7 +152,19 @@ Completion iterator_close(Object& iterator, Completion completion) return completion; } -// 7.4.8 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject +// 7.4.6 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose +Completion iterator_close(Object& iterator, Completion completion) +{ + return iterator_close_(iterator, move(completion), IteratorHint::Sync); +} + +// 7.4.8 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose +Completion async_iterator_close(Object& iterator, Completion completion) +{ + return iterator_close_(iterator, move(completion), IteratorHint::Async); +} + +// 7.4.9 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject Object* create_iterator_result_object(GlobalObject& global_object, Value value, bool done) { auto& vm = global_object.vm(); @@ -146,7 +174,7 @@ Object* create_iterator_result_object(GlobalObject& global_object, Value value, return object; } -// 7.4.10 IterableToList ( items [ , method ] ), https://tc39.es/ecma262/#sec-iterabletolist +// 7.4.11 IterableToList ( items [ , method ] ), https://tc39.es/ecma262/#sec-iterabletolist ThrowCompletionOr iterable_to_list(GlobalObject& global_object, Value iterable, Value method) { auto& vm = global_object.vm(); diff --git a/Userland/Libraries/LibJS/Runtime/IteratorOperations.h b/Userland/Libraries/LibJS/Runtime/IteratorOperations.h index 636e9fef46..af8616c4c1 100644 --- a/Userland/Libraries/LibJS/Runtime/IteratorOperations.h +++ b/Userland/Libraries/LibJS/Runtime/IteratorOperations.h @@ -26,6 +26,7 @@ ThrowCompletionOr iterator_step(GlobalObject&, Object& iterator); ThrowCompletionOr iterator_complete(GlobalObject&, Object& iterator_result); ThrowCompletionOr iterator_value(GlobalObject&, Object& iterator_result); Completion iterator_close(Object& iterator, Completion completion); +Completion async_iterator_close(Object& iterator, Completion completion); Object* create_iterator_result_object(GlobalObject&, Value value, bool done); ThrowCompletionOr iterable_to_list(GlobalObject&, Value iterable, Value method = {});