mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-03 14:50:02 +00:00
LibJS: Update spec numbers for the Iterator Helpers proposal
This proposal has reached stage 4 and was merged into the ECMA-262 spec.
See: 961f269
This commit is contained in:
parent
896c2e2f0f
commit
84ad36de06
Notes:
github-actions[bot]
2024-10-23 21:27:24 +00:00
Author: https://github.com/trflynn89
Commit: 84ad36de06
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1936
8 changed files with 408 additions and 399 deletions
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
||||||
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
|
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +35,19 @@ Iterator::Iterator(Object& prototype)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.2 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod
|
// 7.4.2 GetIteratorDirect ( obj ), https://tc39.es/ecma262/#sec-getiteratordirect
|
||||||
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM& vm, Object& object)
|
||||||
|
{
|
||||||
|
// 1. Let nextMethod be ? Get(obj, "next").
|
||||||
|
auto next_method = TRY(object.get(vm.names.next));
|
||||||
|
|
||||||
|
// 2. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||||
|
// 3. Return iteratorRecord.
|
||||||
|
auto& realm = *vm.current_realm();
|
||||||
|
return vm.heap().allocate<IteratorRecord>(realm, realm, object, next_method, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.4.3 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM& vm, Value object, NonnullGCPtr<FunctionObject> method)
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM& vm, Value object, NonnullGCPtr<FunctionObject> method)
|
||||||
{
|
{
|
||||||
// 1. Let iterator be ? Call(method, obj).
|
// 1. Let iterator be ? Call(method, obj).
|
||||||
|
@ -56,7 +68,7 @@ ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM& vm,
|
||||||
return iterator_record;
|
return iterator_record;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.3 GetIterator ( obj, kind ), https://tc39.es/ecma262/#sec-getiterator
|
// 7.4.4 GetIterator ( obj, kind ), https://tc39.es/ecma262/#sec-getiterator
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM& vm, Value object, IteratorHint kind)
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM& vm, Value object, IteratorHint kind)
|
||||||
{
|
{
|
||||||
JS::GCPtr<FunctionObject> method;
|
JS::GCPtr<FunctionObject> method;
|
||||||
|
@ -96,29 +108,24 @@ ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM& vm, Value objec
|
||||||
return TRY(get_iterator_from_method(vm, object, *method));
|
return TRY(get_iterator_from_method(vm, object, *method));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1.1 GetIteratorDirect ( obj ), https://tc39.es/proposal-iterator-helpers/#sec-getiteratorflattenable
|
// 7.4.5 GetIteratorFlattenable ( obj, primitiveHandling ), https://tc39.es/ecma262/#sec-getiteratorflattenable
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM& vm, Object& object)
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM& vm, Value object, PrimitiveHandling primitive_handling)
|
||||||
{
|
|
||||||
// 1. Let nextMethod be ? Get(obj, "next").
|
|
||||||
auto next_method = TRY(object.get(vm.names.next));
|
|
||||||
|
|
||||||
// 2. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
|
||||||
// 3. Return iteratorRecord.
|
|
||||||
auto& realm = *vm.current_realm();
|
|
||||||
return vm.heap().allocate<IteratorRecord>(realm, realm, object, next_method, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.1.2 GetIteratorFlattenable ( obj, stringHandling ), https://tc39.es/proposal-iterator-helpers/#sec-getiteratorflattenable
|
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM& vm, Value object, StringHandling string_handling)
|
|
||||||
{
|
{
|
||||||
// 1. If obj is not an Object, then
|
// 1. If obj is not an Object, then
|
||||||
if (!object.is_object()) {
|
if (!object.is_object()) {
|
||||||
// a. If stringHandling is reject-strings or obj is not a String, throw a TypeError exception.
|
// a. If primitiveHandling is reject-primitives, throw a TypeError exception.
|
||||||
if (string_handling == StringHandling::RejectStrings || !object.is_string())
|
if (primitive_handling == PrimitiveHandling::RejectPrimitives)
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotAnObject, object.to_string_without_side_effects());
|
return vm.throw_completion<TypeError>(ErrorType::NotAnObject, object.to_string_without_side_effects());
|
||||||
|
|
||||||
|
// b. Assert: primitiveHandling is iterate-string-primitives.
|
||||||
|
ASSERT(primitive_handling == PrimitiveHandling::IterateStringPrimitives);
|
||||||
|
|
||||||
|
// c. If obj is not a String, throw a TypeError exception.
|
||||||
|
if (!object.is_string())
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::NotAString, object.to_string_without_side_effects());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Let method be ? GetMethod(obj, @@iterator).
|
// 2. Let method be ? GetMethod(obj, %Symbol.iterator%).
|
||||||
auto method = TRY(object.get_method(vm, vm.well_known_symbol_iterator()));
|
auto method = TRY(object.get_method(vm, vm.well_known_symbol_iterator()));
|
||||||
|
|
||||||
Value iterator;
|
Value iterator;
|
||||||
|
@ -142,7 +149,7 @@ ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM& vm,
|
||||||
return TRY(get_iterator_direct(vm, iterator.as_object()));
|
return TRY(get_iterator_direct(vm, iterator.as_object()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.4 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext
|
// 7.4.6 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext
|
||||||
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord& iterator_record, Optional<Value> value)
|
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord& iterator_record, Optional<Value> value)
|
||||||
{
|
{
|
||||||
auto result = [&]() {
|
auto result = [&]() {
|
||||||
|
@ -183,21 +190,21 @@ ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord& it
|
||||||
return result_value.as_object();
|
return result_value.as_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.5 IteratorComplete ( iterResult ), https://tc39.es/ecma262/#sec-iteratorcomplete
|
// 7.4.7 IteratorComplete ( iteratorResult ), https://tc39.es/ecma262/#sec-iteratorcomplete
|
||||||
ThrowCompletionOr<bool> iterator_complete(VM& vm, Object& iterator_result)
|
ThrowCompletionOr<bool> iterator_complete(VM& vm, Object& iterator_result)
|
||||||
{
|
{
|
||||||
// 1. Return ToBoolean(? Get(iterResult, "done")).
|
// 1. Return ToBoolean(? Get(iterResult, "done")).
|
||||||
return TRY(iterator_result.get(vm.names.done)).to_boolean();
|
return TRY(iterator_result.get(vm.names.done)).to_boolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.6 IteratorValue ( iterResult ), https://tc39.es/ecma262/#sec-iteratorvalue
|
// 7.4.8 IteratorValue ( iteratorResult ), https://tc39.es/ecma262/#sec-iteratorvalue
|
||||||
ThrowCompletionOr<Value> iterator_value(VM& vm, Object& iterator_result)
|
ThrowCompletionOr<Value> iterator_value(VM& vm, Object& iterator_result)
|
||||||
{
|
{
|
||||||
// 1. Return ? Get(iterResult, "value").
|
// 1. Return ? Get(iterResult, "value").
|
||||||
return TRY(iterator_result.get(vm.names.value));
|
return TRY(iterator_result.get(vm.names.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.7 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
|
// 7.4.9 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
|
||||||
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord& iterator_record)
|
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord& iterator_record)
|
||||||
{
|
{
|
||||||
// 1. Let result be ? IteratorNext(iteratorRecord).
|
// 1. Let result be ? IteratorNext(iteratorRecord).
|
||||||
|
@ -231,7 +238,7 @@ ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord& iterator_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.8 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue
|
// 7.4.10 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue
|
||||||
ThrowCompletionOr<Optional<Value>> iterator_step_value(VM& vm, IteratorRecord& iterator_record)
|
ThrowCompletionOr<Optional<Value>> iterator_step_value(VM& vm, IteratorRecord& iterator_record)
|
||||||
{
|
{
|
||||||
// 1. Let result be ? IteratorStep(iteratorRecord).
|
// 1. Let result be ? IteratorStep(iteratorRecord).
|
||||||
|
@ -256,8 +263,8 @@ ThrowCompletionOr<Optional<Value>> iterator_step_value(VM& vm, IteratorRecord& i
|
||||||
return TRY(value);
|
return TRY(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.9 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
|
// 7.4.11 IteratorClose ( iteratorRecord, completion , https://tc39.es/ecma262/#sec-iteratorclose
|
||||||
// 7.4.11 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
|
// 7.4.13 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
|
||||||
// NOTE: These only differ in that async awaits the inner value after the call.
|
// NOTE: These only differ in that async awaits the inner value after the call.
|
||||||
static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_record, Completion completion, IteratorHint iterator_hint)
|
static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_record, Completion completion, IteratorHint iterator_hint)
|
||||||
{
|
{
|
||||||
|
@ -307,19 +314,19 @@ static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_rec
|
||||||
return completion;
|
return completion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.9 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
|
// 7.4.11 IteratorClose ( iteratorRecord, completion , https://tc39.es/ecma262/#sec-iteratorclose
|
||||||
Completion iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion)
|
Completion iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion)
|
||||||
{
|
{
|
||||||
return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Sync);
|
return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.11 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
|
// 7.4.13 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
|
||||||
Completion async_iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion)
|
Completion async_iterator_close(VM& vm, IteratorRecord const& iterator_record, Completion completion)
|
||||||
{
|
{
|
||||||
return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Async);
|
return iterator_close_impl(vm, iterator_record, move(completion), IteratorHint::Async);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.12 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject
|
// 7.4.14 CreateIteratorResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject
|
||||||
NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool done)
|
NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool done)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
@ -337,7 +344,7 @@ NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool don
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.14 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist
|
// 7.4.16 IteratorToList ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratortolist
|
||||||
ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord& iterator_record)
|
ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord& iterator_record)
|
||||||
{
|
{
|
||||||
// 1. Let values be a new empty List.
|
// 1. Let values be a new empty List.
|
||||||
|
@ -359,7 +366,7 @@ ThrowCompletionOr<MarkedVector<Value>> iterator_to_list(VM& vm, IteratorRecord&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 SetterThatIgnoresPrototypeProperties ( this, home, p, v ), https://tc39.es/proposal-iterator-helpers/#sec-SetterThatIgnoresPrototypeProperties
|
// 7.3.36 SetterThatIgnoresPrototypeProperties ( thisValue, home, p, v ), https://tc39.es/ecma262/#sec-SetterThatIgnoresPrototypeProperties
|
||||||
ThrowCompletionOr<void> setter_that_ignores_prototype_properties(VM& vm, Value this_, Object const& home, PropertyKey const& property, Value value)
|
ThrowCompletionOr<void> setter_that_ignores_prototype_properties(VM& vm, Value this_, Object const& home, PropertyKey const& property, Value value)
|
||||||
{
|
{
|
||||||
// 1. If this is not an Object, then
|
// 1. If this is not an Object, then
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
||||||
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
|
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -65,20 +65,20 @@ enum class IteratorHint {
|
||||||
Async,
|
Async,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StringHandling {
|
enum class PrimitiveHandling {
|
||||||
IterateStrings,
|
IterateStringPrimitives,
|
||||||
RejectStrings,
|
RejectPrimitives,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM&, Object&);
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM&, Value, NonnullGCPtr<FunctionObject>);
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_from_method(VM&, Value, NonnullGCPtr<FunctionObject>);
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM&, Value, IteratorHint);
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator(VM&, Value, IteratorHint);
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_direct(VM&, Object&);
|
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM&, Value, PrimitiveHandling);
|
||||||
ThrowCompletionOr<NonnullGCPtr<IteratorRecord>> get_iterator_flattenable(VM&, Value, StringHandling);
|
|
||||||
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM&, IteratorRecord&, Optional<Value> = {});
|
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM&, IteratorRecord&, Optional<Value> = {});
|
||||||
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM&, IteratorRecord&);
|
|
||||||
ThrowCompletionOr<Optional<Value>> iterator_step_value(VM&, IteratorRecord&);
|
|
||||||
ThrowCompletionOr<bool> iterator_complete(VM&, Object& iterator_result);
|
ThrowCompletionOr<bool> iterator_complete(VM&, Object& iterator_result);
|
||||||
ThrowCompletionOr<Value> iterator_value(VM&, Object& iterator_result);
|
ThrowCompletionOr<Value> iterator_value(VM&, Object& iterator_result);
|
||||||
|
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM&, IteratorRecord&);
|
||||||
|
ThrowCompletionOr<Optional<Value>> iterator_step_value(VM&, IteratorRecord&);
|
||||||
Completion iterator_close(VM&, IteratorRecord const&, Completion);
|
Completion iterator_close(VM&, IteratorRecord const&, Completion);
|
||||||
Completion async_iterator_close(VM&, IteratorRecord const&, Completion);
|
Completion async_iterator_close(VM&, IteratorRecord const&, Completion);
|
||||||
NonnullGCPtr<Object> create_iterator_result_object(VM&, Value, bool done);
|
NonnullGCPtr<Object> create_iterator_result_object(VM&, Value, bool done);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -16,7 +16,7 @@ namespace JS {
|
||||||
|
|
||||||
JS_DEFINE_ALLOCATOR(IteratorConstructor);
|
JS_DEFINE_ALLOCATOR(IteratorConstructor);
|
||||||
|
|
||||||
// 3.1.1.1 The Iterator Constructor, https://tc39.es/proposal-iterator-helpers/#sec-iterator-constructor
|
// 27.1.3.1 The Iterator Constructor, https://tc39.es/ecma262/#sec-iterator-constructor
|
||||||
IteratorConstructor::IteratorConstructor(Realm& realm)
|
IteratorConstructor::IteratorConstructor(Realm& realm)
|
||||||
: Base(realm.vm().names.Iterator.as_string(), realm.intrinsics().function_prototype())
|
: Base(realm.vm().names.Iterator.as_string(), realm.intrinsics().function_prototype())
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ void IteratorConstructor::initialize(Realm& realm)
|
||||||
|
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
|
|
||||||
// 3.1.1.2.1 Iterator.prototype, https://tc39.es/proposal-iterator-helpers/#sec-iterator.prototype
|
// 27.1.3.2.2 Iterator.prototype Iterator.prototype, https://tc39.es/ecma262/#sec-iterator.prototype
|
||||||
define_direct_property(vm.names.prototype, realm.intrinsics().iterator_prototype(), 0);
|
define_direct_property(vm.names.prototype, realm.intrinsics().iterator_prototype(), 0);
|
||||||
|
|
||||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||||
|
@ -37,7 +37,7 @@ void IteratorConstructor::initialize(Realm& realm)
|
||||||
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.1.1.1 Iterator ( ), https://tc39.es/proposal-iterator-helpers/#sec-iterator
|
// 27.1.3.1.1 Iterator ( ), https://tc39.es/ecma262/#sec-iterator
|
||||||
ThrowCompletionOr<Value> IteratorConstructor::call()
|
ThrowCompletionOr<Value> IteratorConstructor::call()
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
|
@ -46,7 +46,7 @@ ThrowCompletionOr<Value> IteratorConstructor::call()
|
||||||
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, "Iterator");
|
return vm.throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, "Iterator");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.1.1.1 Iterator ( ), https://tc39.es/proposal-iterator-helpers/#sec-iterator
|
// 27.1.3.1.1 Iterator ( ), https://tc39.es/ecma262/#sec-iterator
|
||||||
ThrowCompletionOr<NonnullGCPtr<Object>> IteratorConstructor::construct(FunctionObject& new_target)
|
ThrowCompletionOr<NonnullGCPtr<Object>> IteratorConstructor::construct(FunctionObject& new_target)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
|
@ -59,15 +59,15 @@ ThrowCompletionOr<NonnullGCPtr<Object>> IteratorConstructor::construct(FunctionO
|
||||||
return TRY(ordinary_create_from_constructor<Iterator>(vm, new_target, &Intrinsics::iterator_prototype));
|
return TRY(ordinary_create_from_constructor<Iterator>(vm, new_target, &Intrinsics::iterator_prototype));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.1.2.2 Iterator.from ( O ), https://tc39.es/proposal-iterator-helpers/#sec-iterator.from
|
// 27.1.3.2.1 Iterator.from ( O ), https://tc39.es/ecma262/#sec-iterator.from
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorConstructor::from)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorConstructor::from)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
auto object = vm.argument(0);
|
auto object = vm.argument(0);
|
||||||
|
|
||||||
// 1. Let iteratorRecord be ? GetIteratorFlattenable(O, iterate-strings).
|
// 1. Let iteratorRecord be ? GetIteratorFlattenable(O, iterate-string-primitives).
|
||||||
auto iterator_record = TRY(get_iterator_flattenable(vm, object, StringHandling::IterateStrings));
|
auto iterator_record = TRY(get_iterator_flattenable(vm, object, PrimitiveHandling::IterateStringPrimitives));
|
||||||
|
|
||||||
// 2. Let hasInstance be ? OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]).
|
// 2. Let hasInstance be ? OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]).
|
||||||
auto has_instance = TRY(ordinary_has_instance(vm, iterator_record->iterator, realm.intrinsics().iterator_constructor()));
|
auto has_instance = TRY(ordinary_has_instance(vm, iterator_record->iterator, realm.intrinsics().iterator_constructor()));
|
||||||
|
@ -80,7 +80,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorConstructor::from)
|
||||||
|
|
||||||
// 4. Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
|
// 4. Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, « [[Iterated]] »).
|
||||||
// 5. Set wrapper.[[Iterated]] to iteratorRecord.
|
// 5. Set wrapper.[[Iterated]] to iteratorRecord.
|
||||||
auto wrapper = Iterator::create(realm, realm.intrinsics().wrap_for_valid_iterator_prototype(), move(iterator_record));
|
auto wrapper = Iterator::create(realm, realm.intrinsics().wrap_for_valid_iterator_prototype(), iterator_record);
|
||||||
|
|
||||||
// 6. Return wrapper.
|
// 6. Return wrapper.
|
||||||
return wrapper;
|
return wrapper;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +12,7 @@ namespace JS {
|
||||||
|
|
||||||
JS_DEFINE_ALLOCATOR(IteratorHelperPrototype);
|
JS_DEFINE_ALLOCATOR(IteratorHelperPrototype);
|
||||||
|
|
||||||
|
// 27.1.2.1 The %IteratorHelperPrototype% Object, https://tc39.es/ecma262/#sec-%iteratorhelperprototype%-object
|
||||||
IteratorHelperPrototype::IteratorHelperPrototype(Realm& realm)
|
IteratorHelperPrototype::IteratorHelperPrototype(Realm& realm)
|
||||||
: PrototypeObject(realm.intrinsics().iterator_prototype())
|
: PrototypeObject(realm.intrinsics().iterator_prototype())
|
||||||
{
|
{
|
||||||
|
@ -26,11 +27,11 @@ void IteratorHelperPrototype::initialize(Realm& realm)
|
||||||
define_native_function(realm, vm.names.next, next, 0, attr);
|
define_native_function(realm, vm.names.next, next, 0, attr);
|
||||||
define_native_function(realm, vm.names.return_, return_, 0, attr);
|
define_native_function(realm, vm.names.return_, return_, 0, attr);
|
||||||
|
|
||||||
// 3.1.2.1.3 %IteratorHelperPrototype% [ @@toStringTag ], https://tc39.es/proposal-iterator-helpers/#sec-%iteratorhelperprototype%-@@tostringtag
|
// 27.1.2.1.3 %IteratorHelperPrototype% [ %Symbol.toStringTag% ], https://tc39.es/ecma262/#sec-%iteratorhelperprototype%-%symbol.tostringtag%
|
||||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Iterator Helper"_string), Attribute::Configurable);
|
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Iterator Helper"_string), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.2.1.1 %IteratorHelperPrototype%.next ( ), https://tc39.es/proposal-iterator-helpers/#sec-%iteratorhelperprototype%.next
|
// 27.1.2.1.1 %IteratorHelperPrototype%.next ( ), https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.next
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::next)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::next)
|
||||||
{
|
{
|
||||||
auto iterator = TRY(typed_this_object(vm));
|
auto iterator = TRY(typed_this_object(vm));
|
||||||
|
@ -39,7 +40,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::next)
|
||||||
return iterator->resume(vm, js_undefined(), "Iterator Helper"sv);
|
return iterator->resume(vm, js_undefined(), "Iterator Helper"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.2.1.2 %IteratorHelperPrototype%.return ( ), https://tc39.es/proposal-iterator-helpers/#sec-%iteratorhelperprototype%.return
|
// 27.1.2.1.2 %IteratorHelperPrototype%.return ( ), https://tc39.es/ecma262/#sec-%iteratorhelperprototype%.return
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::return_)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorHelperPrototype::return_)
|
||||||
{
|
{
|
||||||
// 1. Let O be this value.
|
// 1. Let O be this value.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
||||||
|
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -32,33 +33,26 @@ void IteratorPrototype::initialize(Realm& realm)
|
||||||
|
|
||||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||||
define_native_function(realm, vm.well_known_symbol_iterator(), symbol_iterator, 0, attr);
|
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.drop, drop, 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.some, some, 1, attr);
|
|
||||||
define_native_function(realm, vm.names.every, every, 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.find, find, 1, attr);
|
||||||
|
define_native_function(realm, vm.names.flatMap, flat_map, 1, 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.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);
|
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);
|
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
|
// 27.1.4.1.1 get Iterator.prototype.constructor, https://tc39.es/ecma262/#sec-get-iterator.prototype.constructor
|
||||||
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
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
@ -67,7 +61,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_getter)
|
||||||
return realm.intrinsics().iterator_constructor();
|
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)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
@ -79,189 +73,7 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::constructor_setter)
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.3.2 Iterator.prototype.map ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.map
|
// 27.1.4.2 Iterator.prototype.drop ( limit ), https://tc39.es/ecma262/#sec-iterator.prototype.drop
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::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));
|
|
||||||
|
|
||||||
// 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> {
|
|
||||||
auto& iterated = iterator.underlying_iterator();
|
|
||||||
|
|
||||||
// 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)));
|
|
||||||
|
|
||||||
// 8. Return result.
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3.1.3.3 Iterator.prototype.filter ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.filter
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::filter)
|
|
||||||
{
|
|
||||||
auto& realm = *vm.current_realm();
|
|
||||||
|
|
||||||
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. 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 closure be a new Abstract Closure with no parameters that captures iterated and predicate and performs the following steps when called:
|
|
||||||
auto closure = JS::create_heap_function(realm.heap(), [predicate = NonnullGCPtr { predicate.as_function() }](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
|
||||||
auto& iterated = iterator.underlying_iterator();
|
|
||||||
|
|
||||||
// a. Let counter be 0.
|
|
||||||
|
|
||||||
// b. Repeat,
|
|
||||||
while (true) {
|
|
||||||
// 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 selected be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
|
||||||
auto selected = call(vm, *predicate, js_undefined(), *value, Value { iterator.counter() });
|
|
||||||
|
|
||||||
// iv. IfAbruptCloseIterator(selected, iterated).
|
|
||||||
if (selected.is_error())
|
|
||||||
return iterator.close_result(vm, selected.release_error());
|
|
||||||
|
|
||||||
// vi. Set counter to counter + 1.
|
|
||||||
// NOTE: We do this step early to ensure it occurs before returning.
|
|
||||||
iterator.increment_counter();
|
|
||||||
|
|
||||||
// v. If ToBoolean(selected) is true, then
|
|
||||||
if (selected.value().to_boolean()) {
|
|
||||||
// 1. Let completion be Completion(Yield(value)).
|
|
||||||
// 2. IfAbruptCloseIterator(completion, iterated).
|
|
||||||
return iterator.result(*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)));
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
// iv. 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)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
@ -324,12 +136,161 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
|
||||||
|
|
||||||
// 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
// 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
||||||
// 10. Set result.[[UnderlyingIterator]] to iterated.
|
// 10. Set result.[[UnderlyingIterator]] to iterated.
|
||||||
auto result = TRY(IteratorHelper::create(realm, move(iterated), move(closure)));
|
auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
||||||
|
|
||||||
// 11. Return result.
|
// 11. Return result.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
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. 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 closure be a new Abstract Closure with no parameters that captures iterated and predicate and performs the following steps when called:
|
||||||
|
auto closure = JS::create_heap_function(realm.heap(), [predicate = NonnullGCPtr { predicate.as_function() }](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
||||||
|
auto& iterated = iterator.underlying_iterator();
|
||||||
|
|
||||||
|
// a. Let counter be 0.
|
||||||
|
|
||||||
|
// b. Repeat,
|
||||||
|
while (true) {
|
||||||
|
// 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 selected be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
||||||
|
auto selected = call(vm, *predicate, js_undefined(), *value, Value { iterator.counter() });
|
||||||
|
|
||||||
|
// iv. IfAbruptCloseIterator(selected, iterated).
|
||||||
|
if (selected.is_error())
|
||||||
|
return iterator.close_result(vm, selected.release_error());
|
||||||
|
|
||||||
|
// vi. Set counter to counter + 1.
|
||||||
|
// NOTE: We do this step early to ensure it occurs before returning.
|
||||||
|
iterator.increment_counter();
|
||||||
|
|
||||||
|
// v. If ToBoolean(selected) is true, then
|
||||||
|
if (selected.value().to_boolean()) {
|
||||||
|
// 1. Let completion be Completion(Yield(value)).
|
||||||
|
// 2. IfAbruptCloseIterator(completion, iterated).
|
||||||
|
return iterator.result(*value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
||||||
|
// 7. Set result.[[UnderlyingIterator]] to iterated.
|
||||||
|
auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
||||||
|
|
||||||
|
// 8. Return result.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 27.1.4.5 Iterator.prototype.find ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.find
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::find)
|
||||||
|
{
|
||||||
|
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. 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 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)));
|
||||||
|
|
||||||
|
// f. Set counter to counter + 1.
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class FlatMapIterator : public Cell {
|
class FlatMapIterator : public Cell {
|
||||||
JS_CELL(FlatMapIterator, Cell);
|
JS_CELL(FlatMapIterator, Cell);
|
||||||
JS_DECLARE_ALLOCATOR(FlatMapIterator);
|
JS_DECLARE_ALLOCATOR(FlatMapIterator);
|
||||||
|
@ -385,8 +346,8 @@ private:
|
||||||
if (mapped.is_error())
|
if (mapped.is_error())
|
||||||
return iterator.close_result(vm, mapped.release_error());
|
return iterator.close_result(vm, mapped.release_error());
|
||||||
|
|
||||||
// v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-strings)).
|
// v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-primitives)).
|
||||||
auto inner_iterator = get_iterator_flattenable(vm, mapped.release_value(), StringHandling::RejectStrings);
|
auto inner_iterator = get_iterator_flattenable(vm, mapped.release_value(), PrimitiveHandling::RejectPrimitives);
|
||||||
|
|
||||||
// vi. IfAbruptCloseIterator(innerIterator, iterated).
|
// vi. IfAbruptCloseIterator(innerIterator, iterated).
|
||||||
if (inner_iterator.is_error())
|
if (inner_iterator.is_error())
|
||||||
|
@ -434,7 +395,7 @@ private:
|
||||||
|
|
||||||
JS_DEFINE_ALLOCATOR(FlatMapIterator);
|
JS_DEFINE_ALLOCATOR(FlatMapIterator);
|
||||||
|
|
||||||
// 3.1.3.6 Iterator.prototype.flatMap ( mapper ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.flatmap
|
// 27.1.4.6 Iterator.prototype.flatMap ( mapper ), https://tc39.es/ecma262/#sec-iterator.prototype.flatmap
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
@ -466,13 +427,109 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::flat_map)
|
||||||
|
|
||||||
// 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
// 6. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
||||||
// 7. Set result.[[UnderlyingIterator]] to iterated.
|
// 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, move(abrupt_closure)));
|
||||||
|
|
||||||
// 8. Return result.
|
// 8. Return result.
|
||||||
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.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));
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
// 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> {
|
||||||
|
auto& iterated = iterator.underlying_iterator();
|
||||||
|
|
||||||
|
// 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, iterated, closure));
|
||||||
|
|
||||||
|
// 8. Return result.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 27.1.4.9 Iterator.prototype.reduce ( reducer [ , initialValue ] ), https://tc39.es/ecma262/#sec-iterator.prototype.reduce
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
|
||||||
{
|
{
|
||||||
auto reducer = vm.argument(0);
|
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
|
// 27.1.4.10 Iterator.prototype.some ( predicate ), https://tc39.es/ecma262/#sec-iterator.prototype.some
|
||||||
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
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::some)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::some)
|
||||||
{
|
{
|
||||||
auto predicate = vm.argument(0);
|
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
|
// 27.1.4.11 Iterator.prototype.take ( limit ), https://tc39.es/ecma262/#sec-iterator.prototype.take
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::every)
|
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.
|
// 1. Let O be the this value.
|
||||||
// 2. If O is not an Object, throw a TypeError exception.
|
// 2. If O is not an Object, throw a TypeError exception.
|
||||||
auto object = TRY(this_object(vm));
|
auto object = TRY(this_object(vm));
|
||||||
|
|
||||||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
// 3. Let numLimit be ? ToNumber(limit).
|
||||||
if (!predicate.is_function())
|
auto numeric_limit = TRY(limit.to_number(vm));
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotAFunction, "predicate"sv);
|
|
||||||
|
|
||||||
// 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));
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
||||||
|
|
||||||
// 5. Let counter be 0.
|
// 8. Let closure be a new Abstract Closure with no parameters that captures iterated and integerLimit and performs the following steps when called:
|
||||||
size_t counter = 0;
|
auto closure = JS::create_heap_function(realm.heap(), [integer_limit](VM& vm, IteratorHelper& iterator) -> ThrowCompletionOr<Value> {
|
||||||
|
auto& iterated = iterator.underlying_iterator();
|
||||||
|
|
||||||
// 6. Repeat,
|
// a. Let remaining be integerLimit.
|
||||||
while (true) {
|
// b. Repeat,
|
||||||
// a. Let value be ? IteratorStepValue(iterated).
|
|
||||||
|
// 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));
|
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())
|
if (!value.has_value())
|
||||||
return Value { true };
|
return iterator.result(js_undefined());
|
||||||
|
|
||||||
// c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
// v. Let completion be Completion(Yield(value)).
|
||||||
auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
|
// vi. IfAbruptCloseIterator(completion, iterated).
|
||||||
|
return iterator.result(*value);
|
||||||
|
});
|
||||||
|
|
||||||
// d. IfAbruptCloseIterator(result, iterated).
|
// 9. Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
|
||||||
if (result.is_error())
|
// 10. Set result.[[UnderlyingIterator]] to iterated.
|
||||||
return *TRY(iterator_close(vm, iterated, result.release_error()));
|
auto result = TRY(IteratorHelper::create(realm, iterated, closure));
|
||||||
|
|
||||||
// e. If ToBoolean(result) is false, return ? IteratorClose(iterated, NormalCompletion(false)).
|
// 11. Return result.
|
||||||
if (!result.value().to_boolean())
|
return result;
|
||||||
return *TRY(iterator_close(vm, iterated, normal_completion(Value { false })));
|
|
||||||
|
|
||||||
// f. Set counter to counter + 1.
|
|
||||||
++counter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.3.12 Iterator.prototype.find ( predicate ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.find
|
// 27.1.4.12 Iterator.prototype.toArray ( ), https://tc39.es/ecma262/#sec-iterator.prototype.toarray
|
||||||
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::find)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_array)
|
||||||
{
|
{
|
||||||
auto predicate = vm.argument(0);
|
auto& realm = *vm.current_realm();
|
||||||
|
|
||||||
// 1. Let O be the this value.
|
// 1. Let O be the this value.
|
||||||
// 2. If O is not an Object, throw a TypeError exception.
|
// 2. If O is not an Object, throw a TypeError exception.
|
||||||
auto object = TRY(this_object(vm));
|
auto object = TRY(this_object(vm));
|
||||||
|
|
||||||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
// 3. Let iterated be ? GetIteratorDirect(O).
|
||||||
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));
|
auto iterated = TRY(get_iterator_direct(vm, object));
|
||||||
|
|
||||||
// 5. Let counter be 0.
|
// 4. Let items be a new empty List.
|
||||||
size_t counter = 0;
|
Vector<Value> items;
|
||||||
|
|
||||||
// 6. Repeat,
|
// 5. Repeat,
|
||||||
while (true) {
|
while (true) {
|
||||||
// a. Let value be ? IteratorStepValue(iterated).
|
// a. Let value be ? IteratorStepValue(iterated).
|
||||||
auto value = TRY(iterator_step_value(vm, 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())
|
if (!value.has_value())
|
||||||
return js_undefined();
|
return Array::create_from(realm, items);
|
||||||
|
|
||||||
// c. Let result be Completion(Call(predicate, undefined, « value, 𝔽(counter) »)).
|
// c. Append value to items.
|
||||||
auto result = call(vm, predicate.as_function(), js_undefined(), *value, Value { counter });
|
TRY_OR_THROW_OOM(vm, items.try_append(*value));
|
||||||
|
|
||||||
// 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)));
|
|
||||||
|
|
||||||
// f. Set counter to counter + 1.
|
|
||||||
++counter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_string_tag_getter)
|
||||||
{
|
{
|
||||||
// 1. Return "Iterator".
|
// 1. Return "Iterator".
|
||||||
return PrimitiveString::create(vm, vm.names.Iterator.as_string());
|
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)
|
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_string_tag_setter)
|
||||||
{
|
{
|
||||||
auto& realm = *vm.current_realm();
|
auto& realm = *vm.current_realm();
|
||||||
|
|
|
@ -25,19 +25,19 @@ private:
|
||||||
JS_DECLARE_NATIVE_FUNCTION(constructor_getter);
|
JS_DECLARE_NATIVE_FUNCTION(constructor_getter);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(constructor_setter);
|
JS_DECLARE_NATIVE_FUNCTION(constructor_setter);
|
||||||
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(map);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(filter);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(take);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(drop);
|
JS_DECLARE_NATIVE_FUNCTION(drop);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(flat_map);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(reduce);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_array);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(for_each);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(some);
|
|
||||||
JS_DECLARE_NATIVE_FUNCTION(every);
|
JS_DECLARE_NATIVE_FUNCTION(every);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(filter);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(find);
|
JS_DECLARE_NATIVE_FUNCTION(find);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(flat_map);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(for_each);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(map);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(reduce);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(some);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(take);
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(to_array);
|
||||||
|
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_string_tag_getter);
|
JS_DECLARE_NATIVE_FUNCTION(to_string_tag_getter);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_string_tag_setter);
|
JS_DECLARE_NATIVE_FUNCTION(to_string_tag_setter);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -12,7 +12,7 @@ namespace JS {
|
||||||
|
|
||||||
JS_DEFINE_ALLOCATOR(WrapForValidIteratorPrototype);
|
JS_DEFINE_ALLOCATOR(WrapForValidIteratorPrototype);
|
||||||
|
|
||||||
// 3.1.1.2.2.1 The %WrapForValidIteratorPrototype% Object, https://tc39.es/proposal-iterator-helpers/#sec-wrapforvaliditeratorprototype-object
|
// 27.1.3.2.1.1 The %WrapForValidIteratorPrototype% Object, https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%-object
|
||||||
WrapForValidIteratorPrototype::WrapForValidIteratorPrototype(Realm& realm)
|
WrapForValidIteratorPrototype::WrapForValidIteratorPrototype(Realm& realm)
|
||||||
: PrototypeObject(realm.intrinsics().iterator_prototype())
|
: PrototypeObject(realm.intrinsics().iterator_prototype())
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ void WrapForValidIteratorPrototype::initialize(Realm& realm)
|
||||||
define_native_function(realm, vm.names.return_, return_, 0, attr);
|
define_native_function(realm, vm.names.return_, return_, 0, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.1.2.2.1.1 %WrapForValidIteratorPrototype%.next ( ), https://tc39.es/proposal-iterator-helpers/#sec-wrapforvaliditeratorprototype.next
|
// 27.1.3.2.1.1.1 %WrapForValidIteratorPrototype%.next ( ), https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.next
|
||||||
JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::next)
|
JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::next)
|
||||||
{
|
{
|
||||||
// 1. Let O be this value.
|
// 1. Let O be this value.
|
||||||
|
@ -42,7 +42,7 @@ JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::next)
|
||||||
return TRY(call(vm, iterator_record.next_method, iterator_record.iterator));
|
return TRY(call(vm, iterator_record.next_method, iterator_record.iterator));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.1.1.2.2.1.2 %WrapForValidIteratorPrototype%.return ( ), https://tc39.es/proposal-iterator-helpers/#sec-wrapforvaliditeratorprototype.return
|
// 27.1.3.2.1.1.2 %WrapForValidIteratorPrototype%.return ( ), https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.return
|
||||||
JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::return_)
|
JS_DEFINE_NATIVE_FUNCTION(WrapForValidIteratorPrototype::return_)
|
||||||
{
|
{
|
||||||
// 1. Let O be this value.
|
// 1. Let O be this value.
|
||||||
|
|
|
@ -2,7 +2,7 @@ describe("errors", () => {
|
||||||
test("called with non-Object", () => {
|
test("called with non-Object", () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
Iterator.from(Symbol.hasInstance);
|
Iterator.from(Symbol.hasInstance);
|
||||||
}).toThrowWithMessage(TypeError, "Symbol(Symbol.hasInstance) is not an object");
|
}).toThrowWithMessage(TypeError, "Symbol(Symbol.hasInstance) is not a string");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("@@iterator is not callable", () => {
|
test("@@iterator is not callable", () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue