瀏覽代碼

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.
Luke Wilde 2 年之前
父節點
當前提交
c0f22065ab
共有 1 個文件被更改,包括 91 次插入30 次删除
  1. 91 30
      Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

+ 91 - 30
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