diff --git a/Libraries/LibIDL/IDLParser.cpp b/Libraries/LibIDL/IDLParser.cpp index 0d3592c13c4..6e2e304a760 100644 --- a/Libraries/LibIDL/IDLParser.cpp +++ b/Libraries/LibIDL/IDLParser.cpp @@ -1012,6 +1012,7 @@ void Parser::parse_dictionary(HashMap extended_attribute Dictionary dictionary {}; dictionary.extended_attributes = move(extended_attributes); + dictionary.module_own_path = interface.module_own_path; auto name = parse_identifier_ending_with_space(); consume_whitespace(); diff --git a/Libraries/LibIDL/Types.h b/Libraries/LibIDL/Types.h index 4d97adc4eb6..f453e9388fa 100644 --- a/Libraries/LibIDL/Types.h +++ b/Libraries/LibIDL/Types.h @@ -210,6 +210,7 @@ struct Dictionary { ByteString parent_name; Vector members; HashMap extended_attributes; + ByteString module_own_path; bool is_original_definition { true }; }; diff --git a/Libraries/LibWeb/DOMURL/DOMURL.idl b/Libraries/LibWeb/DOMURL/DOMURL.idl index 5b2f9c28306..50318ca78c7 100644 --- a/Libraries/LibWeb/DOMURL/DOMURL.idl +++ b/Libraries/LibWeb/DOMURL/DOMURL.idl @@ -7,7 +7,7 @@ interface URL { constructor(USVString url, optional USVString base); - [ImplementedAs=parse_for_bindings] static DOMURL? parse(USVString url, optional USVString base); + [ImplementedAs=parse_for_bindings] static URL? parse(USVString url, optional USVString base); static boolean canParse(USVString url, optional USVString base); stringifier attribute USVString href; diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index c4341f7265d..d0a8ed48e52 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -11,7 +11,6 @@ */ #include "IDLGenerators.h" -#include "Namespaces.h" #include #include #include @@ -59,14 +58,61 @@ static bool is_javascript_builtin_buffer_source_type(Type const& type) return types.span().contains_slow(type.name()); } -static ByteString cpp_type_name(Type const& type) +static ByteString interface_cpp_type_name(Interface const& interface) { - if (libweb_interface_namespaces.span().contains_slow(type.name())) { - // e.g. Document.getSelection which returns Selection, which is in the Selection namespace. - return ByteString::formatted("{}::{}", type.name(), type.name()); + if (!interface.fully_qualified_name.is_empty()) + return interface.fully_qualified_name; + return interface.implemented_name; +} + +static ByteString interface_cpp_type_name(Context const& context, Type const& type) +{ + if (type.name() == "WindowProxy"sv) + return "HTML::WindowProxy"; + + auto interface = context.interfaces.get(type.name()); + if (interface.has_value()) + return interface_cpp_type_name(**interface); + + return type.name(); +} + +static ByteString cpp_namespace_for_module_path(ByteString const& module_own_path) +{ + auto path = LexicalPath { module_own_path }; + auto parts = path.parts_view(); + for (size_t i = 0; i + 2 < parts.size(); ++i) { + if (parts[i] != "LibWeb"sv) + continue; + + return parts[i + 1].to_byte_string(); } + + if (parts.size() >= 2) + return parts[parts.size() - 2].to_byte_string(); + + return {}; +} + +static ByteString dictionary_cpp_type_name(Context const& context, ByteString const& name) +{ + if (auto it = context.dictionaries.find(name); it != context.dictionaries.end()) { + auto namespace_name = cpp_namespace_for_module_path(it->value.module_own_path); + if (!namespace_name.is_empty()) + return ByteString::formatted("{}::{}", namespace_name, name); + } + + return name; +} + +static ByteString cpp_type_name(Type const& type, Context const& context) +{ + if (is_platform_object(context, type)) + return interface_cpp_type_name(context, type); if (is_javascript_builtin_buffer_source_type(type)) return ByteString::formatted("JS::{}", type.name()); + if (context.dictionaries.contains(type.name())) + return dictionary_cpp_type_name(context, type.name()); return type.name(); } @@ -127,13 +173,13 @@ static ByteString union_type_to_variant(UnionType const& union_type, Context con CppType idl_type_name_to_cpp_type(Type const& type, Context const& context) { if (is_platform_object(context, type)) - return { .name = ByteString::formatted("GC::Root<{}>", type.name()), .sequence_storage_type = SequenceStorageType::RootVector }; + return { .name = ByteString::formatted("GC::Root<{}>", interface_cpp_type_name(context, type)), .sequence_storage_type = SequenceStorageType::RootVector }; if (is_javascript_builtin_buffer_source_type(type)) return { .name = ByteString::formatted("GC::Root", type.name()), .sequence_storage_type = SequenceStorageType::RootVector }; if (auto const* callback_interface = callback_interface_for_type(context, type)) - return { .name = ByteString::formatted("GC::Root<{}>", callback_interface->implemented_name), .sequence_storage_type = SequenceStorageType::RootVector }; + return { .name = ByteString::formatted("GC::Root<{}>", interface_cpp_type_name(*callback_interface)), .sequence_storage_type = SequenceStorageType::RootVector }; if (context.callback_functions.contains(type.name())) return { .name = "GC::Root", .sequence_storage_type = SequenceStorageType::RootVector }; @@ -225,12 +271,8 @@ CppType idl_type_name_to_cpp_type(Type const& type, Context const& context) return { .name = union_type_to_variant(union_type, context), .sequence_storage_type = SequenceStorageType::Vector }; } - if (!type.is_nullable()) { - for (auto& dictionary : context.dictionaries) { - if (type.name() == dictionary.key) - return { .name = type.name(), .sequence_storage_type = SequenceStorageType::Vector }; - } - } + if (!type.is_nullable() && context.dictionaries.contains(type.name())) + return { .name = dictionary_cpp_type_name(context, type.name()), .sequence_storage_type = SequenceStorageType::Vector }; if (context.enumerations.contains(type.name())) return { .name = type.name(), .sequence_storage_type = SequenceStorageType::Vector }; @@ -601,7 +643,7 @@ static void generate_dictionary_to_cpp(SourceGenerator& generator, Context const static void generate_callback_interface_to_cpp(SourceGenerator& scoped_generator, IDL::Type const& type, IDL::Interface const& callback_interface) { - scoped_generator.set("cpp_type", callback_interface.implemented_name); + scoped_generator.set("cpp_type", interface_cpp_type_name(callback_interface)); if (type.is_nullable()) { scoped_generator.append(R"~~~( @@ -1162,7 +1204,7 @@ static void generate_union_to_cpp(SourceGenerator& scoped_generator, ParameterTy if (dictionary_type) { auto dictionary_generator = union_generator.fork(); - dictionary_generator.set("dictionary.type", dictionary_type->name()); + dictionary_generator.set("dictionary.type", dictionary_cpp_type_name(context, dictionary_type->name())); // The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic. dictionary_generator.append(R"~~~( @@ -1251,7 +1293,7 @@ static void generate_union_to_cpp(SourceGenerator& scoped_generator, ParameterTy continue; auto union_platform_object_type_generator = union_generator.fork(); - union_platform_object_type_generator.set("platform_object_type", type->name()); + union_platform_object_type_generator.set("platform_object_type", interface_cpp_type_name(context, *type)); union_platform_object_type_generator.append(R"~~~( if (auto* @js_name@@js_suffix@_result = as_if<@platform_object_type@>(@js_name@@js_suffix@_object)) @@ -1681,7 +1723,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter auto const& type = parameter.type; scoped_generator.set("parameter.type.name", type->name()); - scoped_generator.set("parameter.type.name.normalized", cpp_type_name(*type)); + scoped_generator.set("parameter.type.name.normalized", cpp_type_name(*type, context)); scoped_generator.set("parameter.name", parameter.name); @@ -1868,7 +1910,7 @@ static void generate_wrap_statement(SourceGenerator& generator, ByteString const if (optional_uses_value_access) value_non_optional = ByteString::formatted("{}.value()", value); scoped_generator.set("value_non_optional", value_non_optional); - scoped_generator.set("type", cpp_type_name(type)); + scoped_generator.set("type", cpp_type_name(type, context)); scoped_generator.set("result_expression", result_expression); scoped_generator.set("recursion_depth", ByteString::number(recursion_depth)); scoped_generator.set("iteration_index", ByteString::number(iteration_index)); @@ -3023,13 +3065,14 @@ static void generate_dictionaries(SourceGenerator& generator, IDL::Interface con continue; auto dictionary_generator = generator.fork(); dictionary_generator.set("dictionary.name", make_input_acceptable_cpp(it->key)); + dictionary_generator.set("dictionary.cpp_type", dictionary_cpp_type_name(interface.context, it->key)); dictionary_generator.set("dictionary.name:snakecase", make_input_acceptable_cpp(it->key.to_snakecase())); dictionary_generator.append(R"~~~( -JS::Value @dictionary.name:snakecase@_to_value(JS::Realm&, @dictionary.name@ const&); -JS::Value @dictionary.name:snakecase@_to_value(JS::Realm& realm, @dictionary.name@ const& dictionary) +JS::Value @dictionary.name:snakecase@_to_value(JS::Realm&, @dictionary.cpp_type@ const&); +JS::Value @dictionary.name:snakecase@_to_value(JS::Realm& realm, @dictionary.cpp_type@ const& dictionary) { auto& vm = realm.vm(); - @dictionary.name@ copy = dictionary; + @dictionary.cpp_type@ copy = dictionary; )~~~"); // FIXME: Support generating wrap statements for lvalues and get rid of the copy above auto dictionary_type = adopt_ref(*new Type(it->key, false)); @@ -3428,6 +3471,7 @@ static void generate_named_properties_object_definitions(IDL::Interface const& i SourceGenerator generator { builder }; generator.set("name", interface.name); + generator.set("fully_qualified_name", interface.fully_qualified_name); generator.set("parent_name", interface.parent_name); generator.set("prototype_base_class", interface.prototype_base_class); generator.set("named_properties_class", ByteString::formatted("{}Properties", interface.name)); @@ -3481,7 +3525,7 @@ JS::ThrowCompletionOr> @named_properties_class@ auto& realm = this->realm(); // 1. Let A be the interface for the named properties object O. - using A = @name@; + using A = @fully_qualified_name@; // 2. Let object be O.[[Realm]]'s global object. // 3. Assert: object implements A. @@ -3598,7 +3642,7 @@ static void generate_prototype_or_global_mixin_initialization(IDL::Interface con generator.set("prototype_name", interface.prototype_class); // Used for Global Mixin if (interface.pair_iterator_types.has_value()) { - generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.name)); + generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.fully_qualified_name)); } bool define_on_existing_object = is_global_interface || generate_unforgeables == GenerateUnforgeables::Yes; @@ -4260,7 +4304,7 @@ static void generate_prototype_or_global_mixin_definitions(IDL::Interface const& generator.set("prototype_name", interface.prototype_class); // Used for Global Mixin if (interface.pair_iterator_types.has_value()) { - generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.name)); + generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.fully_qualified_name)); } if (interface.is_callback_interface) @@ -4810,7 +4854,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::values) // https://webidl.spec.whatwg.org/#js-asynchronous-iterable if (interface.async_value_iterator_type.has_value()) { auto iterator_generator = generator.fork(); - iterator_generator.set("iterator_name"sv, MUST(String::formatted("{}AsyncIterator", interface.name))); + iterator_generator.set("iterator_name"sv, ByteString::formatted("{}AsyncIterator", interface.fully_qualified_name)); iterator_generator.append(R"~~~( JS_DEFINE_NATIVE_FUNCTION(@class_name@::values) { @@ -4838,7 +4882,8 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::values) if (interface.set_entry_type.has_value()) { auto setlike_generator = generator.fork(); auto const& set_entry_type = *interface.set_entry_type.value(); - setlike_generator.set("value_type", set_entry_type.name()); + auto value_type = cpp_type_name(set_entry_type, interface.context); + setlike_generator.set("value_type", value_type); if (set_entry_type.is_string()) { setlike_generator.set("value_type_check", R"~~~( @@ -4853,7 +4898,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::values) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "{0}"); }} )~~~", - set_entry_type.name()))); + value_type))); } setlike_generator.append(R"~~~( @@ -5255,64 +5300,6 @@ private: )~~~"); } -static void generate_using_namespace_definitions(SourceGenerator& generator) -{ - generator.append(R"~~~( -// FIXME: This is a total hack until we can figure out the namespace for a given type somehow. -using namespace Web::Animations; -using namespace Web::Clipboard; -using namespace Web::ContentSecurityPolicy; -using namespace Web::CookieStore; -using namespace Web::CredentialManagement; -using namespace Web::Crypto; -using namespace Web::CSS; -using namespace Web::DOM; -using namespace Web::DOMURL; -using namespace Web::Encoding; -using namespace Web::EncryptedMediaExtensions; -using namespace Web::EntriesAPI; -using namespace Web::EventTiming; -using namespace Web::Fetch; -using namespace Web::FileAPI; -using namespace Web::Gamepad; -using namespace Web::Geolocation; -using namespace Web::Geometry; -using namespace Web::HighResolutionTime; -using namespace Web::HTML; -using namespace Web::IndexedDB; -using namespace Web::Internals; -using namespace Web::IntersectionObserver; -using namespace Web::MediaCapabilitiesAPI; -using namespace Web::MediaCapture; -using namespace Web::MediaSourceExtensions; -using namespace Web::NavigationTiming; -using namespace Web::NotificationsAPI; -using namespace Web::PerformanceTimeline; -using namespace Web::RequestIdleCallback; -using namespace Web::ResizeObserver; -using namespace Web::ResourceTiming; -using namespace Web::Selection; -using namespace Web::Serial; -using namespace Web::ServiceWorker; -using namespace Web::Speech; -using namespace Web::StorageAPI; -using namespace Web::Streams; -using namespace Web::SVG; -using namespace Web::TrustedTypes; -using namespace Web::UIEvents; -using namespace Web::URLPattern; -using namespace Web::UserTiming; -using namespace Web::WebAssembly; -using namespace Web::WebAudio; -using namespace Web::WebGL; -using namespace Web::WebIDL; -using namespace Web::WebVTT; -using namespace Web::WebXR; -using namespace Web::XHR; -using namespace Web::XPath; -)~~~"sv); -} - // https://webidl.spec.whatwg.org/#define-the-operations static void define_the_operations(SourceGenerator& generator, OrderedHashMap> const& operations) { @@ -6025,7 +6012,6 @@ static void generate_implementation_prologue(IDL::Interface const& interface, St } emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value(), interface.async_value_iterator_type.has_value()); - generate_using_namespace_definitions(generator); generator.append(R"~~~( namespace Web::Bindings { diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/Namespaces.h b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/Namespaces.h deleted file mode 100644 index 4c4e09de665..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/Namespaces.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2022, Luke Wilde - * Copyright (c) 2022, Linus Groh - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace IDL { - -static constexpr Array libweb_interface_namespaces = { - "CSS"sv, - "Clipboard"sv, - "Compression"sv, - "ContentSecurityPolicy"sv, - "CookieStore"sv, - "Crypto"sv, - "DOM"sv, - "DOMURL"sv, - "Encoding"sv, - "Fetch"sv, - "FileAPI"sv, - "Gamepad"sv, - "Geolocation"sv, - "Geometry"sv, - "HTML"sv, - "HighResolutionTime"sv, - "Internals"sv, - "IntersectionObserver"sv, - "MathML"sv, - "MediaSourceExtensions"sv, - "NavigationTiming"sv, - "RequestIdleCallback"sv, - "ResizeObserver"sv, - "SVG"sv, - "Selection"sv, - "Serial"sv, - "ServiceWorker"sv, - "Streams"sv, - "UIEvents"sv, - "URLPattern"sv, - "ViewTransition"sv, - "WebAudio"sv, - "WebGL"sv, - "WebIDL"sv, - "WebSockets"sv, - "XHR"sv, - "XPath"sv, -}; - -} diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp index a9a347ba4ff..097dd53f740 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp @@ -9,7 +9,6 @@ */ #include "IDLGenerators.h" -#include "Namespaces.h" #include #include #include @@ -64,6 +63,34 @@ static ErrorOr generate_depfile(StringView depfile_path, ReadonlySpanwrite_until_depleted(depfile_builder.string_view().bytes()); } +static ByteString cpp_namespace_for_module_path(ByteString const& module_own_path) +{ + auto path = LexicalPath { module_own_path }; + auto parts = path.parts_view(); + for (size_t i = 0; i + 2 < parts.size(); ++i) { + if (parts[i] != "LibWeb"sv) + continue; + + return parts[i + 1].to_byte_string(); + } + + if (parts.size() >= 2) + return parts[parts.size() - 2].to_byte_string(); + + return {}; +} + +static void assign_fully_qualified_name(IDL::Interface& interface) +{ + auto namespace_name = cpp_namespace_for_module_path(interface.module_own_path); + if (namespace_name.is_empty()) { + interface.fully_qualified_name = interface.implemented_name; + return; + } + + interface.fully_qualified_name = ByteString::formatted("{}::{}", namespace_name, interface.implemented_name); +} + ErrorOr ladybird_main(Main::Arguments arguments) { Core::ArgsParser args_parser; @@ -144,23 +171,13 @@ ErrorOr ladybird_main(Main::Arguments arguments) append_dependency_path(imported_file); } + for (auto& interface : context.owned_interfaces) + assign_fully_qualified_name(*interface); + for (size_t i = 0; i < paths.size(); ++i) { auto const& lexical_path = lexical_paths[i]; - auto& namespace_ = lexical_path.parts_view().at(lexical_path.parts_view().size() - 2); auto& interface = *interfaces[i]; - // If the interface name is the same as its namespace, qualify the name in the generated code. - // e.g. Selection::Selection - if (IDL::libweb_interface_namespaces.span().contains_slow(namespace_)) { - StringBuilder builder; - builder.append(namespace_); - builder.append("::"sv); - builder.append(interface.implemented_name); - interface.fully_qualified_name = builder.to_byte_string(); - } else { - interface.fully_qualified_name = interface.implemented_name; - } - if constexpr (BINDINGS_GENERATOR_DEBUG) interface.dump();