ladybird/Meta/Generators/libweb_bindings/namespaces.py
Andreas Kling b6bef6b688 Libraries: Use UTF-16 for JS-visible runtime strings
Produce JS-visible string results as UTF-16 at their source, including
numeric formatting, BigInt and BigFraction formatting, URI encoding,
console formatting, parser errors, regular expression errors, Intl and
Temporal records, LibUnicode locale boundaries, and LibWeb bindings.

Handle fractional radix formatting through the UTF-16 builder view.
2026-06-22 19:51:25 +02:00

150 lines
5.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (c) 2026-present, the Ladybird developers.
#
# SPDX-License-Identifier: BSD-2-Clause
from typing import TextIO
from Generators.libweb_bindings import overload_resolution
from Generators.libweb_bindings.attributes import define_the_regular_attributes
from Generators.libweb_bindings.constants import define_the_constants
from Generators.libweb_bindings.context import GenerationContext
from Generators.libweb_bindings.cpp_types import fully_qualified_name_for_interface
from Generators.libweb_bindings.cpp_types import idl_identifier_cpp_name
from Generators.libweb_bindings.cpp_types import implementation_header_for_interface
from Generators.libweb_bindings.includes import GeneratedIncludes
from Generators.libweb_bindings.operations import define_the_regular_operations
from Generators.libweb_bindings.operations import write_regular_operations
from Utils.webidl_parser import Interface
def write_namespace_declaration(
out: TextIO, includes: GeneratedIncludes, context: GenerationContext, interface: Interface
) -> None:
includes.add("LibJS/Runtime/NativeFunction.h")
includes.add("LibJS/Runtime/Object.h")
out.write(
f"""class {interface.namespace_class} final : public JS::Object {{
JS_OBJECT({interface.namespace_class}, JS::Object);
GC_DECLARE_ALLOCATOR({interface.namespace_class});
public:
explicit {interface.namespace_class}(JS::Realm&);
virtual void initialize(JS::Realm&) override;
virtual ~{interface.namespace_class}() override;
private:
"""
)
if "WithGCVisitor" in interface.extended_attributes:
out.write(" virtual void visit_edges(JS::Cell::Visitor&) override;\n")
if "WithFinalizer" in interface.extended_attributes:
out.write(
"""
public:
static constexpr bool OVERRIDES_FINALIZE = true;
private:
virtual void finalize() override;
"""
)
for operations in overload_resolution.operation_overload_sets(interface).values():
operation = operations[0]
out.write(f" JS_DECLARE_NATIVE_FUNCTION({idl_identifier_cpp_name(operation)});\n")
if len(operations) > 1:
for overload_index, overloaded_operation in enumerate(operations):
out.write(
f" JS_DECLARE_NATIVE_FUNCTION({idl_identifier_cpp_name(overloaded_operation, suffix=overload_index)});\n"
)
out.write(
"""};
"""
)
# https://webidl.spec.whatwg.org/#namespace-object
def write_namespace_implementation(
out: TextIO, context: GenerationContext, includes: GeneratedIncludes, interface: Interface
) -> None:
includes.add("LibJS/Runtime/ValueInlines.h")
includes.add("LibWeb/WebIDL/Tracing.h")
includes.add_binding(interface.implemented_name)
includes.add(implementation_header_for_interface(interface))
# 1. Let namespaceObject be OrdinaryObjectCreate(realm.[[Intrinsics]].[[%Object.prototype%]]).
out.write(
f"""GC_DEFINE_ALLOCATOR({interface.namespace_class});
{interface.namespace_class}::{interface.namespace_class}(JS::Realm& realm)
: Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
{{
}}
{interface.namespace_class}::~{interface.namespace_class}()
{{
}}
void {interface.namespace_class}::initialize(JS::Realm& realm)
{{
auto& object = *this;
[[maybe_unused]] auto& vm = this->vm();
[[maybe_unused]] u8 default_attributes = JS::Attribute::Writable | JS::Attribute::Enumerable | JS::Attribute::Configurable;
Base::initialize(realm);
// The class string of a namespace object is the namespaces identifier.
define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "{interface.name}"_utf16), JS::Attribute::Configurable);
"""
)
# 2. Define the regular attributes of namespace on namespaceObject given realm.
define_the_regular_attributes(out, includes, interface)
# 3. Define the regular operations of namespace on namespaceObject given realm.
define_the_regular_operations(out, includes, interface)
# 4. Define the constants of namespace on namespaceObject given realm.
define_the_constants(out, context, includes, interface)
# 5. For each exposed interface interface which has the [LegacyNamespace] extended attribute with the identifier of namespace as its argument,
# 1. Let id be interfaces identifier.
# 2. Let interfaceObject be the result of creating an interface object for interface with id in realm.
# 3. Perform DefineMethodProperty(namespaceObject, id, interfaceObject, false).
# 6. Return namespaceObject.
# NB: Above is done in intrinsics defintions.
if "WithInitializer" in interface.extended_attributes:
out.write(
f"""
{fully_qualified_name_for_interface(interface).partition("::")[0]}::initialize(*this, realm);
"""
)
out.write(
"""}
"""
)
write_regular_operations(out, context, includes, interface)
if "WithGCVisitor" in interface.extended_attributes:
out.write(
f"""void {interface.namespace_class}::visit_edges(JS::Cell::Visitor& visitor)
{{
Base::visit_edges(visitor);
{fully_qualified_name_for_interface(interface).partition("::")[0]}::visit_edges(*this, visitor);
}}
"""
)
if "WithFinalizer" in interface.extended_attributes:
out.write(
f"""void {interface.namespace_class}::finalize()
{{
Base::finalize();
{fully_qualified_name_for_interface(interface).partition("::")[0]}::finalize(*this);
}}
"""
)