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; }
)~~~");
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);

View File

@ -282,7 +282,7 @@ NonnullRefPtr<Type const> Parser::parse_type()
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);
if (inherit)
@ -316,7 +316,10 @@ void Parser::parse_attribute(HashMap<ByteString, ByteString>& 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<Parameter> Parser::parse_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();
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<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."
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<ByteString, ByteString>& 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<ByteString, ByteString>& 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<ByteString, ByteString>& 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)

View File

@ -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<Interface&> resolve_import(auto path);
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_namespace(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_stringifier(HashMap<ByteString, ByteString>& extended_attributes, 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();
NonnullRefPtr<Type const> parse_type();
void parse_constant(Interface&);

View File

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