From 2b78e227f2bba96ebdf10f5aa0a83e0c9fd022cb Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Mon, 13 Sep 2021 00:27:13 +0300 Subject: [PATCH] LibWeb: Add support for generating a stringifier method/attribute --- .../LibWeb/WrapperGenerator.cpp | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp index 998aac94cb..7929915f55 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp @@ -136,6 +136,8 @@ struct Interface { Vector constructors; Vector functions; Vector static_functions; + bool has_stringifier { false }; + Optional stringifier_attribute; // Added for convenience after parsing String wrapper_class; @@ -333,6 +335,16 @@ static OwnPtr parse_interface(StringView filename, StringView const& interface->constructors.append(Constructor { interface->name, move(parameters) }); }; + auto parse_stringifier = [&](HashMap& 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 extended_attributes; @@ -358,6 +370,11 @@ static OwnPtr 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 )~~~");