LibWeb/Bindings: Reuse @@iterator method for sequence union conversion
When converting an object to a union containing a sequence, Web IDL first gets @@iterator to decide whether the sequence arm applies, then creates the sequence from the iterable using that same method. The generator instead called sequence_to_idl_value(), which repeated the @@iterator lookup. Split out create_sequence_from_iterable() and use it from union sequence/FrozenArray conversion so overridden Symbol.iterator accessors are only observed once.
This commit is contained in:
parent
d33525be65
commit
6c2ad3af02
2 changed files with 32 additions and 19 deletions
|
|
@ -743,12 +743,6 @@ def sequence_to_idl_value(
|
|||
includes: GeneratedIncludes,
|
||||
context: GenerationContext,
|
||||
) -> str:
|
||||
includes.add("LibJS/Runtime/Error.h")
|
||||
includes.add("LibJS/Runtime/Iterator.h")
|
||||
includes.add("LibJS/Runtime/Value.h")
|
||||
includes.add("LibJS/Runtime/ValueInlines.h")
|
||||
includes.add("LibWeb/Bindings/ExceptionOrUtils.h")
|
||||
|
||||
element_type = sequence_type.parameters[0]
|
||||
element_cpp_type = cpp_type_for_idl_type_details(element_type, context)
|
||||
storage_type_name = element_cpp_type.contained_storage_type.value
|
||||
|
|
@ -761,13 +755,37 @@ def sequence_to_idl_value(
|
|||
if (!{value_name}.is_object())
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, {value_name});
|
||||
|
||||
auto iterator_method0 = TRY({value_name}.get_method(vm, vm.well_known_symbol_iterator()));
|
||||
if (!iterator_method0)
|
||||
auto method = TRY({value_name}.get_method(vm, vm.well_known_symbol_iterator()));
|
||||
if (!method)
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotIterable, {value_name});
|
||||
|
||||
return TRY({create_sequence_from_iterable(sequence_type, identifier, value_name, "method", includes, context)});
|
||||
}}()"""
|
||||
|
||||
|
||||
# 3.2.21.1. Creating a sequence from an iterable, https://webidl.spec.whatwg.org/#create-sequence-from-iterable
|
||||
def create_sequence_from_iterable(
|
||||
sequence_type: IDLParameterizedType,
|
||||
identifier: str,
|
||||
value_name: str,
|
||||
iterator_method_name: str,
|
||||
includes: GeneratedIncludes,
|
||||
context: GenerationContext,
|
||||
) -> str:
|
||||
includes.add("LibJS/Runtime/Error.h")
|
||||
includes.add("LibJS/Runtime/Iterator.h")
|
||||
includes.add("LibJS/Runtime/Value.h")
|
||||
includes.add("LibJS/Runtime/ValueInlines.h")
|
||||
includes.add("LibWeb/Bindings/ExceptionOrUtils.h")
|
||||
|
||||
element_type = sequence_type.parameters[0]
|
||||
element_cpp_type = cpp_type_for_idl_type_details(element_type, context)
|
||||
storage_type_name = element_cpp_type.contained_storage_type.value
|
||||
|
||||
return f"""[&]() -> JS::ThrowCompletionOr<{storage_type_name}<{element_cpp_type.name}>> {{
|
||||
// To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
|
||||
// 1. Let iteratorRecord be ? GetIteratorFromMethod(iterable, method).
|
||||
auto iterator0 = TRY(JS::get_iterator_from_method(vm, {value_name}, *iterator_method0));
|
||||
auto iterator = TRY(JS::get_iterator_from_method(vm, {value_name}, *{iterator_method_name}));
|
||||
|
||||
{storage_type_name}<{element_cpp_type.name}> sequence;
|
||||
|
||||
|
|
@ -775,7 +793,7 @@ def sequence_to_idl_value(
|
|||
// 3. Repeat
|
||||
for (;;) {{
|
||||
// 1. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
auto next = TRY(JS::iterator_step_value(vm, iterator0));
|
||||
auto next = TRY(JS::iterator_step_value(vm, iterator));
|
||||
|
||||
// 2. If next is done, then return an IDL sequence value of type sequence<T> of length i, where the value of the element at index j is Sj.
|
||||
if (!next.has_value())
|
||||
|
|
@ -1045,30 +1063,26 @@ def union_to_idl_value(
|
|||
# FIXME: 11.1 If types includes an async sequence type, then
|
||||
# 11.2. If types includes a sequence type, then
|
||||
if types.sequence_type is not None:
|
||||
sequence_conversion = sequence_to_idl_value(types.sequence_type, identifier, value_name, includes, context)
|
||||
append(f"""
|
||||
// 1. Let method be ? GetMethod(V, @@iterator).
|
||||
auto method = TRY({value_name}.get_method(vm, vm.well_known_symbol_iterator()));
|
||||
|
||||
// 2. If method is not undefined, return the result of creating a sequence of that type from V and method.
|
||||
if (method) {{
|
||||
auto sequence_union_type = TRY({sequence_conversion});
|
||||
auto sequence_union_type = TRY({create_sequence_from_iterable(types.sequence_type, identifier, value_name, "method", includes, context)});
|
||||
return {variant_type} {{ sequence_union_type }};
|
||||
}}
|
||||
|
||||
""")
|
||||
# 11.3. If types includes a frozen array type, then
|
||||
if types.frozen_array_type is not None:
|
||||
frozen_array_conversion = sequence_to_idl_value(
|
||||
types.frozen_array_type, identifier, value_name, includes, context
|
||||
)
|
||||
append(f"""
|
||||
// 1. Let method be ? GetMethod(V, @@iterator).
|
||||
auto frozen_array_method = TRY({value_name}.get_method(vm, vm.well_known_symbol_iterator()));
|
||||
|
||||
// 2. If method is not undefined, return the result of creating a frozen array of that type from V and method.
|
||||
if (frozen_array_method) {{
|
||||
auto frozen_array_union_type = TRY({frozen_array_conversion});
|
||||
auto frozen_array_union_type = TRY({create_sequence_from_iterable(types.frozen_array_type, identifier, value_name, "frozen_array_method", includes, context)});
|
||||
return {variant_type} {{ frozen_array_union_type }};
|
||||
}}
|
||||
""")
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ Harness status: OK
|
|||
|
||||
Found 8 tests
|
||||
|
||||
7 Pass
|
||||
1 Fail
|
||||
8 Pass
|
||||
Pass An array
|
||||
Pass A generator
|
||||
Pass An array with an overridden Symbol.iterator
|
||||
Fail An object with an overriden Symbol.iterator
|
||||
Pass An object with an overriden Symbol.iterator
|
||||
Pass An array with an overridden Symbol.iterator on the prototype
|
||||
Pass An array with an overridden %ArrayIterator%.prototype.next
|
||||
Pass A holey array with fallback to an accessor on the prototype
|
||||
|
|
|
|||
Loading…
Reference in a new issue