|
@@ -1,5 +1,6 @@
|
|
|
/*
|
|
|
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
|
|
+ * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
|
|
*
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
*/
|
|
@@ -32,33 +33,26 @@ void IteratorPrototype::initialize(Realm& realm)
|
|
|
|
|
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
|
|
define_native_function(realm, vm.well_known_symbol_iterator(), symbol_iterator, 0, attr);
|
|
|
- define_native_function(realm, vm.names.map, map, 1, attr);
|
|
|
- define_native_function(realm, vm.names.filter, filter, 1, attr);
|
|
|
- define_native_function(realm, vm.names.take, take, 1, attr);
|
|
|
define_native_function(realm, vm.names.drop, drop, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.every, every, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.filter, filter, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.find, find, 1, attr);
|
|
|
define_native_function(realm, vm.names.flatMap, flat_map, 1, attr);
|
|
|
- define_native_function(realm, vm.names.reduce, reduce, 1, attr);
|
|
|
- define_native_function(realm, vm.names.toArray, to_array, 0, attr);
|
|
|
define_native_function(realm, vm.names.forEach, for_each, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.map, map, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.reduce, reduce, 1, attr);
|
|
|
define_native_function(realm, vm.names.some, some, 1, attr);
|
|
|
- define_native_function(realm, vm.names.every, every, 1, attr);
|
|
|
- define_native_function(realm, vm.names.find, find, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.take, take, 1, attr);
|
|
|
+ define_native_function(realm, vm.names.toArray, to_array, 0, attr);
|
|
|
|
|
|
- // 3.1.3.1 Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.constructor
|
|
|
+ // 27.1.4.1 Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-iterator.prototype.constructor
|
|
|
define_native_accessor(realm, vm.names.constructor, constructor_getter, constructor_setter, Attribute::Configurable);
|
|
|
|
|
|
- // 3.1.3.13 Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype-@@tostringtag
|
|
|
+ // 27.1.4.14 Iterator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-iterator.prototype-%symbol.tostringtag%
|
|
|
define_native_accessor(realm, vm.well_known_symbol_to_string_tag(), to_string_tag_getter, to_string_tag_setter, Attribute::Configurable);
|
|
|
}
|
|
|
|
|
|
-// 27.1.2.1 %IteratorPrototype% [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::symbol_iterator)
|
|
|
-{
|
|
|
- // 1. Return the this value.
|
|
|
- return vm.this_value();
|
|
|
-}
|
|
|
-
|
|
|
-// 3.1.3.1.1 get Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-constructor
|
|
|
+// 27.1.4.1.1 get Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-get-iterator.prototype.constructor
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
@@ -67,7 +61,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
|
|
|
return realm.intrinsics().iterator_constructor();
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.1.2 set Iterator.prototype.constructor, https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-constructor
|
|
|
+// 27.1.4.1.2 set Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-set-iterator.prototype.constructor
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
@@ -79,30 +73,54 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
|
|
|
return js_undefined();
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.2 Iterator.prototype.map ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.map
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
|
|
|
+// 27.1.4.2 Iterator.prototype.drop ( limit ), https://tc39.es/ecma262/#sec-iterator.prototype.drop
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
|
|
|
|
- auto mapper = vm.argument(0);
|
|
|
+ auto limit = vm.argument(0);
|
|
|
|
|
|
// 1. Let O be the this value.
|
|
|
// 2. If O is not an Object, throw a TypeError exception.
|
|
|
auto object = TRY(this_object(vm));
|
|
|
|
|
|
- // 3. If IsCallable(mapper) is false, throw a TypeError exception.
|
|
|
- if (!mapper.is_function())
|
|
|
- return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "mapper"sv);
|
|
|
+ // 3. Let numLimit be ? ToNumber(limit).
|
|
|
+ auto numeric_limit = TRY(limit.to_number(vm));
|
|
|
|
|
|
- // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ // 4. If numLimit is NaN, throw a RangeError exception.
|
|
|
+ if (numeric_limit.is_nan())
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
|
|
|
+
|
|
|
+ // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
|
|
|
+ auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
|
|
|
+
|
|
|
+ // 6. If integerLimit < 0, throw a RangeError exception.
|
|
|
+ if (integer_limit < 0)
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
|
|
|
+
|
|
|
+ // 7. Let iterated be ? GetIteratorDirect(O).
|
|
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
|
|
|
- // 5. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
|
|
|
- auto closure = JS::create_heap_function(realm.heap(), [mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
|
+ // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
|
|
|
+ auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
|
auto& iterated = iterator.underlying_iterator();
|
|
|
|
|
|
- // a. Let counter be 0.
|
|
|
- // b. Repeat,
|
|
|
+ // a. Let remaining be integerLimit.
|
|
|
+ // b. Repeat, while remaining > 0,
|
|
|
+ while (iterator.counter() < integer_limit) {
|
|
|
+ // i. If remaining is not +∞, then
|
|
|
+ // 1. Set remaining to remaining - 1.
|
|
|
+ iterator.increment_counter();
|
|
|
+
|
|
|
+ // ii. Let next be ? IteratorStep(iterated).
|
|
|
+ auto next = TRY(iterator_step(vm, iterated));
|
|
|
+
|
|
|
+ // iii. If next is false, return undefined.
|
|
|
+ if (!next)
|
|
|
+ return iterator.result(js_undefined());
|
|
|
+ }
|
|
|
+
|
|
|
+ // c. Repeat,
|
|
|
|
|
|
// i. Let value be ? IteratorStepValue(iterated).
|
|
|
auto value = TRY(iterator_step_value(vm, iterated));
|
|
@@ -111,31 +129,64 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
|
|
|
if (!value.has_value())
|
|
|
return iterator.result(js_undefined());
|
|
|
|
|
|
- // iii. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
|
|
|
- auto mapped = call(vm, *mapper, js_undefined(), *value, Value { iterator.counter() });
|
|
|
+ // iii. Let completion be Completion(Yield(value)).
|
|
|
+ // iv. IfAbruptCloseIterator(completion, iterated).
|
|
|
+ return iterator.result(*value);
|
|
|
+ });
|
|
|
|
|
|
- // iv. IfAbruptCloseIterator(mapped, iterated).
|
|
|
- if (mapped.is_error())
|
|
|
- return iterator.close_result(vm, mapped.release_error());
|
|
|
+ // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
+ // 10. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
+ auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
|
|
|
|
|
- // vii. Set counter to counter + 1.
|
|
|
- // NOTE: We do this step early to ensure it occurs before returning.
|
|
|
- iterator.increment_counter();
|
|
|
+ // 11. Return result.
|
|
|
+ return result;
|
|
|
+}
|
|
|
|
|
|
- // v. Let completion be Completion(Yield(mapped)).
|
|
|
- // vi. IfAbruptCloseIterator(completion, iterated).
|
|
|
- return iterator.result(mapped.release_value());
|
|
|
- });
|
|
|
+// 27.1.4.3 Iterator.prototype.every ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.every
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::every)
|
|
|
+{
|
|
|
+ auto predicate = vm.argument(0);
|
|
|
|
|
|
- // 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
- // 7. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
- auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
|
|
|
+ // 1. Let O be the this value.
|
|
|
+ // 2. If O is not an Object, throw a TypeError exception.
|
|
|
+ auto object = TRY(this_object(vm));
|
|
|
|
|
|
- // 8. Return result.
|
|
|
- return result;
|
|
|
+ // 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
|
|
+ if (!predicate.is_function())
|
|
|
+ return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
|
|
|
+
|
|
|
+ // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
+
|
|
|
+ // 5. Let counter be 0.
|
|
|
+ size_t counter = 0;
|
|
|
+
|
|
|
+ // 6. Repeat,
|
|
|
+ while (true) {
|
|
|
+ // a. Let value be ? IteratorStepValue(iterated).
|
|
|
+ auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
+
|
|
|
+ // b. If value is done, return undefined.
|
|
|
+ if (!value.has_value())
|
|
|
+ return Value { true };
|
|
|
+
|
|
|
+ // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
|
|
+ auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
|
|
|
+
|
|
|
+ // d. IfAbruptCloseIterator(result, iterated).
|
|
|
+ if (result.is_error())
|
|
|
+ return *TRY(iterator_close(vm, iterated, result.release_error()));
|
|
|
+
|
|
|
+ // e. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
|
|
|
+ if (!result.value().to_boolean())
|
|
|
+ return *TRY(iterator_close(vm, iterated, normal_completion(Value { false })));
|
|
|
+
|
|
|
+ // f. Set counter to counter + 1.
|
|
|
+ ++counter;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.3 Iterator.prototype.filter ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.filter
|
|
|
+// 27.1.4.4 Iterator.prototype.filter ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.filter
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::filter)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
@@ -190,144 +241,54 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::filter)
|
|
|
|
|
|
// 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
// 7. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
- auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
|
|
|
+ auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
|
|
|
|
|
// 8. Return result.
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.4 Iterator.prototype.take ( limit ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.take
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::take)
|
|
|
+// 27.1.4.5 Iterator.prototype.find ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.find
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::find)
|
|
|
{
|
|
|
- auto& realm = *vm.current_realm();
|
|
|
-
|
|
|
- auto limit = vm.argument(0);
|
|
|
+ auto predicate = vm.argument(0);
|
|
|
|
|
|
// 1. Let O be the this value.
|
|
|
// 2. If O is not an Object, throw a TypeError exception.
|
|
|
auto object = TRY(this_object(vm));
|
|
|
|
|
|
- // 3. Let numLimit be ? ToNumber(limit).
|
|
|
- auto numeric_limit = TRY(limit.to_number(vm));
|
|
|
-
|
|
|
- // 4. If numLimit is NaN, throw a RangeError exception.
|
|
|
- if (numeric_limit.is_nan())
|
|
|
- return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
|
|
|
-
|
|
|
- // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
|
|
|
- auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
|
|
|
-
|
|
|
- // 6. If integerLimit < 0, throw a RangeError exception.
|
|
|
- if (integer_limit < 0)
|
|
|
- return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
|
|
|
+ // 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
|
|
+ if (!predicate.is_function())
|
|
|
+ return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
|
|
|
|
|
|
- // 7. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
|
|
|
- // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
|
|
|
- auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
|
- auto& iterated = iterator.underlying_iterator();
|
|
|
-
|
|
|
- // a. Let remaining be integerLimit.
|
|
|
- // b. Repeat,
|
|
|
-
|
|
|
- // i. If remaining is 0, then
|
|
|
- if (iterator.counter() >= integer_limit) {
|
|
|
- // 1. Return ? IteratorClose(iterated, NormalCompletion(undefined)).
|
|
|
- return iterator.close_result(vm, normal_completion(js_undefined()));
|
|
|
- }
|
|
|
-
|
|
|
- // ii. If remaining is not +∞, then
|
|
|
- // 1. Set remaining to remaining - 1.
|
|
|
- iterator.increment_counter();
|
|
|
+ // 5. Let counter be 0.
|
|
|
+ size_t counter = 0;
|
|
|
|
|
|
- // iii. Let value be ? IteratorStepValue(iterated).
|
|
|
+ // 6. Repeat,
|
|
|
+ while (true) {
|
|
|
+ // a. Let value be ? IteratorStepValue(iterated).
|
|
|
auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
|
|
|
- // iv. If value is done, return undefined.
|
|
|
+ // b. If value is done, return undefined.
|
|
|
if (!value.has_value())
|
|
|
- return iterator.result(js_undefined());
|
|
|
-
|
|
|
- // v. Let completion be Completion(Yield(value)).
|
|
|
- // vi. IfAbruptCloseIterator(completion, iterated).
|
|
|
- return iterator.result(*value);
|
|
|
- });
|
|
|
-
|
|
|
- // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
- // 10. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
- auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
|
|
|
-
|
|
|
- // 11. Return result.
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-// 3.1.3.5 Iterator.prototype.drop ( limit ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.drop
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
|
|
|
-{
|
|
|
- auto& realm = *vm.current_realm();
|
|
|
-
|
|
|
- auto limit = vm.argument(0);
|
|
|
-
|
|
|
- // 1. Let O be the this value.
|
|
|
- // 2. If O is not an Object, throw a TypeError exception.
|
|
|
- auto object = TRY(this_object(vm));
|
|
|
-
|
|
|
- // 3. Let numLimit be ? ToNumber(limit).
|
|
|
- auto numeric_limit = TRY(limit.to_number(vm));
|
|
|
-
|
|
|
- // 4. If numLimit is NaN, throw a RangeError exception.
|
|
|
- if (numeric_limit.is_nan())
|
|
|
- return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
|
|
|
-
|
|
|
- // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
|
|
|
- auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
|
|
|
-
|
|
|
- // 6. If integerLimit < 0, throw a RangeError exception.
|
|
|
- if (integer_limit < 0)
|
|
|
- return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
|
|
|
-
|
|
|
- // 7. Let iterated be ? GetIteratorDirect(O).
|
|
|
- auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
-
|
|
|
- // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
|
|
|
- auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
|
- auto& iterated = iterator.underlying_iterator();
|
|
|
-
|
|
|
- // a. Let remaining be integerLimit.
|
|
|
- // b. Repeat, while remaining > 0,
|
|
|
- while (iterator.counter() < integer_limit) {
|
|
|
- // i. If remaining is not +∞, then
|
|
|
- // 1. Set remaining to remaining - 1.
|
|
|
- iterator.increment_counter();
|
|
|
-
|
|
|
- // ii. Let next be ? IteratorStep(iterated).
|
|
|
- auto next = TRY(iterator_step(vm, iterated));
|
|
|
-
|
|
|
- // iii. If next is false, return undefined.
|
|
|
- if (!next)
|
|
|
- return iterator.result(js_undefined());
|
|
|
- }
|
|
|
-
|
|
|
- // c. Repeat,
|
|
|
-
|
|
|
- // i. Let value be ? IteratorStepValue(iterated).
|
|
|
- auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
+ return js_undefined();
|
|
|
|
|
|
- // ii. If value is done, return undefined.
|
|
|
- if (!value.has_value())
|
|
|
- return iterator.result(js_undefined());
|
|
|
+ // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
|
|
+ auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
|
|
|
|
|
|
- // iii. Let completion be Completion(Yield(value)).
|
|
|
- // iv. IfAbruptCloseIterator(completion, iterated).
|
|
|
- return iterator.result(*value);
|
|
|
- });
|
|
|
+ // d. IfAbruptCloseIterator(result, iterated).
|
|
|
+ if (result.is_error())
|
|
|
+ return *TRY(iterator_close(vm, iterated, result.release_error()));
|
|
|
|
|
|
- // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
- // 10. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
- auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
|
|
|
+ // e. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(value)).
|
|
|
+ if (result.value().to_boolean())
|
|
|
+ return *TRY(iterator_close(vm, iterated, normal_completion(value)));
|
|
|
|
|
|
- // 11. Return result.
|
|
|
- return result;
|
|
|
+ // f. Set counter to counter + 1.
|
|
|
+ ++counter;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
class FlatMapIterator : public Cell {
|
|
@@ -385,8 +346,8 @@ private:
|
|
|
if (mapped.is_error())
|
|
|
return iterator.close_result(vm, mapped.release_error());
|
|
|
|
|
|
- // v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-strings)).
|
|
|
- auto inner_iterator = get_iterator_flattenable(vm, mapped.release_value(), StringHandling::RejectStrings);
|
|
|
+ // v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-primitives)).
|
|
|
+ auto inner_iterator = get_iterator_flattenable(vm, mapped.release_value(), PrimitiveHandling::RejectPrimitives);
|
|
|
|
|
|
// vi. IfAbruptCloseIterator(innerIterator, iterated).
|
|
|
if (inner_iterator.is_error())
|
|
@@ -403,39 +364,117 @@ private:
|
|
|
return next_inner_iterator(vm, iterated, iterator, mapper);
|
|
|
}
|
|
|
|
|
|
- ThrowCompletionOr<Value> next_inner_iterator(VM& vm, IteratorRecord& iterated, IteratorHelper& iterator, FunctionObject& mapper)
|
|
|
- {
|
|
|
- VERIFY(m_inner_iterator);
|
|
|
+ ThrowCompletionOr<Value> next_inner_iterator(VM& vm, IteratorRecord& iterated, IteratorHelper& iterator, FunctionObject& mapper)
|
|
|
+ {
|
|
|
+ VERIFY(m_inner_iterator);
|
|
|
+
|
|
|
+ // 1. Let innerValue be Completion(IteratorStepValue(innerIterator)).
|
|
|
+ auto inner_value = iterator_step_value(vm, *m_inner_iterator);
|
|
|
+
|
|
|
+ // 2. IfAbruptCloseIterator(innerValue, iterated).
|
|
|
+ if (inner_value.is_error())
|
|
|
+ return iterator.close_result(vm, inner_value.release_error());
|
|
|
+
|
|
|
+ // 3. If innerValue is done, then
|
|
|
+ if (!inner_value.value().has_value()) {
|
|
|
+ // a. Set innerAlive to false.
|
|
|
+ m_inner_iterator = nullptr;
|
|
|
+
|
|
|
+ return next_outer_iterator(vm, iterated, iterator, mapper);
|
|
|
+ }
|
|
|
+ // 4. Else,
|
|
|
+ else {
|
|
|
+ // a. Let completion be Completion(Yield(innerValue)).
|
|
|
+ // NOTE: Step b is implemented via on_abrupt_completion.
|
|
|
+ return *inner_value.release_value();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ GCPtr<IteratorRecord> m_inner_iterator;
|
|
|
+};
|
|
|
+
|
|
|
+JS_DEFINE_ALLOCATOR(FlatMapIterator);
|
|
|
+
|
|
|
+// 27.1.4.6 Iterator.prototype.flatMap ( mapper ), https://tc39.es/ecma262/#sec-iterator.prototype.flatmap
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
|
|
|
+{
|
|
|
+ auto& realm = *vm.current_realm();
|
|
|
+
|
|
|
+ auto mapper = vm.argument(0);
|
|
|
+
|
|
|
+ // 1. Let O be the this value.
|
|
|
+ // 2. If O is not an Object, throw a TypeError exception.
|
|
|
+ auto object = TRY(this_object(vm));
|
|
|
+
|
|
|
+ // 3. If IsCallable(mapper) is false, throw a TypeError exception.
|
|
|
+ if (!mapper.is_function())
|
|
|
+ return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "mapper"sv);
|
|
|
+
|
|
|
+ // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
+
|
|
|
+ auto flat_map_iterator = vm.heap().allocate<FlatMapIterator>(realm);
|
|
|
+
|
|
|
+ // 5. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
|
|
|
+ auto closure = JS::create_heap_function(realm.heap(), [flat_map_iterator, mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) mutable -> ThrowCompletionOr<Value> {
|
|
|
+ auto& iterated = iterator.underlying_iterator();
|
|
|
+ return flat_map_iterator->next(vm, iterated, iterator, *mapper);
|
|
|
+ });
|
|
|
+
|
|
|
+ auto abrupt_closure = JS::create_heap_function(realm.heap(), [flat_map_iterator](VM& vm, IteratorHelper& iterator, Completion const& completion) -> ThrowCompletionOr<Value> {
|
|
|
+ return flat_map_iterator->on_abrupt_completion(vm, iterator, completion);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
+ // 7. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
+ auto result = TRY(IteratorHelper::create(realm, iterated, closure, move(abrupt_closure)));
|
|
|
+
|
|
|
+ // 8. Return result.
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+// 27.1.4.7 Iterator.prototype.forEach ( procedure ), https://tc39.es/ecma262/#sec-iterator.prototype.foreach
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::for_each)
|
|
|
+{
|
|
|
+ auto function = vm.argument(0);
|
|
|
+
|
|
|
+ // 1. Let O be the this value.
|
|
|
+ // 2. If O is not an Object, throw a TypeError exception.
|
|
|
+ auto object = TRY(this_object(vm));
|
|
|
+
|
|
|
+ // 3. If IsCallable(fn) is false, throw a TypeError exception.
|
|
|
+ if (!function.is_function())
|
|
|
+ return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "fn"sv);
|
|
|
+
|
|
|
+ // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
|
|
|
- // 1. Let innerValue be Completion(IteratorStepValue(innerIterator)).
|
|
|
- auto inner_value = iterator_step_value(vm, *m_inner_iterator);
|
|
|
+ // 5. Let counter be 0.
|
|
|
+ size_t counter = 0;
|
|
|
|
|
|
- // 2. IfAbruptCloseIterator(innerValue, iterated).
|
|
|
- if (inner_value.is_error())
|
|
|
- return iterator.close_result(vm, inner_value.release_error());
|
|
|
+ // 6. Repeat,
|
|
|
+ while (true) {
|
|
|
+ // a. Let value be ? IteratorStepValue(iterated).
|
|
|
+ auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
|
|
|
- // 3. If innerValue is done, then
|
|
|
- if (!inner_value.value().has_value()) {
|
|
|
- // a. Set innerAlive to false.
|
|
|
- m_inner_iterator = nullptr;
|
|
|
+ // b. If value is done, return undefined.
|
|
|
+ if (!value.has_value())
|
|
|
+ return js_undefined();
|
|
|
|
|
|
- return next_outer_iterator(vm, iterated, iterator, mapper);
|
|
|
- }
|
|
|
- // 4. Else,
|
|
|
- else {
|
|
|
- // a. Let completion be Completion(Yield(innerValue)).
|
|
|
- // NOTE: Step b is implemented via on_abrupt_completion.
|
|
|
- return *inner_value.release_value();
|
|
|
- }
|
|
|
- }
|
|
|
+ // c. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
|
|
|
+ auto result = call(vm, function.as_function(), js_undefined(), *value, Value { counter });
|
|
|
|
|
|
- GCPtr<IteratorRecord> m_inner_iterator;
|
|
|
-};
|
|
|
+ // d. IfAbruptCloseIterator(result, iterated).
|
|
|
+ if (result.is_error())
|
|
|
+ return *TRY(iterator_close(vm, iterated, result.release_error()));
|
|
|
|
|
|
-JS_DEFINE_ALLOCATOR(FlatMapIterator);
|
|
|
+ // e. Set counter to counter + 1.
|
|
|
+ ++counter;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-// 3.1.3.6 Iterator.prototype.flatMap ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.flatmap
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
|
|
|
+// 27.1.4.8 Iterator.prototype.map ( mapper ), https://tc39.es/ecma262/#sec-iterator.prototype.map
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::map)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
|
|
|
@@ -452,27 +491,45 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
|
|
|
// 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
|
|
|
- auto flat_map_iterator = vm.heap().allocate<FlatMapIterator>(realm);
|
|
|
-
|
|
|
// 5. Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
|
|
|
- auto closure = JS::create_heap_function(realm.heap(), [flat_map_iterator, mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) mutable -> ThrowCompletionOr<Value> {
|
|
|
+ auto closure = JS::create_heap_function(realm.heap(), [mapper = NonnullGCPtr { mapper.as_function() }](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
|
auto& iterated = iterator.underlying_iterator();
|
|
|
- return flat_map_iterator->next(vm, iterated, iterator, *mapper);
|
|
|
- });
|
|
|
|
|
|
- auto abrupt_closure = JS::create_heap_function(realm.heap(), [flat_map_iterator](VM& vm, IteratorHelper& iterator, Completion const& completion) -> ThrowCompletionOr<Value> {
|
|
|
- return flat_map_iterator->on_abrupt_completion(vm, iterator, completion);
|
|
|
+ // a. Let counter be 0.
|
|
|
+ // b. Repeat,
|
|
|
+
|
|
|
+ // i. Let value be ? IteratorStepValue(iterated).
|
|
|
+ auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
+
|
|
|
+ // ii. If value is done, return undefined.
|
|
|
+ if (!value.has_value())
|
|
|
+ return iterator.result(js_undefined());
|
|
|
+
|
|
|
+ // iii. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
|
|
|
+ auto mapped = call(vm, *mapper, js_undefined(), *value, Value { iterator.counter() });
|
|
|
+
|
|
|
+ // iv. IfAbruptCloseIterator(mapped, iterated).
|
|
|
+ if (mapped.is_error())
|
|
|
+ return iterator.close_result(vm, mapped.release_error());
|
|
|
+
|
|
|
+ // vii. Set counter to counter + 1.
|
|
|
+ // NOTE: We do this step early to ensure it occurs before returning.
|
|
|
+ iterator.increment_counter();
|
|
|
+
|
|
|
+ // v. Let completion be Completion(Yield(mapped)).
|
|
|
+ // vi. IfAbruptCloseIterator(completion, iterated).
|
|
|
+ return iterator.result(mapped.release_value());
|
|
|
});
|
|
|
|
|
|
// 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
// 7. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
- auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure), move(abrupt_closure)));
|
|
|
+ auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
|
|
|
|
|
// 8. Return result.
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.7 Iterator.prototype.reduce ( reducer [ , initialValue ] ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.reduce
|
|
|
+// 27.1.4.9 Iterator.prototype.reduce ( reducer [ , initialValue ] ), https://tc39.es/ecma262/#sec-iterator.prototype.reduce
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
|
|
|
{
|
|
|
auto reducer = vm.argument(0);
|
|
@@ -538,76 +595,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.8 Iterator.prototype.toArray ( ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.toarray
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_array)
|
|
|
-{
|
|
|
- auto& realm = *vm.current_realm();
|
|
|
-
|
|
|
- // 1. Let O be the this value.
|
|
|
- // 2. If O is not an Object, throw a TypeError exception.
|
|
|
- auto object = TRY(this_object(vm));
|
|
|
-
|
|
|
- // 3. Let iterated be ? GetIteratorDirect(O).
|
|
|
- auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
-
|
|
|
- // 4. Let items be a new empty List.
|
|
|
- Vector<Value> items;
|
|
|
-
|
|
|
- // 5. Repeat,
|
|
|
- while (true) {
|
|
|
- // a. Let value be ? IteratorStepValue(iterated).
|
|
|
- auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
-
|
|
|
- // b. If value is done, return CreateArrayFromList(items).
|
|
|
- if (!value.has_value())
|
|
|
- return Array::create_from(realm, items);
|
|
|
-
|
|
|
- // c. Append value to items.
|
|
|
- TRY_OR_THROW_OOM(vm, items.try_append(*value));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 3.1.3.9 Iterator.prototype.forEach ( fn ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.foreach
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::for_each)
|
|
|
-{
|
|
|
- auto function = vm.argument(0);
|
|
|
-
|
|
|
- // 1. Let O be the this value.
|
|
|
- // 2. If O is not an Object, throw a TypeError exception.
|
|
|
- auto object = TRY(this_object(vm));
|
|
|
-
|
|
|
- // 3. If IsCallable(fn) is false, throw a TypeError exception.
|
|
|
- if (!function.is_function())
|
|
|
- return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "fn"sv);
|
|
|
-
|
|
|
- // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
- auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
-
|
|
|
- // 5. Let counter be 0.
|
|
|
- size_t counter = 0;
|
|
|
-
|
|
|
- // 6. Repeat,
|
|
|
- while (true) {
|
|
|
- // a. Let value be ? IteratorStepValue(iterated).
|
|
|
- auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
-
|
|
|
- // b. If value is done, return undefined.
|
|
|
- if (!value.has_value())
|
|
|
- return js_undefined();
|
|
|
-
|
|
|
- // c. Let result be Completion(Call(fn, undefined, « value, 𝔽(counter) »)).
|
|
|
- auto result = call(vm, function.as_function(), js_undefined(), *value, Value { counter });
|
|
|
-
|
|
|
- // d. IfAbruptCloseIterator(result, iterated).
|
|
|
- if (result.is_error())
|
|
|
- return *TRY(iterator_close(vm, iterated, result.release_error()));
|
|
|
-
|
|
|
- // e. Set counter to counter + 1.
|
|
|
- ++counter;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 3.1.3.10 Iterator.prototype.some ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.some
|
|
|
+// 27.1.4.10 Iterator.prototype.some ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.some
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::some)
|
|
|
{
|
|
|
auto predicate = vm.argument(0);
|
|
@@ -651,102 +639,115 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::some)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.11 Iterator.prototype.every ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.every
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::every)
|
|
|
+// 27.1.4.11 Iterator.prototype.take ( limit ), https://tc39.es/ecma262/#sec-iterator.prototype.take
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::take)
|
|
|
{
|
|
|
- auto predicate = vm.argument(0);
|
|
|
+ auto& realm = *vm.current_realm();
|
|
|
+
|
|
|
+ auto limit = vm.argument(0);
|
|
|
|
|
|
// 1. Let O be the this value.
|
|
|
// 2. If O is not an Object, throw a TypeError exception.
|
|
|
auto object = TRY(this_object(vm));
|
|
|
|
|
|
- // 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
|
|
- if (!predicate.is_function())
|
|
|
- return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
|
|
|
+ // 3. Let numLimit be ? ToNumber(limit).
|
|
|
+ auto numeric_limit = TRY(limit.to_number(vm));
|
|
|
|
|
|
- // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ // 4. If numLimit is NaN, throw a RangeError exception.
|
|
|
+ if (numeric_limit.is_nan())
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::NumberIsNaN, "limit"sv);
|
|
|
+
|
|
|
+ // 5. Let integerLimit be ! ToIntegerOrInfinity(numLimit).
|
|
|
+ auto integer_limit = MUST(numeric_limit.to_integer_or_infinity(vm));
|
|
|
+
|
|
|
+ // 6. If integerLimit < 0, throw a RangeError exception.
|
|
|
+ if (integer_limit < 0)
|
|
|
+ return vm.throw_completion<RangeError>(ErrorType::NumberIsNegative, "limit"sv);
|
|
|
+
|
|
|
+ // 7. Let iterated be ? GetIteratorDirect(O).
|
|
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
|
|
|
- // 5. Let counter be 0.
|
|
|
- size_t counter = 0;
|
|
|
+ // 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
|
|
|
+ auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
|
+ auto& iterated = iterator.underlying_iterator();
|
|
|
|
|
|
- // 6. Repeat,
|
|
|
- while (true) {
|
|
|
- // a. Let value be ? IteratorStepValue(iterated).
|
|
|
+ // a. Let remaining be integerLimit.
|
|
|
+ // b. Repeat,
|
|
|
+
|
|
|
+ // i. If remaining is 0, then
|
|
|
+ if (iterator.counter() >= integer_limit) {
|
|
|
+ // 1. Return ? IteratorClose(iterated, NormalCompletion(undefined)).
|
|
|
+ return iterator.close_result(vm, normal_completion(js_undefined()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ii. If remaining is not +∞, then
|
|
|
+ // 1. Set remaining to remaining - 1.
|
|
|
+ iterator.increment_counter();
|
|
|
+
|
|
|
+ // iii. Let value be ? IteratorStepValue(iterated).
|
|
|
auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
|
|
|
- // b. If value is done, return undefined.
|
|
|
+ // iv. If value is done, return undefined.
|
|
|
if (!value.has_value())
|
|
|
- return Value { true };
|
|
|
-
|
|
|
- // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
|
|
- auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
|
|
|
+ return iterator.result(js_undefined());
|
|
|
|
|
|
- // d. IfAbruptCloseIterator(result, iterated).
|
|
|
- if (result.is_error())
|
|
|
- return *TRY(iterator_close(vm, iterated, result.release_error()));
|
|
|
+ // v. Let completion be Completion(Yield(value)).
|
|
|
+ // vi. IfAbruptCloseIterator(completion, iterated).
|
|
|
+ return iterator.result(*value);
|
|
|
+ });
|
|
|
|
|
|
- // e. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
|
|
|
- if (!result.value().to_boolean())
|
|
|
- return *TRY(iterator_close(vm, iterated, normal_completion(Value { false })));
|
|
|
+ // 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
|
|
+ // 10. Set result.[[UnderlyingIterator]] to iterated.
|
|
|
+ auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
|
|
|
|
|
- // f. Set counter to counter + 1.
|
|
|
- ++counter;
|
|
|
- }
|
|
|
+ // 11. Return result.
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.12 Iterator.prototype.find ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.find
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::find)
|
|
|
+// 27.1.4.12 Iterator.prototype.toArray ( ), https://tc39.es/ecma262/#sec-iterator.prototype.toarray
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_array)
|
|
|
{
|
|
|
- auto predicate = vm.argument(0);
|
|
|
+ auto& realm = *vm.current_realm();
|
|
|
|
|
|
// 1. Let O be the this value.
|
|
|
// 2. If O is not an Object, throw a TypeError exception.
|
|
|
auto object = TRY(this_object(vm));
|
|
|
|
|
|
- // 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
|
|
- if (!predicate.is_function())
|
|
|
- return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
|
|
|
-
|
|
|
- // 4. Let iterated be ? GetIteratorDirect(O).
|
|
|
+ // 3. Let iterated be ? GetIteratorDirect(O).
|
|
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
|
|
|
|
|
- // 5. Let counter be 0.
|
|
|
- size_t counter = 0;
|
|
|
+ // 4. Let items be a new empty List.
|
|
|
+ Vector<Value> items;
|
|
|
|
|
|
- // 6. Repeat,
|
|
|
+ // 5. Repeat,
|
|
|
while (true) {
|
|
|
// a. Let value be ? IteratorStepValue(iterated).
|
|
|
auto value = TRY(iterator_step_value(vm, iterated));
|
|
|
|
|
|
- // b. If value is done, return undefined.
|
|
|
+ // b. If value is done, return CreateArrayFromList(items).
|
|
|
if (!value.has_value())
|
|
|
- return js_undefined();
|
|
|
-
|
|
|
- // c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
|
|
- auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
|
|
|
-
|
|
|
- // d. IfAbruptCloseIterator(result, iterated).
|
|
|
- if (result.is_error())
|
|
|
- return *TRY(iterator_close(vm, iterated, result.release_error()));
|
|
|
-
|
|
|
- // e. If ToBoolean(result) is true, return ? IteratorClose(iterated, NormalCompletion(value)).
|
|
|
- if (result.value().to_boolean())
|
|
|
- return *TRY(iterator_close(vm, iterated, normal_completion(value)));
|
|
|
+ return Array::create_from(realm, items);
|
|
|
|
|
|
- // f. Set counter to counter + 1.
|
|
|
- ++counter;
|
|
|
+ // c. Append value to items.
|
|
|
+ TRY_OR_THROW_OOM(vm, items.try_append(*value));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.13.1 get Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-get-iteratorprototype-@@tostringtag
|
|
|
+// 27.1.4.13 Iterator.prototype [ %Symbol.iterator% ] ( ), https://tc39.es/ecma262/#sec-iterator.prototype-%symbol.iterator%
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::symbol_iterator)
|
|
|
+{
|
|
|
+ // 1. Return the this value.
|
|
|
+ return vm.this_value();
|
|
|
+}
|
|
|
+
|
|
|
+// 27.1.4.14.1 get Iterator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-get-iterator.prototype-%symbol.tostringtag%
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_string_tag_getter)
|
|
|
{
|
|
|
// 1. Return "Iterator".
|
|
|
return PrimitiveString::create(vm, vm.names.Iterator.as_string());
|
|
|
}
|
|
|
|
|
|
-// 3.1.3.13.2 set Iterator.prototype [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-set-iteratorprototype-@@tostringtag
|
|
|
+// 27.1.4.14.2 set Iterator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-set-iterator.prototype-%symbol.tostringtag%
|
|
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_string_tag_setter)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|