mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 01:27:43 +00:00
LibJS+LibWeb: Refactor GetIterator to use GetIteratorFromMethod
This is an editorial change in the ECMA-262 spec. See:
956e5af
This splits the GetIterator AO into two AOs, to remove some recursion
and to (soon) remove optional parameters.
This commit is contained in:
parent
b918dcd4db
commit
5703833116
5 changed files with 111 additions and 71 deletions
|
@ -1533,8 +1533,9 @@ void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& ge
|
||||||
// 4. Initialize Si to the result of converting nextItem to an IDL value of type T.
|
// 4. Initialize Si to the result of converting nextItem to an IDL value of type T.
|
||||||
// 5. Set i to i + 1.
|
// 5. Set i to i + 1.
|
||||||
|
|
||||||
|
// FIXME: The WebIDL spec is out of date - it should be using GetIteratorFromMethod.
|
||||||
sequence_generator.append(R"~~~(
|
sequence_generator.append(R"~~~(
|
||||||
auto iterator@recursion_depth@ = TRY(JS::get_iterator(vm, @iterable_cpp_name@, JS::IteratorHint::Sync, @iterator_method_cpp_name@));
|
auto iterator@recursion_depth@ = TRY(JS::get_iterator_from_method(vm, @iterable_cpp_name@, *@iterator_method_cpp_name@));
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
if (sequence_cpp_type.sequence_storage_type == SequenceStorageType::Vector) {
|
if (sequence_cpp_type.sequence_storage_type == SequenceStorageType::Vector) {
|
||||||
|
|
|
@ -179,8 +179,8 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
|
||||||
array = MUST(Array::create(realm, 0));
|
array = MUST(Array::create(realm, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// c. Let iteratorRecord be ? GetIterator(items, sync, usingIterator).
|
// c. Let iteratorRecord be ? GetIteratorFromMethod(items, usingIterator).
|
||||||
auto iterator = TRY(get_iterator(vm, items, IteratorHint::Sync, using_iterator));
|
auto iterator = TRY(get_iterator_from_method(vm, items, *using_iterator));
|
||||||
|
|
||||||
// d. Let k be 0.
|
// d. Let k be 0.
|
||||||
// e. Repeat,
|
// e. Repeat,
|
||||||
|
@ -356,12 +356,14 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from_async)
|
||||||
// h. If usingAsyncIterator is not undefined, then
|
// h. If usingAsyncIterator is not undefined, then
|
||||||
if (using_async_iterator) {
|
if (using_async_iterator) {
|
||||||
// i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
|
// i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
|
||||||
iterator_record = TRY(get_iterator(vm, async_items, IteratorHint::Async, using_async_iterator));
|
// FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
|
||||||
|
iterator_record = TRY(get_iterator_from_method(vm, async_items, *using_async_iterator));
|
||||||
}
|
}
|
||||||
// i. Else if usingSyncIterator is not undefined, then
|
// i. Else if usingSyncIterator is not undefined, then
|
||||||
else if (using_sync_iterator) {
|
else if (using_sync_iterator) {
|
||||||
// i. Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
|
// i. Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
|
||||||
iterator_record = create_async_from_sync_iterator(vm, TRY(get_iterator(vm, async_items, IteratorHint::Sync, using_sync_iterator)));
|
// FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
|
||||||
|
iterator_record = create_async_from_sync_iterator(vm, TRY(get_iterator_from_method(vm, async_items, *using_sync_iterator)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// j. If iteratorRecord is not undefined, then
|
// j. If iteratorRecord is not undefined, then
|
||||||
|
|
|
@ -14,60 +14,69 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
// 7.4.2 GetIterator ( obj [ , hint [ , method ] ] ), https://tc39.es/ecma262/#sec-getiterator
|
// 7.4.2 GetIteratorFromMethod ( obj, method ), https://tc39.es/ecma262/#sec-getiteratorfrommethod
|
||||||
ThrowCompletionOr<IteratorRecord> get_iterator(VM& vm, Value value, IteratorHint hint, Optional<Value> method)
|
ThrowCompletionOr<IteratorRecord> get_iterator_from_method(VM& vm, Value object, NonnullGCPtr<FunctionObject> method)
|
||||||
{
|
{
|
||||||
// 1. If hint is not present, set hint to sync.
|
// 1. Let iterator be ? Call(method, obj).
|
||||||
|
auto iterator = TRY(call(vm, *method, object));
|
||||||
|
|
||||||
// 2. If method is not present, then
|
// 2. If iterator is not an Object, throw a TypeError exception.
|
||||||
if (!method.has_value()) {
|
|
||||||
// a. If hint is async, then
|
|
||||||
if (hint == IteratorHint::Async) {
|
|
||||||
// i. Set method to ? GetMethod(obj, @@asyncIterator).
|
|
||||||
auto async_method = TRY(value.get_method(vm, vm.well_known_symbol_async_iterator()));
|
|
||||||
|
|
||||||
// ii. If method is undefined, then
|
|
||||||
if (async_method == nullptr) {
|
|
||||||
// 1. Let syncMethod be ? GetMethod(obj, @@iterator).
|
|
||||||
auto sync_method = TRY(value.get_method(vm, vm.well_known_symbol_iterator()));
|
|
||||||
|
|
||||||
// 2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
|
|
||||||
auto sync_iterator_record = TRY(get_iterator(vm, value, IteratorHint::Sync, sync_method));
|
|
||||||
|
|
||||||
// 3. Return CreateAsyncFromSyncIterator(syncIteratorRecord).
|
|
||||||
return create_async_from_sync_iterator(vm, sync_iterator_record);
|
|
||||||
}
|
|
||||||
|
|
||||||
method = Value(async_method);
|
|
||||||
}
|
|
||||||
// b. Otherwise, set method to ? GetMethod(obj, @@iterator).
|
|
||||||
else {
|
|
||||||
method = TRY(value.get_method(vm, vm.well_known_symbol_iterator()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Additional type check to produce a better error message than Call().
|
|
||||||
if (!method->is_function())
|
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, value.to_string_without_side_effects()));
|
|
||||||
|
|
||||||
// 3. Let iterator be ? Call(method, obj).
|
|
||||||
auto iterator = TRY(call(vm, *method, value));
|
|
||||||
|
|
||||||
// 4. If Type(iterator) is not Object, throw a TypeError exception.
|
|
||||||
if (!iterator.is_object())
|
if (!iterator.is_object())
|
||||||
return vm.throw_completion<TypeError>(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, value.to_string_without_side_effects()));
|
return vm.throw_completion<TypeError>(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects()));
|
||||||
|
|
||||||
// 5. Let nextMethod be ? GetV(iterator, "next").
|
// 3. Let nextMethod be ? Get(iterator, "next").
|
||||||
auto next_method = TRY(iterator.get(vm, vm.names.next));
|
auto next_method = TRY(iterator.get(vm, vm.names.next));
|
||||||
|
|
||||||
// 6. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
// 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||||
auto iterator_record = IteratorRecord { .iterator = &iterator.as_object(), .next_method = next_method, .done = false };
|
auto iterator_record = IteratorRecord { .iterator = &iterator.as_object(), .next_method = next_method, .done = false };
|
||||||
|
|
||||||
// 7. Return iteratorRecord.
|
// 5. Return iteratorRecord.
|
||||||
return iterator_record;
|
return iterator_record;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.3 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext
|
// 7.4.3 GetIterator ( obj [ , hint ] ), https://tc39.es/ecma262/#sec-getiterator
|
||||||
|
ThrowCompletionOr<IteratorRecord> get_iterator(VM& vm, Value object, IteratorHint hint)
|
||||||
|
{
|
||||||
|
JS::GCPtr<FunctionObject> method;
|
||||||
|
|
||||||
|
// 1. If hint is not present, set hint to sync.
|
||||||
|
|
||||||
|
// 2. If hint is async, then
|
||||||
|
if (hint == IteratorHint::Async) {
|
||||||
|
// a. Let method be ? GetMethod(obj, @@asyncIterator).
|
||||||
|
method = TRY(object.get_method(vm, vm.well_known_symbol_async_iterator()));
|
||||||
|
|
||||||
|
// b. If method is undefined, then
|
||||||
|
if (!method) {
|
||||||
|
// i. Let syncMethod be ? GetMethod(obj, @@iterator).
|
||||||
|
auto sync_method = TRY(object.get_method(vm, vm.well_known_symbol_iterator()));
|
||||||
|
|
||||||
|
// NOTE: Additional type check to produce a better error message than Call().
|
||||||
|
if (!sync_method)
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects()));
|
||||||
|
|
||||||
|
// ii. Let syncIteratorRecord be ? GetIteratorFromMethod(obj, syncMethod).
|
||||||
|
auto sync_iterator_record = TRY(get_iterator_from_method(vm, object, *sync_method));
|
||||||
|
|
||||||
|
// iii. Return CreateAsyncFromSyncIterator(syncIteratorRecord).
|
||||||
|
return create_async_from_sync_iterator(vm, sync_iterator_record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 3. Else,
|
||||||
|
else {
|
||||||
|
// a. Let method be ? GetMethod(obj, @@iterator).
|
||||||
|
method = TRY(object.get_method(vm, vm.well_known_symbol_iterator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Additional type check to produce a better error message than Call().
|
||||||
|
if (!method)
|
||||||
|
return vm.throw_completion<TypeError>(ErrorType::NotIterable, TRY_OR_THROW_OOM(vm, object.to_string_without_side_effects()));
|
||||||
|
|
||||||
|
// 4. Return ? GetIteratorFromMethod(obj, method).
|
||||||
|
return TRY(get_iterator_from_method(vm, object, *method));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.4.4 IteratorNext ( iteratorRecord [ , value ] ), https://tc39.es/ecma262/#sec-iteratornext
|
||||||
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord const& iterator_record, Optional<Value> value)
|
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord const& iterator_record, Optional<Value> value)
|
||||||
{
|
{
|
||||||
Value result;
|
Value result;
|
||||||
|
@ -89,21 +98,21 @@ ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM& vm, IteratorRecord con
|
||||||
return result.as_object();
|
return result.as_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.4 IteratorComplete ( iterResult ), https://tc39.es/ecma262/#sec-iteratorcomplete
|
// 7.4.5 IteratorComplete ( iterResult ), 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.5 IteratorValue ( iterResult ), https://tc39.es/ecma262/#sec-iteratorvalue
|
// 7.4.6 IteratorValue ( iterResult ), 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.6 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
|
// 7.4.7 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
|
||||||
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord const& iterator_record)
|
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord const& iterator_record)
|
||||||
{
|
{
|
||||||
// 1. Let result be ? IteratorNext(iteratorRecord).
|
// 1. Let result be ? IteratorNext(iteratorRecord).
|
||||||
|
@ -120,8 +129,8 @@ ThrowCompletionOr<GCPtr<Object>> iterator_step(VM& vm, IteratorRecord const& ite
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.7 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
|
// 7.4.8 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
|
||||||
// 7.4.9 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
|
// 7.4.10 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)
|
||||||
{
|
{
|
||||||
|
@ -171,19 +180,19 @@ static Completion iterator_close_impl(VM& vm, IteratorRecord const& iterator_rec
|
||||||
return completion;
|
return completion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.7 IteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-iteratorclose
|
// 7.4.8 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.9 AsyncIteratorClose ( iteratorRecord, completion ), https://tc39.es/ecma262/#sec-asynciteratorclose
|
// 7.4.10 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.10 CreateIterResultObject ( value, done ), https://tc39.es/ecma262/#sec-createiterresultobject
|
// 7.4.11 CreateIterResultObject ( 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();
|
||||||
|
@ -201,25 +210,51 @@ NonnullGCPtr<Object> create_iterator_result_object(VM& vm, Value value, bool don
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4.12 IterableToList ( items [ , method ] ), https://tc39.es/ecma262/#sec-iterabletolist
|
// 7.4.13 IterableToList ( items [ , method ] ), https://tc39.es/ecma262/#sec-iterabletolist
|
||||||
ThrowCompletionOr<MarkedVector<Value>> iterable_to_list(VM& vm, Value iterable, Optional<Value> method)
|
ThrowCompletionOr<MarkedVector<Value>> iterable_to_list(VM& vm, Value items, GCPtr<FunctionObject> method)
|
||||||
{
|
{
|
||||||
|
IteratorRecord iterator_record;
|
||||||
|
|
||||||
|
// 1. If method is present, then
|
||||||
|
if (method) {
|
||||||
|
// a. Let iteratorRecord be ? GetIteratorFromMethod(items, method).
|
||||||
|
iterator_record = TRY(get_iterator_from_method(vm, items, *method));
|
||||||
|
}
|
||||||
|
// 2. Else,
|
||||||
|
else {
|
||||||
|
// b. Let iteratorRecord be ? GetIterator(items, sync).
|
||||||
|
iterator_record = TRY(get_iterator(vm, items, IteratorHint::Sync));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Let values be a new empty List.
|
||||||
MarkedVector<Value> values(vm.heap());
|
MarkedVector<Value> values(vm.heap());
|
||||||
|
|
||||||
(void)TRY(get_iterator_values(
|
// 4. Let next be true.
|
||||||
vm, iterable, [&](auto value) -> Optional<Completion> {
|
GCPtr<Object> next;
|
||||||
values.append(value);
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
move(method)));
|
|
||||||
|
|
||||||
return { move(values) };
|
// 5. Repeat, while next is not false,
|
||||||
|
do {
|
||||||
|
// a. Set next to ? IteratorStep(iteratorRecord).
|
||||||
|
next = TRY(iterator_step(vm, iterator_record));
|
||||||
|
|
||||||
|
// b. If next is not false, then
|
||||||
|
if (next) {
|
||||||
|
// i. Let nextValue be ? IteratorValue(next).
|
||||||
|
auto next_value = TRY(iterator_value(vm, *next));
|
||||||
|
|
||||||
|
// ii. Append nextValue to values.
|
||||||
|
TRY_OR_THROW_OOM(vm, values.try_append(next_value));
|
||||||
|
}
|
||||||
|
} while (next);
|
||||||
|
|
||||||
|
// 6. Return values.
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-standard
|
// Non-standard
|
||||||
Completion get_iterator_values(VM& vm, Value iterable, IteratorValueCallback callback, Optional<Value> method)
|
Completion get_iterator_values(VM& vm, Value iterable, IteratorValueCallback callback)
|
||||||
{
|
{
|
||||||
auto iterator_record = TRY(get_iterator(vm, iterable, IteratorHint::Sync, move(method)));
|
auto iterator_record = TRY(get_iterator(vm, iterable, IteratorHint::Sync));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto next_object = TRY(iterator_step(vm, iterator_record));
|
auto next_object = TRY(iterator_step(vm, iterator_record));
|
||||||
|
|
|
@ -22,7 +22,8 @@ enum class IteratorHint {
|
||||||
Async,
|
Async,
|
||||||
};
|
};
|
||||||
|
|
||||||
ThrowCompletionOr<IteratorRecord> get_iterator(VM&, Value, IteratorHint = IteratorHint::Sync, Optional<Value> method = {});
|
ThrowCompletionOr<IteratorRecord> get_iterator_from_method(VM&, Value, NonnullGCPtr<FunctionObject>);
|
||||||
|
ThrowCompletionOr<IteratorRecord> get_iterator(VM&, Value, IteratorHint = IteratorHint::Sync);
|
||||||
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM&, IteratorRecord const&, Optional<Value> = {});
|
ThrowCompletionOr<NonnullGCPtr<Object>> iterator_next(VM&, IteratorRecord const&, Optional<Value> = {});
|
||||||
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM&, IteratorRecord const&);
|
ThrowCompletionOr<GCPtr<Object>> iterator_step(VM&, IteratorRecord const&);
|
||||||
ThrowCompletionOr<bool> iterator_complete(VM&, Object& iterator_result);
|
ThrowCompletionOr<bool> iterator_complete(VM&, Object& iterator_result);
|
||||||
|
@ -30,9 +31,9 @@ ThrowCompletionOr<Value> iterator_value(VM&, Object& iterator_result);
|
||||||
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);
|
||||||
ThrowCompletionOr<MarkedVector<Value>> iterable_to_list(VM&, Value iterable, Optional<Value> method = {});
|
ThrowCompletionOr<MarkedVector<Value>> iterable_to_list(VM&, Value iterable, GCPtr<FunctionObject> method = {});
|
||||||
|
|
||||||
using IteratorValueCallback = Function<Optional<Completion>(Value)>;
|
using IteratorValueCallback = Function<Optional<Completion>(Value)>;
|
||||||
Completion get_iterator_values(VM&, Value iterable, IteratorValueCallback callback, Optional<Value> method = {});
|
Completion get_iterator_values(VM&, Value iterable, IteratorValueCallback callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,8 @@ static JS::ThrowCompletionOr<Vector<String>> convert_value_to_sequence_of_string
|
||||||
// https://webidl.spec.whatwg.org/#create-sequence-from-iterable
|
// https://webidl.spec.whatwg.org/#create-sequence-from-iterable
|
||||||
// To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
|
// To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
|
||||||
// 1. Let iter be ? GetIterator(iterable, sync, method).
|
// 1. Let iter be ? GetIterator(iterable, sync, method).
|
||||||
auto iterator = TRY(JS::get_iterator(vm, value, JS::IteratorHint::Sync, method));
|
// FIXME: The WebIDL spec is out of date - it should be using GetIteratorFromMethod.
|
||||||
|
auto iterator = TRY(JS::get_iterator_from_method(vm, value, *method));
|
||||||
|
|
||||||
// 2. Initialize i to be 0.
|
// 2. Initialize i to be 0.
|
||||||
Vector<String> sequence_of_strings;
|
Vector<String> sequence_of_strings;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue