From c0f22065abe2c032ce61afba727d38b95cffa9dd Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Fri, 17 Feb 2023 18:56:12 +0000 Subject: [PATCH] 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. --- .../BindingsGenerator/IDLGenerators.cpp | 153 ++++++++++++------ 1 file changed, 107 insertions(+), 46 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 }; @@ -250,6 +254,104 @@ static void emit_includes_for_all_imports(auto& interface, auto& generator, bool } } +template +static void generate_to_deprecated_string(SourceGenerator& scoped_generator, ParameterType const& parameter, bool variadic, bool optional, Optional const& optional_default_value) +{ + if (variadic) { + scoped_generator.append(R"~~~( + Vector @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_deprecated_string(vm)); + @cpp_name@.append(move(to_string_result)); + } +)~~~"); + } 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(); + } else { + @cpp_name@ = TRY(@js_name@@js_suffix@.to_deprecated_string(vm)); + } +)~~~"); + } 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"~~~( + DeprecatedString @cpp_name@; + if (!@js_name@@js_suffix@.is_undefined()) { + if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) + @cpp_name@ = DeprecatedString::empty(); + 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 { + @cpp_name@ = @parameter.optional_default_value@; + } +)~~~"); + } else { + scoped_generator.append(R"~~~( +)~~~"); + } + } +} + +template +static void generate_to_new_string(SourceGenerator& scoped_generator, ParameterType const& parameter, bool variadic, bool optional, Optional const& optional_default_value) +{ + if (variadic) { + scoped_generator.append(R"~~~( + Vector @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 @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 @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 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 optional_default_value = {}, bool variadic = false, size_t recursion_depth = 0) { @@ -266,52 +368,11 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // FIXME: Add support for optional, variadic, nullable and default values to all types if (parameter.type->is_string()) { - if (variadic) { - scoped_generator.append(R"~~~( - Vector @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_deprecated_string(vm)); - @cpp_name@.append(move(to_string_result)); - } -)~~~"); - } 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(); - } else { - @cpp_name@ = TRY(@js_name@@js_suffix@.to_deprecated_string(vm)); - } -)~~~"); - } 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"~~~( - DeprecatedString @cpp_name@; - if (!@js_name@@js_suffix@.is_undefined()) { - if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) - @cpp_name@ = DeprecatedString::empty(); + 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 - @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 { - @cpp_name@ = @parameter.optional_default_value@; - } -)~~~"); - } else { - scoped_generator.append(R"~~~( -)~~~"); - } - } + 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