LibIDL+LibWeb: Add support for static readonly attributes

Support for settable attributes is a FIXME.
This commit is contained in:
Luke Wilde 2024-04-01 14:03:41 +01:00 committed by Andreas Kling
parent 7fc4ea5495
commit 316814988f
Notes: sideshowbarker 2024-07-17 21:16:31 +09:00
4 changed files with 90 additions and 15 deletions

View File

@ -3849,6 +3849,20 @@ private:
virtual bool has_constructor() const override { return true; } 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) { for (auto const& overload_set : interface.constructor_overload_sets) {
auto constructor_generator = generator.fork(); auto constructor_generator = generator.fork();
if (overload_set.value.size() > 1) { 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 // https://webidl.spec.whatwg.org/#es-operations
for (auto const& overload_set : interface.static_overload_sets) { for (auto const& overload_set : interface.static_overload_sets) {
auto function_generator = generator.fork(); 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 // Implementation: Static Functions
for (auto& function : interface.static_functions) for (auto& function : interface.static_functions)
generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name, interface); generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name, interface);

View File

@ -282,7 +282,7 @@ NonnullRefPtr<Type const> Parser::parse_type()
return adopt_ref(*new Type(builder.to_byte_string(), nullable)); return adopt_ref(*new Type(builder.to_byte_string(), nullable));
} }
void Parser::parse_attribute(HashMap<ByteString, ByteString>& extended_attributes, Interface& interface) void Parser::parse_attribute(HashMap<ByteString, ByteString>& extended_attributes, Interface& interface, IsStatic is_static)
{ {
bool inherit = lexer.consume_specific("inherit"sv); bool inherit = lexer.consume_specific("inherit"sv);
if (inherit) if (inherit)
@ -316,7 +316,10 @@ void Parser::parse_attribute(HashMap<ByteString, ByteString>& extended_attribute
move(getter_callback_name), move(getter_callback_name),
move(setter_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) void Parser::parse_constant(Interface& interface)
@ -391,14 +394,9 @@ Vector<Parameter> Parser::parse_parameters()
return parameters; return parameters;
} }
Function Parser::parse_function(HashMap<ByteString, ByteString>& extended_attributes, Interface& interface, IsSpecialOperation is_special_operation) Function Parser::parse_function(HashMap<ByteString, ByteString>& extended_attributes, Interface& interface, IsStatic is_static, IsSpecialOperation is_special_operation)
{ {
auto position = lexer.current_position(); auto position = lexer.current_position();
bool static_ = false;
if (lexer.consume_specific("static"sv)) {
static_ = true;
consume_whitespace();
}
auto return_type = parse_type(); auto return_type = parse_type();
consume_whitespace(); consume_whitespace();
@ -414,7 +412,7 @@ Function Parser::parse_function(HashMap<ByteString, ByteString>& extended_attrib
// "Defining a special operation with an identifier is equivalent to separating the special operation out into its own declaration without an identifier." // "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 (is_special_operation == IsSpecialOperation::No || (is_special_operation == IsSpecialOperation::Yes && !name.is_empty())) {
if (!static_) if (is_static == IsStatic::No)
interface.functions.append(function); interface.functions.append(function);
else else
interface.static_functions.append(function); interface.static_functions.append(function);
@ -476,7 +474,7 @@ void Parser::parse_getter(HashMap<ByteString, ByteString>& extended_attributes,
{ {
assert_string("getter"sv); assert_string("getter"sv);
consume_whitespace(); 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) 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()); 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<ByteString, ByteString>& extended_attributes,
{ {
assert_string("setter"sv); assert_string("setter"sv);
consume_whitespace(); 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) 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()); 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<ByteString, ByteString>& extended_attributes,
{ {
assert_string("deleter"sv); assert_string("deleter"sv);
consume_whitespace(); 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) 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()); 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; 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()) if (auto legacy_namespace = interface.extended_attributes.get("LegacyNamespace"sv); legacy_namespace.has_value())
@ -1081,6 +1089,8 @@ Interface& Parser::parse()
// Resolve typedefs // Resolve typedefs
for (auto& attribute : interface.attributes) for (auto& attribute : interface.attributes)
resolve_typedef(interface, attribute.type, &attribute.extended_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) for (auto& constant : interface.constants)
resolve_typedef(interface, constant.type); resolve_typedef(interface, constant.type);
for (auto& constructor : interface.constructors) for (auto& constructor : interface.constructors)

View File

@ -30,6 +30,11 @@ private:
Yes, Yes,
}; };
enum class IsStatic {
No,
Yes,
};
Parser(Parser* parent, ByteString filename, StringView contents, ByteString import_base_path); Parser(Parser* parent, ByteString filename, StringView contents, ByteString import_base_path);
void assert_specific(char ch); void assert_specific(char ch);
@ -38,7 +43,7 @@ private:
Optional<Interface&> resolve_import(auto path); Optional<Interface&> resolve_import(auto path);
HashMap<ByteString, ByteString> parse_extended_attributes(); HashMap<ByteString, ByteString> parse_extended_attributes();
void parse_attribute(HashMap<ByteString, ByteString>& extended_attributes, Interface&); void parse_attribute(HashMap<ByteString, ByteString>& extended_attributes, Interface&, IsStatic is_static = IsStatic::No);
void parse_interface(Interface&); void parse_interface(Interface&);
void parse_namespace(Interface&); void parse_namespace(Interface&);
void parse_non_interface_entities(bool allow_interface, Interface&); void parse_non_interface_entities(bool allow_interface, Interface&);
@ -53,7 +58,7 @@ private:
void parse_deleter(HashMap<ByteString, ByteString>& extended_attributes, Interface&); void parse_deleter(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
void parse_stringifier(HashMap<ByteString, ByteString>& extended_attributes, Interface&); void parse_stringifier(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
void parse_iterable(Interface&); void parse_iterable(Interface&);
Function parse_function(HashMap<ByteString, ByteString>& extended_attributes, Interface&, IsSpecialOperation is_special_operation = IsSpecialOperation::No); Function parse_function(HashMap<ByteString, ByteString>& extended_attributes, Interface&, IsStatic is_static = IsStatic::No, IsSpecialOperation is_special_operation = IsSpecialOperation::No);
Vector<Parameter> parse_parameters(); Vector<Parameter> parse_parameters();
NonnullRefPtr<Type const> parse_type(); NonnullRefPtr<Type const> parse_type();
void parse_constant(Interface&); void parse_constant(Interface&);

View File

@ -270,6 +270,7 @@ public:
HashMap<ByteString, ByteString> extended_attributes; HashMap<ByteString, ByteString> extended_attributes;
Vector<Attribute> attributes; Vector<Attribute> attributes;
Vector<Attribute> static_attributes;
Vector<Constant> constants; Vector<Constant> constants;
Vector<Constructor> constructors; Vector<Constructor> constructors;
Vector<Function> functions; Vector<Function> functions;