mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:02:46 +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
	
	 Timothy Flynn
						Timothy Flynn