From 3eff6024b112c66754b2f8cc46bc7720462f6993 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 24 Jul 2020 12:59:47 +0200 Subject: [PATCH] LibWeb: Add code generation for reflecting IDL attributes You can now tag reflecting attributes with [Reflect] to generate code that does basic DOM element attribute get/set. (This patch also makes it easy to add more extended attributes like that going forward.) From the HTML spec: "Some IDL attributes are defined to reflect a particular content attribute. This means that on getting, the IDL attribute returns the current value of the content attribute, and on setting, the IDL attribute changes the value of the content attribute to the given value." --- .../CodeGenerators/WrapperGenerator.cpp | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp index 51e6c67c4d..4e5da81a23 100644 --- a/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp +++ b/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -65,6 +66,7 @@ struct Function { Type return_type; String name; Vector parameters; + HashMap extended_attributes; size_t length() const { @@ -78,6 +80,7 @@ struct Attribute { bool unsigned_ { false }; Type type; String name; + HashMap extended_attributes; // Added for convenience after parsing String getter_callback_name; @@ -174,7 +177,7 @@ OwnPtr parse_interface(const StringView& input) return Type { name, nullable }; }; - auto parse_attribute = [&] { + auto parse_attribute = [&](HashMap& extended_attributes) { bool readonly = false; bool unsigned_ = false; if (next_is("readonly")) { @@ -202,10 +205,11 @@ OwnPtr parse_interface(const StringView& input) attribute.name = name; attribute.getter_callback_name = String::format("%s_getter", snake_name(attribute.name).characters()); attribute.setter_callback_name = String::format("%s_setter", snake_name(attribute.name).characters()); + attribute.extended_attributes = move(extended_attributes); interface->attributes.append(move(attribute)); }; - auto parse_function = [&] { + auto parse_function = [&](HashMap& extended_attributes) { auto return_type = parse_type(); consume_whitespace(); auto name = consume_while([](auto ch) { return !isspace(ch) && ch != '('; }); @@ -228,22 +232,45 @@ OwnPtr parse_interface(const StringView& input) consume_specific(';'); - interface->functions.append(Function { return_type, name, move(parameters) }); + interface->functions.append(Function { return_type, name, move(parameters), move(extended_attributes) }); + }; + + auto parse_extended_attributes = [&] { + HashMap extended_attributes; + for (;;) { + consume_whitespace(); + if (consume_if(']')) + break; + auto name = consume_while([](auto ch) { return ch != ']' && ch != '=' && ch != ','; }); + if (consume_if('=')) { + auto value = consume_while([](auto ch) { return ch != ']' && ch != ','; }); + extended_attributes.set(name, value); + } else { + extended_attributes.set(name, {}); + } + } + consume_whitespace(); + return extended_attributes; }; for (;;) { + HashMap extended_attributes; consume_whitespace(); if (consume_if('}')) break; + if (consume_if('[')) { + extended_attributes = parse_extended_attributes(); + } + if (next_is("readonly") || next_is("attribute")) { - parse_attribute(); + parse_attribute(extended_attributes); continue; } - parse_function(); + parse_function(extended_attributes); } interface->wrapper_class = String::format("%sWrapper", interface->name.characters()); @@ -569,7 +596,13 @@ void generate_implementation(const IDL::Interface& interface) out() << " auto* impl = impl_from(interpreter, global_object);"; out() << " if (!impl)"; out() << " return {};"; - out() << " auto retval = impl->" << snake_name(attribute.name) << "();"; + + if (attribute.extended_attributes.contains("Reflect")) { + out() << " auto retval = impl->attribute(HTML::AttributeNames::" << attribute.name << ");"; + } else { + out() << " auto retval = impl->" << snake_name(attribute.name) << "();"; + } + generate_return_statement(attribute.type); out() << "}"; @@ -582,7 +615,11 @@ void generate_implementation(const IDL::Interface& interface) generate_to_cpp(attribute, "value", "", "cpp_value", true); - out() << " impl->set_" << snake_name(attribute.name) << "(cpp_value);"; + if (attribute.extended_attributes.contains("Reflect")) { + out() << " impl->set_attribute(HTML::AttributeNames::" << attribute.name << ", cpp_value);"; + } else { + out() << " impl->set_" << snake_name(attribute.name) << "(cpp_value);"; + } out() << "}"; } }