mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 08:34:57 +00:00
LibJS: Use IteratorStepValue in ECMA-262
This is an editorial change in the ECMA-262 spec. See:
12d3687
Note they have not yet updated all potential consumers to use this new
AO.
This commit is contained in:
parent
2b96e732dd
commit
18847fca50
9 changed files with 80 additions and 156 deletions
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
// 2. Repeat,
|
||||
while (true) {
|
||||
// a. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
auto next = TRY(iterator_step_value(vm, iterator_record));
|
||||
|
||||
// 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));
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
// a. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
auto next = TRY(iterator_step_value(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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {};
|
||||
}));
|
||||
|
||||
|
|
|
@ -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);
|
||||
// a. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
auto next = TRY(iterator_step_value(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();
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
}));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue