1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:07:35 +00:00

LibWeb: Support generating IDL namespaces

These are similar to prototypes and constructors in that they will now
be lazily instantiated when they are first requested.
This commit is contained in:
Timothy Flynn 2023-03-15 10:02:04 -04:00 committed by Tim Flynn
parent 61ecdbca54
commit 020c2b59c4
5 changed files with 269 additions and 24 deletions

View file

@ -2653,6 +2653,151 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::values)
}
}
void generate_namespace_header(IDL::Interface const& interface, StringBuilder& builder)
{
SourceGenerator generator { builder };
generator.set("namespace_class", interface.namespace_class);
generator.append(R"~~~(
#pragma once
#include <LibJS/Runtime/Object.h>
namespace Web::Bindings {
class @namespace_class@ final : public JS::Object {
JS_OBJECT(@namespace_class@, JS::Object);
public:
explicit @namespace_class@(JS::Realm&);
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
virtual ~@namespace_class@() override;
private:
)~~~");
for (auto const& overload_set : interface.overload_sets) {
auto function_generator = generator.fork();
function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
function_generator.append(R"~~~(
JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
)~~~");
if (overload_set.value.size() > 1) {
for (auto i = 0u; i < overload_set.value.size(); ++i) {
function_generator.set("overload_suffix", DeprecatedString::number(i));
function_generator.append(R"~~~(
JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@@overload_suffix@);
)~~~");
}
}
}
generator.append(R"~~~(
};
} // namespace Web::Bindings
)~~~");
}
void generate_namespace_implementation(IDL::Interface const& interface, StringBuilder& builder)
{
SourceGenerator generator { builder };
generator.set("name", interface.name);
generator.set("namespace_class", interface.namespace_class);
generator.append(R"~~~(
#include <AK/Function.h>
#include <LibIDL/Types.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/Value.h>
#include <LibWeb/Bindings/@namespace_class@.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WindowProxy.h>
#include <LibWeb/WebIDL/OverloadResolution.h>
)~~~");
for (auto& path : interface.required_imported_paths)
generate_include_for(generator, path);
emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
generator.append(R"~~~(
// FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
using namespace Web::CSS;
using namespace Web::DOM;
using namespace Web::DOMParsing;
using namespace Web::Fetch;
using namespace Web::FileAPI;
using namespace Web::Geometry;
using namespace Web::HighResolutionTime;
using namespace Web::HTML;
using namespace Web::IntersectionObserver;
using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver;
using namespace Web::Selection;
using namespace Web::Streams;
using namespace Web::UIEvents;
using namespace Web::URL;
using namespace Web::XHR;
using namespace Web::WebGL;
using namespace Web::WebIDL;
namespace Web::Bindings {
@namespace_class@::@namespace_class@(JS::Realm& realm)
: Object(ConstructWithoutPrototypeTag::Tag, realm)
{
}
@namespace_class@::~@namespace_class@()
{
}
JS::ThrowCompletionOr<void> @namespace_class@::initialize(JS::Realm& realm)
{
[[maybe_unused]] auto& vm = this->vm();
[[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
MUST_OR_THROW_OOM(Base::initialize(realm));
)~~~");
// https://webidl.spec.whatwg.org/#es-operations
for (auto const& overload_set : interface.overload_sets) {
auto function_generator = generator.fork();
function_generator.set("function.name", overload_set.key);
function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
function_generator.set("function.length", DeprecatedString::number(get_shortest_function_length(overload_set.value)));
function_generator.append(R"~~~(
define_native_function(realm, "@function.name@", @function.name:snakecase@, @function.length@, default_attributes);
)~~~");
}
generator.append(R"~~~(
return {};
}
)~~~");
for (auto const& function : interface.functions)
generate_function(generator, function, StaticFunction::Yes, interface.namespace_class, interface.name, interface);
for (auto const& overload_set : interface.overload_sets) {
if (overload_set.value.size() == 1)
continue;
generate_overload_arbiter(generator, overload_set, interface.namespace_class);
}
generator.append(R"~~~(
} // namespace Web::Bindings
)~~~");
}
void generate_constructor_header(IDL::Interface const& interface, StringBuilder& builder)
{
SourceGenerator generator { builder };

View file

@ -18,6 +18,8 @@
extern Vector<StringView> s_header_search_paths;
namespace IDL {
void generate_namespace_header(IDL::Interface const&, StringBuilder&);
void generate_namespace_implementation(IDL::Interface const&, StringBuilder&);
void generate_constructor_header(IDL::Interface const&, StringBuilder&);
void generate_constructor_implementation(IDL::Interface const&, StringBuilder&);
void generate_prototype_header(IDL::Interface const&, StringBuilder&);
@ -36,6 +38,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
StringView output_path = "-"sv;
StringView depfile_path;
StringView depfile_target;
bool namespace_header_mode = false;
bool namespace_implementation_mode = false;
bool constructor_header_mode = false;
bool constructor_implementation_mode = false;
bool prototype_header_mode = false;
@ -44,6 +48,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
bool iterator_prototype_implementation_mode = false;
bool global_mixin_header_mode = false;
bool global_mixin_implementation_mode = false;
args_parser.add_option(namespace_header_mode, "Generate the namespace .h file", "namespace-header", 'N');
args_parser.add_option(namespace_implementation_mode, "Generate the namespace .cpp file", "namespace-implementation", 'A');
args_parser.add_option(constructor_header_mode, "Generate the constructor .h file", "constructor-header", 'C');
args_parser.add_option(constructor_implementation_mode, "Generate the constructor .cpp file", "constructor-implementation", 'O');
args_parser.add_option(prototype_header_mode, "Generate the prototype .h file", "prototype-header", 'P');
@ -136,6 +142,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
}
StringBuilder output_builder;
if (namespace_header_mode)
IDL::generate_namespace_header(interface, output_builder);
if (namespace_implementation_mode)
IDL::generate_namespace_implementation(interface, output_builder);
if (constructor_header_mode)
IDL::generate_constructor_header(interface, output_builder);