diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index bc51b049a30..aa97b12df2e 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -3849,6 +3849,20 @@ private: virtual bool has_constructor() const override { return true; } )~~~"); + for (auto& attribute : interface.static_attributes) { + auto attribute_generator = generator.fork(); + attribute_generator.set("attribute.name:snakecase", attribute.name.to_snakecase()); + attribute_generator.append(R"~~~( + JS_DECLARE_NATIVE_FUNCTION(@attribute.name:snakecase@_getter); +)~~~"); + + if (!attribute.readonly) { + attribute_generator.append(R"~~~( + JS_DECLARE_NATIVE_FUNCTION(@attribute.name:snakecase@_setter); +)~~~"); + } + } + for (auto const& overload_set : interface.constructor_overload_sets) { auto constructor_generator = generator.fork(); if (overload_set.value.size() > 1) { @@ -4050,6 +4064,22 @@ void @constructor_class@::initialize(JS::Realm& realm) )~~~"); } + for (auto& attribute : interface.static_attributes) { + auto attribute_generator = generator.fork(); + attribute_generator.set("attribute.name", attribute.name); + attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name); + attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name); + + if (!attribute.readonly) + attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name); + else + attribute_generator.set("attribute.setter_callback", "nullptr"); + + attribute_generator.append(R"~~~( + define_native_accessor(realm, "@attribute.name@", @attribute.getter_callback@, @attribute.setter_callback@, default_attributes); +)~~~"); + } + // https://webidl.spec.whatwg.org/#es-operations for (auto const& overload_set : interface.static_overload_sets) { auto function_generator = generator.fork(); @@ -4066,6 +4096,35 @@ void @constructor_class@::initialize(JS::Realm& realm) } )~~~"); + // Implementation: Static Attributes + for (auto& attribute : interface.static_attributes) { + auto attribute_generator = generator.fork(); + attribute_generator.set("attribute.name", attribute.name); + attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name); + attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name); + + if (attribute.extended_attributes.contains("ImplementedAs")) { + auto implemented_as = attribute.extended_attributes.get("ImplementedAs").value(); + attribute_generator.set("attribute.cpp_name", implemented_as); + } else { + attribute_generator.set("attribute.cpp_name", attribute.name.to_snakecase()); + } + + attribute_generator.append(R"~~~( +JS_DEFINE_NATIVE_FUNCTION(@constructor_class@::@attribute.getter_callback@) +{ + auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::@attribute.cpp_name@(vm); })); +)~~~"); + + generate_return_statement(generator, *attribute.type, interface); + + attribute_generator.append(R"~~~( +} +)~~~"); + + // FIXME: Add support for static attribute setters. + } + // Implementation: Static Functions for (auto& function : interface.static_functions) generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name, interface); diff --git a/Userland/Libraries/LibIDL/IDLParser.cpp b/Userland/Libraries/LibIDL/IDLParser.cpp index 6853a3af5bf..b1ed3316750 100644 --- a/Userland/Libraries/LibIDL/IDLParser.cpp +++ b/Userland/Libraries/LibIDL/IDLParser.cpp @@ -282,7 +282,7 @@ NonnullRefPtr Parser::parse_type() return adopt_ref(*new Type(builder.to_byte_string(), nullable)); } -void Parser::parse_attribute(HashMap& extended_attributes, Interface& interface) +void Parser::parse_attribute(HashMap& extended_attributes, Interface& interface, IsStatic is_static) { bool inherit = lexer.consume_specific("inherit"sv); if (inherit) @@ -316,7 +316,10 @@ void Parser::parse_attribute(HashMap& extended_attribute move(getter_callback_name), move(setter_callback_name), }; - interface.attributes.append(move(attribute)); + if (is_static == IsStatic::No) + interface.attributes.append(move(attribute)); + else + interface.static_attributes.append(move(attribute)); } void Parser::parse_constant(Interface& interface) @@ -391,14 +394,9 @@ Vector Parser::parse_parameters() return parameters; } -Function Parser::parse_function(HashMap& extended_attributes, Interface& interface, IsSpecialOperation is_special_operation) +Function Parser::parse_function(HashMap& extended_attributes, Interface& interface, IsStatic is_static, IsSpecialOperation is_special_operation) { auto position = lexer.current_position(); - bool static_ = false; - if (lexer.consume_specific("static"sv)) { - static_ = true; - consume_whitespace(); - } auto return_type = parse_type(); consume_whitespace(); @@ -414,7 +412,7 @@ Function Parser::parse_function(HashMap& extended_attrib // "Defining a special operation with an identifier is equivalent to separating the special operation out into its own declaration without an identifier." if (is_special_operation == IsSpecialOperation::No || (is_special_operation == IsSpecialOperation::Yes && !name.is_empty())) { - if (!static_) + if (is_static == IsStatic::No) interface.functions.append(function); else interface.static_functions.append(function); @@ -476,7 +474,7 @@ void Parser::parse_getter(HashMap& extended_attributes, { assert_string("getter"sv); consume_whitespace(); - auto function = parse_function(extended_attributes, interface, IsSpecialOperation::Yes); + auto function = parse_function(extended_attributes, interface, IsStatic::No, IsSpecialOperation::Yes); if (function.parameters.size() != 1) report_parsing_error(ByteString::formatted("Named/indexed property getters must have only 1 parameter, got {} parameters.", function.parameters.size()), filename, input, lexer.tell()); @@ -510,7 +508,7 @@ void Parser::parse_setter(HashMap& extended_attributes, { assert_string("setter"sv); consume_whitespace(); - auto function = parse_function(extended_attributes, interface, IsSpecialOperation::Yes); + auto function = parse_function(extended_attributes, interface, IsStatic::No, IsSpecialOperation::Yes); if (function.parameters.size() != 2) report_parsing_error(ByteString::formatted("Named/indexed property setters must have only 2 parameters, got {} parameter(s).", function.parameters.size()), filename, input, lexer.tell()); @@ -550,7 +548,7 @@ void Parser::parse_deleter(HashMap& extended_attributes, { assert_string("deleter"sv); consume_whitespace(); - auto function = parse_function(extended_attributes, interface, IsSpecialOperation::Yes); + auto function = parse_function(extended_attributes, interface, IsStatic::No, IsSpecialOperation::Yes); if (function.parameters.size() != 1) report_parsing_error(ByteString::formatted("Named property deleter must have only 1 parameter, got {} parameters.", function.parameters.size()), filename, input, lexer.tell()); @@ -647,7 +645,17 @@ void Parser::parse_interface(Interface& interface) continue; } - parse_function(extended_attributes, interface); + bool is_static = lexer.consume_specific("static"); + if (!is_static) { + parse_function(extended_attributes, interface, IsStatic::No); + } else { + consume_whitespace(); + if (lexer.next_is("readonly") || lexer.next_is("attribute")) { + parse_attribute(extended_attributes, interface, IsStatic::Yes); + } else { + parse_function(extended_attributes, interface, IsStatic::Yes); + } + } } if (auto legacy_namespace = interface.extended_attributes.get("LegacyNamespace"sv); legacy_namespace.has_value()) @@ -1081,6 +1089,8 @@ Interface& Parser::parse() // Resolve typedefs for (auto& attribute : interface.attributes) resolve_typedef(interface, attribute.type, &attribute.extended_attributes); + for (auto& attribute : interface.static_attributes) + resolve_typedef(interface, attribute.type, &attribute.extended_attributes); for (auto& constant : interface.constants) resolve_typedef(interface, constant.type); for (auto& constructor : interface.constructors) diff --git a/Userland/Libraries/LibIDL/IDLParser.h b/Userland/Libraries/LibIDL/IDLParser.h index c8db88d0ff9..330e1a42159 100644 --- a/Userland/Libraries/LibIDL/IDLParser.h +++ b/Userland/Libraries/LibIDL/IDLParser.h @@ -30,6 +30,11 @@ private: Yes, }; + enum class IsStatic { + No, + Yes, + }; + Parser(Parser* parent, ByteString filename, StringView contents, ByteString import_base_path); void assert_specific(char ch); @@ -38,7 +43,7 @@ private: Optional resolve_import(auto path); HashMap parse_extended_attributes(); - void parse_attribute(HashMap& extended_attributes, Interface&); + void parse_attribute(HashMap& extended_attributes, Interface&, IsStatic is_static = IsStatic::No); void parse_interface(Interface&); void parse_namespace(Interface&); void parse_non_interface_entities(bool allow_interface, Interface&); @@ -53,7 +58,7 @@ private: void parse_deleter(HashMap& extended_attributes, Interface&); void parse_stringifier(HashMap& extended_attributes, Interface&); void parse_iterable(Interface&); - Function parse_function(HashMap& extended_attributes, Interface&, IsSpecialOperation is_special_operation = IsSpecialOperation::No); + Function parse_function(HashMap& extended_attributes, Interface&, IsStatic is_static = IsStatic::No, IsSpecialOperation is_special_operation = IsSpecialOperation::No); Vector parse_parameters(); NonnullRefPtr parse_type(); void parse_constant(Interface&); diff --git a/Userland/Libraries/LibIDL/Types.h b/Userland/Libraries/LibIDL/Types.h index 853b97c5bb4..77333aac29f 100644 --- a/Userland/Libraries/LibIDL/Types.h +++ b/Userland/Libraries/LibIDL/Types.h @@ -270,6 +270,7 @@ public: HashMap extended_attributes; Vector attributes; + Vector static_attributes; Vector constants; Vector constructors; Vector functions;