Bladeren bron

LibJS: Use IteratorStepValue in ECMA-262

This is an editorial change in the ECMA-262 spec. See:
https://github.com/tc39/ecma262/commit/12d3687

Note they have not yet updated all potential consumers to use this new
AO.
Timothy Flynn 1 jaar geleden
bovenliggende
commit
18847fca50

+ 3 - 8
Userland/Libraries/LibJS/Bytecode/CommonImplementations.h

@@ -681,16 +681,11 @@ inline ThrowCompletionOr<NonnullGCPtr<Array>> iterator_to_array(VM& vm, Value it
     size_t index = 0;
 
     while (true) {
-        auto iterator_result = TRY(iterator_next(vm, iterator_record));
-
-        auto complete = TRY(iterator_complete(vm, iterator_result));
-
-        if (complete)
+        auto value = TRY(iterator_step_value(vm, iterator_record));
+        if (!value.has_value())
             return array;
 
-        auto value = TRY(iterator_value(vm, iterator_result));
-
-        MUST(array->create_data_property_or_throw(index, value));
+        MUST(array->create_data_property_or_throw(index, value.release_value()));
         index++;
     }
 }

+ 6 - 6
Userland/Libraries/LibJS/Runtime/AbstractOperations.h

@@ -241,17 +241,17 @@ ThrowCompletionOr<GroupsType> group_by(VM& vm, Value items, Value callback_funct
             return iterator_close(vm, iterator_record, move(error));
         }
 
-        // b. Let next be ? IteratorStep(iteratorRecord).
-        auto next = TRY(iterator_step(vm, iterator_record));
+        // b. Let next be ? IteratorStepValue(iteratorRecord).
+        auto next = TRY(iterator_step_value(vm, iterator_record));
 
-        // c. If next is false, then
-        if (!next) {
+        // c. If next is DONE, then
+        if (!next.has_value()) {
             // i. Return groups.
             return ThrowCompletionOr<GroupsType> { move(groups) };
         }
 
-        // d. Let value be ? IteratorValue(next).
-        auto value = TRY(iterator_value(vm, *next));
+        // d. Let value be next.
+        auto value = next.release_value();
 
         // e. Let key be Completion(Call(callbackfn, undefined, « value, 𝔽(k) »)).
         auto key = call(vm, callback_function, js_undefined(), value, Value(k));

+ 11 - 14
Userland/Libraries/LibJS/Runtime/ArrayConstructor.cpp

@@ -197,11 +197,11 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
             // ii. Let Pk be ! ToString(𝔽(k)).
             auto property_key = PropertyKey { k };
 
-            // iii. Let next be ? IteratorStep(iteratorRecord).
-            auto next = TRY(iterator_step(vm, iterator));
+            // iii. Let next be ? IteratorStepValue(iteratorRecord).
+            auto next = TRY(iterator_step_value(vm, iterator));
 
-            // iv. If next is false, then
-            if (!next) {
+            // iv. If next is DONE, then
+            if (!next.has_value()) {
                 // 1. Perform ? Set(A, "length", 𝔽(k), true).
                 TRY(array->set(vm.names.length, Value(k), Object::ShouldThrowExceptions::Yes));
 
@@ -209,34 +209,31 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
                 return array;
             }
 
-            // v. Let nextValue be ? IteratorValue(next).
-            auto next_value = TRY(iterator_value(vm, *next));
-
             Value mapped_value;
 
-            // vi. If mapping is true, then
+            // v. If mapping is true, then
             if (mapfn) {
                 // 1. Let mappedValue be Completion(Call(mapfn, thisArg, « nextValue, 𝔽(k) »)).
-                auto mapped_value_or_error = JS::call(vm, *mapfn, this_arg, next_value, Value(k));
+                auto mapped_value_or_error = JS::call(vm, *mapfn, this_arg, next.release_value(), Value(k));
 
                 // 2. IfAbruptCloseIterator(mappedValue, iteratorRecord).
                 if (mapped_value_or_error.is_error())
                     return *TRY(iterator_close(vm, iterator, mapped_value_or_error.release_error()));
                 mapped_value = mapped_value_or_error.release_value();
             }
-            // vii. Else, let mappedValue be nextValue.
+            // vi. Else, let mappedValue be nextValue.
             else {
-                mapped_value = next_value;
+                mapped_value = next.release_value();
             }
 
-            // viii. Let defineStatus be Completion(CreateDataPropertyOrThrow(A, Pk, mappedValue)).
+            // vii. Let defineStatus be Completion(CreateDataPropertyOrThrow(A, Pk, mappedValue)).
             auto result_or_error = array->create_data_property_or_throw(property_key, mapped_value);
 
-            // IfAbruptCloseIterator(defineStatus, iteratorRecord).
+            // viii. IfAbruptCloseIterator(defineStatus, iteratorRecord).
             if (result_or_error.is_error())
                 return *TRY(iterator_close(vm, iterator, result_or_error.release_error()));
 
-            // x. Set k to k + 1.
+            // ix. Set k to k + 1.
         }
     }
 

+ 15 - 23
Userland/Libraries/LibJS/Runtime/Iterator.cpp

@@ -332,31 +332,25 @@ NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool don
 }
 
 // 7.4.14 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist
-ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord const& iterator_record)
+ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord& iterator_record)
 {
     // 1. Let values be a new empty List.
     MarkedVector<Value> values(vm.heap());
 
-    // 2. Let next be true.
-    GCPtr<Object> 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));
+    // 2. Repeat,
+    while (true) {
+        // a. Let next be ? IteratorStepValue(iteratorRecord).
+        auto next = TRY(iterator_step_value(vm, iterator_record));
 
-            // ii. Append nextValue to values.
-            TRY_OR_THROW_OOM(vm, values.try_append(next_value));
+        // b. If next is DONE, then
+        if (!next.has_value()) {
+            // i. Return values.
+            return values;
         }
-    } while (next);
 
-    // 4. Return values.
-    return values;
+        // c. Append next to values.
+        values.append(next.release_value());
+    }
 }
 
 // Non-standard
@@ -365,13 +359,11 @@ Completion get_iterator_values(VM& vm, Value iterable, IteratorValueCallback cal
     auto iterator_record = TRY(get_iterator(vm, iterable, IteratorHint::Sync));
 
     while (true) {
-        auto next_object = TRY(iterator_step(vm, iterator_record));
-        if (!next_object)
+        auto next = TRY(iterator_step_value(vm, iterator_record));
+        if (!next.has_value())
             return {};
 
-        auto next_value = TRY(iterator_value(vm, *next_object));
-
-        if (auto completion = callback(next_value); completion.has_value())
+        if (auto completion = callback(next.release_value()); completion.has_value())
             return iterator_close(vm, iterator_record, completion.release_value());
     }
 }

+ 1 - 1
Userland/Libraries/LibJS/Runtime/Iterator.h

@@ -82,7 +82,7 @@ ThrowCompletionOr<Value> iterator_value(VM&, Object& iterator_result);
 Completion iterator_close(VM&, IteratorRecord const&, Completion);
 Completion async_iterator_close(VM&, IteratorRecord const&, Completion);
 NonnullGCPtr<Object> create_iterator_result_object(VM&, Value, bool done);
-ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM&, IteratorRecord const&);
+ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM&, IteratorRecord&);
 
 using IteratorValueCallback = Function<Optional<Completion>(Value)>;
 Completion get_iterator_values(VM&, Value iterable, IteratorValueCallback callback);

+ 15 - 37
Userland/Libraries/LibJS/Runtime/PromiseConstructor.cpp

@@ -56,59 +56,37 @@ static ThrowCompletionOr<Value> perform_promise_common(VM& vm, IteratorRecord& i
 
     // 4. Repeat,
     while (true) {
-        // a. Let next be Completion(IteratorStep(iteratorRecord)).
-        auto next_or_error = iterator_step(vm, iterator_record);
-
-        // b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
-        // c. ReturnIfAbrupt(next).
-        if (next_or_error.is_throw_completion()) {
-            iterator_record.done = true;
-            return next_or_error.release_error();
-        }
-        auto next = next_or_error.release_value();
-
-        // d. If next is false, then
-        if (!next) {
-            // i. Set iteratorRecord.[[Done]] to true.
-            iterator_record.done = true;
+        // a. Let next be ? IteratorStepValue(iteratorRecord).
+        auto next = TRY(iterator_step_value(vm, iterator_record));
 
-            // ii. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
-            // iii. If remainingElementsCount.[[Value]] is 0, then
+        // b. If next is DONE, then
+        if (!next.has_value()) {
+            // i. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] - 1.
+            // ii. If remainingElementsCount.[[Value]] = 0, then
             if (--remaining_elements_count->value == 0) {
-                // 1-2/3. are handled in `end_of_list`
+                // 1-2. are handled in `end_of_list`
                 return TRY(end_of_list(*values));
             }
 
-            // iv. Return resultCapability.[[Promise]].
+            // iii. Return resultCapability.[[Promise]].
             return result_capability.promise();
         }
 
-        // e. Let nextValue be Completion(IteratorValue(next)).
-        auto next_value_or_error = iterator_value(vm, *next);
-
-        // f. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
-        // g. ReturnIfAbrupt(nextValue).
-        if (next_value_or_error.is_throw_completion()) {
-            iterator_record.done = true;
-            return next_value_or_error.release_error();
-        }
-        auto next_value = next_value_or_error.release_value();
-
-        // h. Append undefined to values.
+        // c. Append undefined to values.
         values->values().append(js_undefined());
 
-        // i. Let nextPromise be ? Call(promiseResolve, constructor, « nextValue »).
-        auto next_promise = TRY(call(vm, promise_resolve.as_function(), constructor, next_value));
+        // d. Let nextPromise be ? Call(promiseResolve, constructor, « next »).
+        auto next_promise = TRY(call(vm, promise_resolve.as_function(), constructor, next.release_value()));
 
-        // j-q. are handled in `invoke_element_function`
+        // e-l. are handled in `invoke_element_function`
 
-        // r. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1.
+        // m. Set remainingElementsCount.[[Value]] to remainingElementsCount.[[Value]] + 1.
         ++remaining_elements_count->value;
 
-        // s. Perform ? Invoke(nextPromise, "then", « ... »).
+        // n. Perform ? Invoke(nextPromise, "then", « ... »).
         TRY(invoke_element_function(*values, *remaining_elements_count, next_promise, index));
 
-        // t. Set index to index + 1.
+        // o. Set index to index + 1.
         ++index;
     }
 }

+ 6 - 6
Userland/Libraries/LibJS/Runtime/SetConstructor.cpp

@@ -66,12 +66,12 @@ ThrowCompletionOr<NonnullGCPtr<Object>> SetConstructor::construct(FunctionObject
 
     // 7. Let iteratorRecord be ? GetIterator(iterable, sync).
     // 8. Repeat,
-    //     a. Let next be ? IteratorStep(iteratorRecord).
-    //     c. Let nextValue be ? IteratorValue(next).
-    (void)TRY(get_iterator_values(vm, iterable, [&](Value next_value) -> Optional<Completion> {
-        // d. Let status be Completion(Call(adder, set, « nextValue »)).
-        // e. IfAbruptCloseIterator(status, iteratorRecord).
-        TRY(JS::call(vm, adder.as_function(), set, next_value));
+    (void)TRY(get_iterator_values(vm, iterable, [&](Value next) -> Optional<Completion> {
+        // a. Let next be ? IteratorStepValue(iteratorRecord).
+        // b. If next is DONE, return set.
+        // c. Let status be Completion(Call(adder, set, « nextValue »)).
+        // d. IfAbruptCloseIterator(status, iteratorRecord).
+        TRY(JS::call(vm, adder.as_function(), set, next));
         return {};
     }));
 

+ 17 - 55
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -420,46 +420,27 @@ ThrowCompletionOr<void> VM::iterator_binding_initialization(BindingPattern const
             // 3. Let n be 0.
             // 4. Repeat,
             while (true) {
-                ThrowCompletionOr<GCPtr<Object>> next { nullptr };
+                // a. Let next be DONE.
+                Optional<Value> next;
 
-                // a. If iteratorRecord.[[Done]] is false, then
+                // b. If iteratorRecord.[[Done]] is false, then
                 if (!iterator_record.done) {
-                    // i. Let next be Completion(IteratorStep(iteratorRecord)).
-                    next = iterator_step(vm, iterator_record);
-
-                    // ii. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
-                    // iii. ReturnIfAbrupt(next).
-                    if (next.is_error()) {
-                        iterator_record.done = true;
-                        return next.release_error();
-                    }
-
-                    // iv. If next is false, set iteratorRecord.[[Done]] to true.
-                    if (!next.value())
-                        iterator_record.done = true;
+                    // i. Set next to ? IteratorStepValue(iteratorRecord).
+                    next = TRY(iterator_step_value(vm, iterator_record));
                 }
 
-                // b. If iteratorRecord.[[Done]] is true, then
-                if (iterator_record.done) {
+                // c. If next is DONE, then
+                if (!next.has_value()) {
                     // NOTE: Step i. and ii. are handled below.
                     break;
                 }
 
-                // c. Let nextValue be Completion(IteratorValue(next)).
-                auto next_value = iterator_value(vm, *next.value());
+                // d. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), next).
+                array->indexed_properties().append(next.release_value());
 
-                // d. If nextValue is an abrupt completion, set iteratorRecord.[[Done]] to true.
-                // e. ReturnIfAbrupt(nextValue).
-                if (next_value.is_error()) {
-                    iterator_record.done = true;
-                    return next_value.release_error();
-                }
-
-                // f. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), nextValue).
-                array->indexed_properties().append(next_value.value());
-
-                // g. Set n to n + 1.
+                // e. Set n to n + 1.
             }
+
             value = array;
         }
         // SingleNameBinding : BindingIdentifier Initializer[opt]
@@ -470,32 +451,13 @@ ThrowCompletionOr<void> VM::iterator_binding_initialization(BindingPattern const
 
             // 2. If iteratorRecord.[[Done]] is false, then
             if (!iterator_record.done) {
-                // a. Let next be Completion(IteratorStep(iteratorRecord)).
-                auto next = iterator_step(vm, iterator_record);
-
-                // b. If next is an abrupt completion, set iteratorRecord.[[Done]] to true.
-                // c. ReturnIfAbrupt(next).
-                if (next.is_error()) {
-                    iterator_record.done = true;
-                    return next.release_error();
-                }
+                // a. Let next be ? IteratorStepValue(iteratorRecord).
+                auto next = TRY(iterator_step_value(vm, iterator_record));
 
-                // d. If next is false, set iteratorRecord.[[Done]] to true.
-                if (!next.value()) {
-                    iterator_record.done = true;
-                }
-                // e. Else,
-                else {
-                    // i. Set v to Completion(IteratorValue(next)).
-                    auto value_or_error = iterator_value(vm, *next.value());
-
-                    // ii. If v is an abrupt completion, set iteratorRecord.[[Done]] to true.
-                    // iii. ReturnIfAbrupt(v).
-                    if (value_or_error.is_throw_completion()) {
-                        iterator_record.done = true;
-                        return value_or_error.release_error();
-                    }
-                    value = value_or_error.release_value();
+                // b. If next is not DONE, then
+                if (next.has_value()) {
+                    // i. Set v to next.
+                    value = next.release_value();
                 }
             }
 

+ 6 - 6
Userland/Libraries/LibJS/Runtime/WeakSetConstructor.cpp

@@ -63,12 +63,12 @@ ThrowCompletionOr<NonnullGCPtr<Object>> WeakSetConstructor::construct(FunctionOb
 
     // 7. Let iteratorRecord be ? GetIterator(iterable, sync).
     // 8. Repeat,
-    //     a. Let next be ? IteratorStep(iteratorRecord).
-    //     c. Let nextValue be ? IteratorValue(next).
-    (void)TRY(get_iterator_values(vm, iterable, [&](Value next_value) -> Optional<Completion> {
-        // d. Let status be Completion(Call(adder, set, « nextValue »)).
-        // e. IfAbruptCloseIterator(status, iteratorRecord).
-        TRY(JS::call(vm, adder.as_function(), set, next_value));
+    (void)TRY(get_iterator_values(vm, iterable, [&](Value next) -> Optional<Completion> {
+        // a. Let next be ? IteratorStepValue(iteratorRecord).
+        // c. If next is DONE, return set.
+        // c. Let status be Completion(Call(adder, set, « nextValue »)).
+        // d. IfAbruptCloseIterator(status, iteratorRecord).
+        TRY(JS::call(vm, adder.as_function(), set, next));
         return {};
     }));