LibWeb/Bindings: Handle variadic conversion at the top level
Move variadic JS-to-C++ handling out of the per-type conversion helpers and into the top-level conversion path. This allows us to centrlize the logic, and also adds support to variadic to more types.
This commit is contained in:
parent
3d35517734
commit
c8a650ec1f
1 changed files with 58 additions and 57 deletions
|
|
@ -950,7 +950,48 @@ static void generate_optional_to_cpp(SourceGenerator& generator, ParameterType&
|
|||
}
|
||||
|
||||
template<typename ParameterType>
|
||||
static void generate_to_string(SourceGenerator& scoped_generator, ParameterType const& parameter, bool variadic)
|
||||
static void generate_variadic_to_cpp(SourceGenerator& generator, ParameterType& parameter, ByteString const& cpp_name, Context const& context, size_t recursion_depth)
|
||||
{
|
||||
auto variadic_generator = generator.fork();
|
||||
auto variadic_cpp_type = idl_type_name_to_cpp_type(*parameter.type, context, parameter.extended_attributes);
|
||||
auto variadic_storage_type = sequence_storage_type_to_cpp_storage_type_name(variadic_cpp_type.sequence_storage_type);
|
||||
auto inner_cpp_name = ByteString::formatted("{}_item", cpp_name);
|
||||
auto value_name = ByteString::formatted("variadic_argument_{}", recursion_depth);
|
||||
|
||||
variadic_generator.set("variadic.storage_type", variadic_storage_type);
|
||||
variadic_generator.set("variadic.item_type", variadic_cpp_type.name);
|
||||
variadic_generator.set("variadic.inner_cpp_name", inner_cpp_name);
|
||||
variadic_generator.set("variadic.value_name", value_name);
|
||||
|
||||
if (variadic_cpp_type.sequence_storage_type == SequenceStorageType::RootVector) {
|
||||
variadic_generator.append(R"~~~(
|
||||
@variadic.storage_type@<@variadic.item_type@> @cpp_name@ { vm.heap() };
|
||||
)~~~");
|
||||
} else {
|
||||
variadic_generator.append(R"~~~(
|
||||
@variadic.storage_type@<@variadic.item_type@> @cpp_name@;
|
||||
)~~~");
|
||||
}
|
||||
|
||||
variadic_generator.append(R"~~~(
|
||||
if (vm.argument_count() > @js_suffix@) {
|
||||
@cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
|
||||
|
||||
for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
|
||||
auto @variadic.value_name@ = vm.argument(i);
|
||||
)~~~");
|
||||
|
||||
generate_to_cpp(variadic_generator, parameter, value_name, "", inner_cpp_name, context, false, {}, false, recursion_depth + 1);
|
||||
|
||||
variadic_generator.append(R"~~~(
|
||||
@cpp_name@.unchecked_append(move(@variadic.inner_cpp_name@));
|
||||
}
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
template<typename ParameterType>
|
||||
static void generate_to_string(SourceGenerator& scoped_generator, ParameterType const& parameter)
|
||||
{
|
||||
auto is_utf16_string = parameter.type->name().contains("Utf16"sv);
|
||||
auto is_fly_string = parameter.extended_attributes.contains("FlyString"sv);
|
||||
|
|
@ -970,35 +1011,20 @@ static void generate_to_string(SourceGenerator& scoped_generator, ParameterType
|
|||
else
|
||||
scoped_generator.set("to_string", is_utf16_string ? "to_utf16_string"sv : "to_string"sv);
|
||||
|
||||
if (variadic) {
|
||||
if (parameter.type->is_nullable()) {
|
||||
scoped_generator.append(R"~~~(
|
||||
Vector<@string_type@> @cpp_name@;
|
||||
|
||||
if (vm.argument_count() > @js_suffix@) {
|
||||
@cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
|
||||
|
||||
for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
|
||||
auto to_string_result = TRY(WebIDL::@to_string@(vm, vm.argument(i)));
|
||||
@cpp_name@.unchecked_append(move(to_string_result));
|
||||
}
|
||||
}
|
||||
)~~~");
|
||||
} else {
|
||||
if (parameter.type->is_nullable()) {
|
||||
scoped_generator.append(R"~~~(
|
||||
Optional<@string_type@> @cpp_name@;
|
||||
if (!@js_name@@js_suffix@.is_nullish()) {
|
||||
@cpp_name@ = TRY(WebIDL::@to_string@(vm, @js_name@@js_suffix@));
|
||||
}
|
||||
)~~~");
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
@string_type@ @cpp_name@;
|
||||
if (!@legacy_null_to_empty_string@ || !@js_name@@js_suffix@.is_null()) {
|
||||
@cpp_name@ = TRY(WebIDL::@to_string@(vm, @js_name@@js_suffix@));
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1365,24 +1391,11 @@ static void generate_array_buffer_view_to_cpp(SourceGenerator& scoped_generator,
|
|||
}
|
||||
}
|
||||
|
||||
static void generate_any_to_cpp(SourceGenerator& scoped_generator, bool variadic)
|
||||
static void generate_any_to_cpp(SourceGenerator& scoped_generator)
|
||||
{
|
||||
if (variadic) {
|
||||
scoped_generator.append(R"~~~(
|
||||
GC::RootVector<JS::Value> @cpp_name@ { vm.heap() };
|
||||
|
||||
if (vm.argument_count() > @js_suffix@) {
|
||||
@cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
|
||||
|
||||
for (size_t i = @js_suffix@; i < vm.argument_count(); ++i)
|
||||
@cpp_name@.unchecked_append(vm.argument(i));
|
||||
}
|
||||
)~~~");
|
||||
} else {
|
||||
scoped_generator.append(R"~~~(
|
||||
scoped_generator.append(R"~~~(
|
||||
auto @cpp_name@ = @js_name@@js_suffix@;
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
enum class ThrowOnInvalidEnumValue {
|
||||
|
|
@ -1585,7 +1598,7 @@ static void generate_sequence_to_cpp(SourceGenerator& scoped_generator, IDL::Par
|
|||
}
|
||||
|
||||
template<typename ParameterType>
|
||||
static void generate_union_to_cpp(SourceGenerator& scoped_generator, ParameterType& parameter, ByteString const& js_name, ByteString const& js_suffix, ByteString const& cpp_name, Context const& context, bool variadic, size_t recursion_depth)
|
||||
static void generate_union_to_cpp(SourceGenerator& scoped_generator, ParameterType& parameter, ByteString const& js_name, ByteString const& js_suffix, ByteString const& cpp_name, Context const& context, size_t recursion_depth)
|
||||
{
|
||||
// https://webidl.spec.whatwg.org/#es-union
|
||||
|
||||
|
|
@ -1624,8 +1637,6 @@ static void generate_union_to_cpp(SourceGenerator& scoped_generator, ParameterTy
|
|||
// This is because we cannot unconditionally throw in generate_to_cpp as generate_to_cpp is supposed to assign to a variable and then continue.
|
||||
// Note that all the other types only throw on a condition.
|
||||
|
||||
// The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic.
|
||||
|
||||
union_generator.append(R"~~~(
|
||||
auto @js_name@@js_suffix@_to_variant = [&vm, &realm](JS::Value @js_name@@js_suffix@) -> JS::ThrowCompletionOr<@union_type@> {
|
||||
// These might be unused.
|
||||
|
|
@ -2026,24 +2037,9 @@ static void generate_union_to_cpp(SourceGenerator& scoped_generator, ParameterTy
|
|||
};
|
||||
)~~~");
|
||||
|
||||
if (!variadic) {
|
||||
union_generator.append(R"~~~(
|
||||
union_generator.append(R"~~~(
|
||||
@union_type@ @cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
|
||||
)~~~");
|
||||
} else {
|
||||
union_generator.append(R"~~~(
|
||||
Vector<@union_type@> @cpp_name@;
|
||||
|
||||
if (vm.argument_count() > @js_suffix@) {
|
||||
@cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
|
||||
|
||||
for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
|
||||
auto result = TRY(@js_name@@js_suffix@_to_variant(vm.argument(i)));
|
||||
@cpp_name@.unchecked_append(move(result));
|
||||
}
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ParameterType>
|
||||
|
|
@ -2065,14 +2061,19 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
|
||||
scoped_generator.set("parameter.name", parameter.name);
|
||||
|
||||
if (optional && !variadic) {
|
||||
if (variadic) {
|
||||
generate_variadic_to_cpp(scoped_generator, parameter, acceptable_cpp_name, context, recursion_depth);
|
||||
return;
|
||||
}
|
||||
|
||||
if (optional) {
|
||||
generate_optional_to_cpp(scoped_generator, parameter, js_name, js_suffix, acceptable_cpp_name, context, optional_default_value, recursion_depth);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Add support for optional, variadic, nullable and default values to all types
|
||||
if (parameter.type->is_string()) {
|
||||
generate_to_string(scoped_generator, parameter, variadic);
|
||||
generate_to_string(scoped_generator, parameter);
|
||||
} else if (parameter.type->is_boolean() || parameter.type->is_integer()) {
|
||||
generate_to_integral(scoped_generator, parameter);
|
||||
} else if (auto const* callback_interface = callback_interface_for_type(context, parameter.type)) {
|
||||
|
|
@ -2090,7 +2091,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
} else if (parameter.type->name() == "ArrayBufferView") {
|
||||
generate_array_buffer_view_to_cpp(scoped_generator, *parameter.type);
|
||||
} else if (parameter.type->name() == "any") {
|
||||
generate_any_to_cpp(scoped_generator, variadic);
|
||||
generate_any_to_cpp(scoped_generator);
|
||||
} else if (context.enumerations.contains(parameter.type->name())) {
|
||||
// NOTE: Attribute setters return undefined instead of throwing when the string doesn't match an enum value.
|
||||
ThrowOnInvalidEnumValue throw_on_invalid = ThrowOnInvalidEnumValue::No;
|
||||
|
|
@ -2111,7 +2112,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
} else if (parameter.type->name() == "record") {
|
||||
generate_record_to_cpp(scoped_generator, as<IDL::ParameterizedType>(*parameter.type), acceptable_cpp_name, context, recursion_depth);
|
||||
} else if (is<IDL::UnionType>(*parameter.type)) {
|
||||
generate_union_to_cpp(scoped_generator, parameter, js_name, js_suffix, acceptable_cpp_name, context, variadic, recursion_depth);
|
||||
generate_union_to_cpp(scoped_generator, parameter, js_name, js_suffix, acceptable_cpp_name, context, recursion_depth);
|
||||
} else {
|
||||
dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name());
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
|||
Loading…
Reference in a new issue