1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:28:11 +00:00

LibWeb: Add support for generating a stringifier method/attribute

This commit is contained in:
Idan Horowitz 2021-09-13 00:27:13 +03:00 committed by Andreas Kling
parent 47e261c691
commit 2b78e227f2

View file

@ -136,6 +136,8 @@ struct Interface {
Vector<Constructor> constructors;
Vector<Function> functions;
Vector<Function> static_functions;
bool has_stringifier { false };
Optional<String> stringifier_attribute;
// Added for convenience after parsing
String wrapper_class;
@ -333,6 +335,16 @@ static OwnPtr<Interface> parse_interface(StringView filename, StringView const&
interface->constructors.append(Constructor { interface->name, move(parameters) });
};
auto parse_stringifier = [&](HashMap<String, String>& extended_attributes) {
assert_string("stringifier");
interface->has_stringifier = true;
if (lexer.next_is("readonly") || lexer.next_is("attribute")) {
parse_attribute(extended_attributes);
interface->stringifier_attribute = interface->attributes.last().name;
}
assert_specific(';');
};
for (;;) {
HashMap<String, String> extended_attributes;
@ -358,6 +370,11 @@ static OwnPtr<Interface> parse_interface(StringView filename, StringView const&
continue;
}
if (lexer.next_is("stringifier")) {
parse_stringifier(extended_attributes);
continue;
}
if (lexer.next_is("readonly") || lexer.next_is("attribute")) {
parse_attribute(extended_attributes);
continue;
@ -1378,6 +1395,13 @@ private:
)~~~");
}
if (interface.has_stringifier) {
auto stringifier_generator = generator.fork();
stringifier_generator.append(R"~~~(
JS_DECLARE_NATIVE_FUNCTION(to_string);
)~~~");
}
for (auto& attribute : interface.attributes) {
auto attribute_generator = generator.fork();
attribute_generator.set("attribute.name:snakecase", attribute.name.to_snakecase());
@ -1565,12 +1589,19 @@ void @prototype_class@::initialize(JS::GlobalObject& global_object)
)~~~");
}
if (interface.has_stringifier) {
auto stringifier_generator = generator.fork();
stringifier_generator.append(R"~~~(
define_native_function("toString", to_string, 0, default_attributes);
)~~~");
}
generator.append(R"~~~(
Object::initialize(global_object);
}
)~~~");
if (!interface.attributes.is_empty() || !interface.functions.is_empty()) {
if (!interface.attributes.is_empty() || !interface.functions.is_empty() || interface.has_stringifier) {
generator.append(R"~~~(
static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_object)
{
@ -1703,6 +1734,41 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@)
generate_function(generator, function, StaticFunction::No, interface.prototype_class, interface.fully_qualified_name);
}
if (interface.has_stringifier) {
auto stringifier_generator = generator.fork();
stringifier_generator.set("class_name", interface.prototype_class);
if (interface.stringifier_attribute.has_value())
stringifier_generator.set("attribute.cpp_getter_name", interface.stringifier_attribute->to_snakecase());
stringifier_generator.append(R"~~~(
JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
{
auto* impl = impl_from(vm, global_object);
if (!impl)
return {};
)~~~");
if (interface.stringifier_attribute.has_value()) {
stringifier_generator.append(R"~~~(
auto retval = impl->@attribute.cpp_getter_name@();
)~~~");
} else {
stringifier_generator.append(R"~~~(
auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->to_string(); });
if (should_return_empty(result))
return JS::Value();
auto retval = result.release_value();
)~~~");
}
stringifier_generator.append(R"~~~(
return JS::js_string(vm, move(retval));
}
)~~~");
}
generator.append(R"~~~(
} // namespace Web::Bindings
)~~~");