1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:28:11 +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

@ -69,6 +69,13 @@ static ErrorOr<void> generate_forwarding_header(StringView output_path, Vector<I
namespace Web::Bindings {
)~~~");
auto add_namespace = [](SourceGenerator& gen, StringView namespace_class) {
gen.set("namespace_class", namespace_class);
gen.append(R"~~~(
class @namespace_class@;)~~~");
};
auto add_interface = [](SourceGenerator& gen, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor) {
gen.set("prototype_class", prototype_class);
gen.set("constructor_class", constructor_class);
@ -86,7 +93,11 @@ class @legacy_constructor_class@;)~~~");
for (auto& interface : exposed_interfaces) {
auto gen = generator.fork();
add_interface(gen, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface));
if (interface.is_namespace)
add_namespace(gen, interface.namespace_class);
else
add_interface(gen, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface));
}
// FIXME: Special case WebAssembly. We should convert WASM to use IDL.
@ -122,17 +133,23 @@ static ErrorOr<void> generate_intrinsic_definitions(StringView output_path, Vect
for (auto& interface : exposed_interfaces) {
auto gen = generator.fork();
gen.set("namespace_class", interface.namespace_class);
gen.set("prototype_class", interface.prototype_class);
gen.set("constructor_class", interface.constructor_class);
gen.append(R"~~~(
if (interface.is_namespace) {
gen.append(R"~~~(
#include <LibWeb/Bindings/@namespace_class@.h>)~~~");
} else {
gen.append(R"~~~(
#include <LibWeb/Bindings/@constructor_class@.h>
#include <LibWeb/Bindings/@prototype_class@.h>)~~~");
if (auto const& legacy_constructor = lookup_legacy_constructor(interface); legacy_constructor.has_value()) {
gen.set("legacy_constructor_class", legacy_constructor->constructor_class);
gen.append(R"~~~(
if (auto const& legacy_constructor = lookup_legacy_constructor(interface); legacy_constructor.has_value()) {
gen.set("legacy_constructor_class", legacy_constructor->constructor_class);
gen.append(R"~~~(
#include <LibWeb/Bindings/@legacy_constructor_class@.h>)~~~");
}
}
}
@ -152,6 +169,20 @@ static ErrorOr<void> generate_intrinsic_definitions(StringView output_path, Vect
namespace Web::Bindings {
)~~~");
auto add_namespace = [&](SourceGenerator& gen, StringView name, StringView namespace_class) {
gen.set("interface_name", name);
gen.set("namespace_class", namespace_class);
gen.append(R"~~~(
template<>
void Intrinsics::create_web_namespace<@namespace_class@>(JS::Realm& realm)
{
auto namespace_object = heap().allocate<@namespace_class@>(realm, realm).release_allocated_value_but_fixme_should_propagate_errors();
m_namespaces.set("@interface_name@"sv, namespace_object);
}
)~~~");
};
auto add_interface = [&](SourceGenerator& gen, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor) {
gen.set("interface_name", name);
gen.set("prototype_class", prototype_class);
@ -190,7 +221,11 @@ void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Rea
for (auto& interface : exposed_interfaces) {
auto gen = generator.fork();
add_interface(gen, interface.name, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface));
if (interface.is_namespace)
add_namespace(gen, interface.name, interface.namespace_class);
else
add_interface(gen, interface.name, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface));
}
// FIXME: Special case WebAssembly. We should convert WASM to use IDL.
@ -254,17 +289,24 @@ static ErrorOr<void> generate_exposed_interface_implementation(StringView class_
)~~~");
for (auto& interface : exposed_interfaces) {
auto gen = generator.fork();
gen.set("namespace_class", interface.namespace_class);
gen.set("prototype_class", interface.prototype_class);
gen.set("constructor_class", interface.constructor_class);
gen.append(R"~~~(#include <LibWeb/Bindings/@constructor_class@.h>
if (interface.is_namespace) {
gen.append(R"~~~(#include <LibWeb/Bindings/@namespace_class@.h>
)~~~");
} else {
gen.append(R"~~~(#include <LibWeb/Bindings/@constructor_class@.h>
#include <LibWeb/Bindings/@prototype_class@.h>
)~~~");
if (auto const& legacy_constructor = lookup_legacy_constructor(interface); legacy_constructor.has_value()) {
gen.set("legacy_constructor_class", legacy_constructor->constructor_class);
gen.append(R"~~~(#include <LibWeb/Bindings/@legacy_constructor_class@.h>
if (auto const& legacy_constructor = lookup_legacy_constructor(interface); legacy_constructor.has_value()) {
gen.set("legacy_constructor_class", legacy_constructor->constructor_class);
gen.append(R"~~~(#include <LibWeb/Bindings/@legacy_constructor_class@.h>
)~~~");
}
}
}
@ -290,9 +332,21 @@ void add_@global_object_snake_name@_exposed_interfaces(JS::Object& global)
}
};
auto add_namespace = [](SourceGenerator& gen, StringView name, StringView namespace_class) {
gen.set("interface_name", name);
gen.set("namespace_class", namespace_class);
gen.append(R"~~~(
global.define_intrinsic_accessor("@interface_name@", attr, [](auto& realm) -> JS::Value { return &ensure_web_namespace<@namespace_class@>(realm, "@interface_name@"sv); });)~~~");
};
for (auto& interface : exposed_interfaces) {
auto gen = generator.fork();
add_interface(gen, interface.name, interface.prototype_class, lookup_legacy_constructor(interface));
if (interface.is_namespace)
add_namespace(gen, interface.name, interface.namespace_class);
else
add_interface(gen, interface.name, interface.prototype_class, lookup_legacy_constructor(interface));
}
generator.append(R"~~~(