diff options
author | Luke Wilde <lukew@serenityos.org> | 2023-02-17 18:56:12 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-02-18 01:23:36 +0100 |
commit | c0f22065abe2c032ce61afba727d38b95cffa9dd (patch) | |
tree | 9faf59b80ab459bab29b20c917e1f63901ab7c00 | |
parent | 84c7af4dcb9227ade86b6a5c057de936b77c9e45 (diff) | |
download | serenity-c0f22065abe2c032ce61afba727d38b95cffa9dd.zip |
LibWeb: Add an extended attribute that makes interfaces use AK::String
Adding the [UseNewAKString] extended attribute to an interface will
cause all IDL string types to use String instead of DeprecatedString.
This is done on an per interface level instead of per type/parameter
because:
- It's much simpler to implement, as the generators can already access
the interface's extended attributes. Doing it per type/parameter
would mean parsing and piping extended attributes for each type that
doesn't already take extended attributes, such as unions.
- Allows more incremental adoption of AK::String. For example, adding
[UseNewAKString] to BodyInit would require refactoring Request,
Response and XMLHttpRequest to AK::String in one swoop. Doing it on
the interface allows you to convert just XHR and its dependencies at
once, for example.
- Simple string return types (i.e. not parameterised or not in a union)
already accept any of the string types JS::PrimitiveString::create
accepts. For example, you can add [UseNewAKString] to DOMStringMap to
convert Element attributes to AK::String and still return AK::String
from get_attribute, without adding [UseNewAKString] to Element.
- Adding [UseNewAKString] to one function typically means adding it to
a bunch of other functions, if not the rest of them. For example,
adding [UseNewAKString] to the parameters FormData.append would
either mean converting AK::String to AK::DeprecatedString or storing
the AK::String as-is, making the other functions of FormData have to
convert back from AK::String or also support AK::String.
-rw-r--r-- | Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp | 121 |
1 files changed, 91 insertions, 30 deletions
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index d0d053bed6..8e4f0360f5 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -101,8 +101,12 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface) if (is_platform_object(type)) return { .name = DeprecatedString::formatted("JS::Handle<{}>", type.name()), .sequence_storage_type = SequenceStorageType::MarkedVector }; - if (type.is_string()) + if (type.is_string()) { + if (interface.extended_attributes.contains("UseNewAKString")) + return { .name = "String", .sequence_storage_type = SequenceStorageType::Vector }; + return { .name = "DeprecatedString", .sequence_storage_type = SequenceStorageType::Vector }; + } if (type.name() == "double" && !type.is_nullable()) return { .name = "double", .sequence_storage_type = SequenceStorageType::Vector }; @@ -251,23 +255,10 @@ static void emit_includes_for_all_imports(auto& interface, auto& generator, bool } template<typename ParameterType> -static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, DeprecatedString const& js_name, DeprecatedString const& js_suffix, DeprecatedString const& cpp_name, IDL::Interface const& interface, bool legacy_null_to_empty_string = false, bool optional = false, Optional<DeprecatedString> optional_default_value = {}, bool variadic = false, size_t recursion_depth = 0) +static void generate_to_deprecated_string(SourceGenerator& scoped_generator, ParameterType const& parameter, bool variadic, bool optional, Optional<DeprecatedString> const& optional_default_value) { - auto scoped_generator = generator.fork(); - auto acceptable_cpp_name = make_input_acceptable_cpp(cpp_name); - scoped_generator.set("cpp_name", acceptable_cpp_name); - scoped_generator.set("js_name", js_name); - scoped_generator.set("js_suffix", js_suffix); - scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false"); - scoped_generator.set("parameter.type.name", parameter.type->name()); - - if (optional_default_value.has_value()) - scoped_generator.set("parameter.optional_default_value", *optional_default_value); - - // FIXME: Add support for optional, variadic, nullable and default values to all types - if (parameter.type->is_string()) { - if (variadic) { - scoped_generator.append(R"~~~( + if (variadic) { + scoped_generator.append(R"~~~( Vector<DeprecatedString> @cpp_name@; @cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@); @@ -276,9 +267,9 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@.append(move(to_string_result)); } )~~~"); - } else if (!optional) { - if (!parameter.type->is_nullable()) { - scoped_generator.append(R"~~~( + } else if (!optional) { + if (!parameter.type->is_nullable()) { + scoped_generator.append(R"~~~( DeprecatedString @cpp_name@; if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) { @cpp_name@ = DeprecatedString::empty(); @@ -286,15 +277,15 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@ = TRY(@js_name@@js_suffix@.to_deprecated_string(vm)); } )~~~"); - } else { - scoped_generator.append(R"~~~( + } else { + scoped_generator.append(R"~~~( DeprecatedString @cpp_name@; if (!@js_name@@js_suffix@.is_nullish()) @cpp_name@ = TRY(@js_name@@js_suffix@.to_deprecated_string(vm)); )~~~"); - } - } else { - scoped_generator.append(R"~~~( + } + } else { + scoped_generator.append(R"~~~( DeprecatedString @cpp_name@; if (!@js_name@@js_suffix@.is_undefined()) { if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) @@ -302,16 +293,86 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter else @cpp_name@ = TRY(@js_name@@js_suffix@.to_deprecated_string(vm)); })~~~"); - if (optional_default_value.has_value() && (!parameter.type->is_nullable() || optional_default_value.value() != "null")) { - scoped_generator.append(R"~~~( else { + if (optional_default_value.has_value() && (!parameter.type->is_nullable() || optional_default_value.value() != "null")) { + scoped_generator.append(R"~~~( else { @cpp_name@ = @parameter.optional_default_value@; } )~~~"); - } else { - scoped_generator.append(R"~~~( + } else { + scoped_generator.append(R"~~~( +)~~~"); + } + } +} + +template<typename ParameterType> +static void generate_to_new_string(SourceGenerator& scoped_generator, ParameterType const& parameter, bool variadic, bool optional, Optional<DeprecatedString> const& optional_default_value) +{ + if (variadic) { + scoped_generator.append(R"~~~( + Vector<String> @cpp_name@; + @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(vm.argument(i).to_string(vm)); + @cpp_name@.append(move(to_string_result)); + } +)~~~"); + } else if (!optional) { + if (!parameter.type->is_nullable()) { + scoped_generator.append(R"~~~( + String @cpp_name@; + if (!@legacy_null_to_empty_string@ || !@js_name@@js_suffix@.is_null()) { + @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm)); + } +)~~~"); + } else { + scoped_generator.append(R"~~~( + Optional<String> @cpp_name@; + if (!@js_name@@js_suffix@.is_nullish()) + @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm)); +)~~~"); + } + } else { + scoped_generator.append(R"~~~( + Optional<String> @cpp_name@; + if (!@js_name@@js_suffix@.is_undefined()) { + if (!@legacy_null_to_empty_string@ || !@js_name@@js_suffix@.is_null()) + @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm)); + })~~~"); + if (optional_default_value.has_value() && (!parameter.type->is_nullable() || optional_default_value.value() != "null")) { + scoped_generator.append(R"~~~( else { + @cpp_name@ = TRY_OR_THROW_OOM(vm, String::from_utf8(@parameter.optional_default_value@)); + } +)~~~"); + } else { + scoped_generator.append(R"~~~( )~~~"); - } } + } +} + +template<typename ParameterType> +static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, DeprecatedString const& js_name, DeprecatedString const& js_suffix, DeprecatedString const& cpp_name, IDL::Interface const& interface, bool legacy_null_to_empty_string = false, bool optional = false, Optional<DeprecatedString> optional_default_value = {}, bool variadic = false, size_t recursion_depth = 0) +{ + auto scoped_generator = generator.fork(); + auto acceptable_cpp_name = make_input_acceptable_cpp(cpp_name); + scoped_generator.set("cpp_name", acceptable_cpp_name); + scoped_generator.set("js_name", js_name); + scoped_generator.set("js_suffix", js_suffix); + scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false"); + scoped_generator.set("parameter.type.name", parameter.type->name()); + + if (optional_default_value.has_value()) + scoped_generator.set("parameter.optional_default_value", *optional_default_value); + + // FIXME: Add support for optional, variadic, nullable and default values to all types + if (parameter.type->is_string()) { + bool use_new_ak_string = interface.extended_attributes.contains("UseNewAKString"); + if (!use_new_ak_string) + generate_to_deprecated_string(scoped_generator, parameter, variadic, optional, optional_default_value); + else + generate_to_new_string(scoped_generator, parameter, variadic, optional, optional_default_value); } else if (parameter.type->name().is_one_of("EventListener", "NodeFilter")) { // FIXME: Replace this with support for callback interfaces. https://webidl.spec.whatwg.org/#idl-callback-interface |