mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:02:45 +00:00 
			
		
		
		
	AK: Eradicate the uses of out().
This commit is contained in:
		
							parent
							
								
									61e73b1a7b
								
							
						
					
					
						commit
						88bca152c9
					
				
					 7 changed files with 475 additions and 259 deletions
				
			
		|  | @ -137,7 +137,7 @@ void IRCAppWindow::setup_actions() | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     m_close_query_action = GUI::Action::create("Close query", { Mod_Ctrl, Key_D }, Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-close-query.png"), [](auto&) { |     m_close_query_action = GUI::Action::create("Close query", { Mod_Ctrl, Key_D }, Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-close-query.png"), [](auto&) { | ||||||
|         out() << "FIXME: Implement close-query action"; |         outln("FIXME: Implement close-query action"); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     m_change_nick_action = GUI::Action::create("Change nickname", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-nick.png"), [this](auto&) { |     m_change_nick_action = GUI::Action::create("Change nickname", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-nick.png"), [this](auto&) { | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <AK/JsonObject.h> | #include <AK/JsonObject.h> | ||||||
|  | #include <AK/SourceGenerator.h> | ||||||
| #include <AK/StringBuilder.h> | #include <AK/StringBuilder.h> | ||||||
| #include <LibCore/File.h> | #include <LibCore/File.h> | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
|  | @ -48,7 +49,7 @@ static String title_casify(const String& dashy_name) | ||||||
| int main(int argc, char** argv) | int main(int argc, char** argv) | ||||||
| { | { | ||||||
|     if (argc != 2) { |     if (argc != 2) { | ||||||
|         fprintf(stderr, "usage: %s <path/to/CSS/Properties.json>\n", argv[0]); |         warnln("usage: {} <path/to/CSS/Properties.json>", argv[0]); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|     auto file = Core::File::construct(argv[1]); |     auto file = Core::File::construct(argv[1]); | ||||||
|  | @ -59,34 +60,59 @@ int main(int argc, char** argv) | ||||||
|     ASSERT(json.has_value()); |     ASSERT(json.has_value()); | ||||||
|     ASSERT(json.value().is_object()); |     ASSERT(json.value().is_object()); | ||||||
| 
 | 
 | ||||||
|     out() << "#include <AK/Assertions.h>"; |     StringBuilder builder; | ||||||
|     out() << "#include <LibWeb/CSS/PropertyID.h>"; |     SourceGenerator generator { builder }; | ||||||
|     out() << "namespace Web::CSS {"; |  | ||||||
| 
 | 
 | ||||||
|     out() << "PropertyID property_id_from_string(const StringView& string) {"; |     generator.append(R"~~~( | ||||||
|  | #include <AK/Assertions.h> | ||||||
|  | #include <LibWeb/CSS/PropertyID.h> | ||||||
|  | 
 | ||||||
|  | namespace Web::CSS { | ||||||
|  | 
 | ||||||
|  | PropertyID property_id_from_string(const StringView& string) | ||||||
|  | { | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|     json.value().as_object().for_each_member([&](auto& name, auto& value) { |     json.value().as_object().for_each_member([&](auto& name, auto& value) { | ||||||
|         ASSERT(value.is_object()); |         ASSERT(value.is_object()); | ||||||
|         out() << "    if (string.equals_ignoring_case(\"" << name << "\"))"; | 
 | ||||||
|         out() << "        return PropertyID::" << title_casify(name) << ";"; |         auto member_generator = generator.fork(); | ||||||
|  |         member_generator.set("name", name); | ||||||
|  |         member_generator.set("name:titlecase", title_casify(name)); | ||||||
|  |         member_generator.append(R"~~~( | ||||||
|  |     if (string.equals_ignoring_case("@name@")) | ||||||
|  |         return PropertyID::@name:titlecase@; | ||||||
|  | )~~~"); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     out() << "    return PropertyID::Invalid;"; |     generator.append(R"~~~( | ||||||
| 
 |     return PropertyID::Invalid; | ||||||
|     out() << "}"; | } | ||||||
| 
 | 
 | ||||||
|     out() << "const char* string_from_property_id(PropertyID property_id) {"; | const char* string_from_property_id(PropertyID property_id) { | ||||||
|     out() << "    switch (property_id) {"; |     switch (property_id) { | ||||||
|     json.value().as_object().for_each_member([&](auto& name, auto& value) { | )~~~"); | ||||||
|         ASSERT(value.is_object()); | 
 | ||||||
|         out() << "    case PropertyID::" << title_casify(name) << ":"; |     json.value().as_object().for_each_member([&](auto& name, auto& value) { | ||||||
|         out() << "        return \"" << name << "\";"; |         ASSERT(value.is_object()); | ||||||
|     }); | 
 | ||||||
|     out() << "    default:"; |         auto member_generator = generator.fork(); | ||||||
|     out() << "        return \"(invalid CSS::PropertyID)\";"; |         member_generator.set("name", name); | ||||||
|     out() << "    }"; |         member_generator.set("name:titlecase", title_casify(name)); | ||||||
|     out() << "}"; |         member_generator.append(R"~~~( | ||||||
|     out() << "}"; |     case PropertyID::@name:titlecase@: | ||||||
| 
 |         return "@name@"; | ||||||
|     return 0; |         )~~~"); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     generator.append(R"~~~( | ||||||
|  |     default: | ||||||
|  |         return "(invalid CSS::PropertyID)"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Web::CSS
 | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |     outln("{}", generator.as_string_view()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <AK/JsonObject.h> | #include <AK/JsonObject.h> | ||||||
|  | #include <AK/SourceGenerator.h> | ||||||
| #include <AK/StringBuilder.h> | #include <AK/StringBuilder.h> | ||||||
| #include <LibCore/File.h> | #include <LibCore/File.h> | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
|  | @ -48,7 +49,7 @@ static String title_casify(const String& dashy_name) | ||||||
| int main(int argc, char** argv) | int main(int argc, char** argv) | ||||||
| { | { | ||||||
|     if (argc != 2) { |     if (argc != 2) { | ||||||
|         fprintf(stderr, "usage: %s <path/to/CSS/Properties.json>\n", argv[0]); |         warnln("usage: {} <path/to/CSS/Properties.json>", argv[0]); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|     auto file = Core::File::construct(argv[1]); |     auto file = Core::File::construct(argv[1]); | ||||||
|  | @ -59,30 +60,46 @@ int main(int argc, char** argv) | ||||||
|     ASSERT(json.has_value()); |     ASSERT(json.has_value()); | ||||||
|     ASSERT(json.value().is_object()); |     ASSERT(json.value().is_object()); | ||||||
| 
 | 
 | ||||||
|     out() << "#pragma once"; |     StringBuilder builder; | ||||||
|     out() << "#include <AK/StringView.h>"; |     SourceGenerator generator { builder }; | ||||||
|     out() << "#include <AK/Traits.h>"; |     generator.append(R"~~~( | ||||||
|  | #pragma once | ||||||
| 
 | 
 | ||||||
|     out() << "namespace Web::CSS {"; | #include <AK/StringView.h> | ||||||
|     out() << "enum class PropertyID {"; | #include <AK/Traits.h> | ||||||
|     out() << "    Invalid,"; | 
 | ||||||
|  | namespace Web::CSS { | ||||||
|  | 
 | ||||||
|  | enum class PropertyID { | ||||||
|  |     Invalid, | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|     json.value().as_object().for_each_member([&](auto& name, auto& value) { |     json.value().as_object().for_each_member([&](auto& name, auto& value) { | ||||||
|         ASSERT(value.is_object()); |         ASSERT(value.is_object()); | ||||||
|         out() << "    " << title_casify(name) << ","; | 
 | ||||||
|  |         auto member_generator = generator.fork(); | ||||||
|  |         member_generator.set("name:titlecase", title_casify(name)); | ||||||
|  | 
 | ||||||
|  |         member_generator.append(R"~~~( | ||||||
|  |     @name:titlecase@, | ||||||
|  | )~~~"); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     out() << "};\n\
 |     generator.append(R"~~~( | ||||||
| PropertyID property_id_from_string(const StringView&);\n\ | }; | ||||||
| const char* string_from_property_id(PropertyID);\n\ |  | ||||||
| }\n\ |  | ||||||
| \n\ |  | ||||||
| namespace AK {\n\ |  | ||||||
| template<>\n\ |  | ||||||
| struct Traits<Web::CSS::PropertyID> : public GenericTraits<Web::CSS::PropertyID> {\n\ |  | ||||||
|     static unsigned hash(Web::CSS::PropertyID property_id) { return int_hash((unsigned)property_id); }\n\ |  | ||||||
| };\n\ |  | ||||||
| }\n"; |  | ||||||
| 
 | 
 | ||||||
|     return 0; | PropertyID property_id_from_string(const StringView&); | ||||||
|  | const char* string_from_property_id(PropertyID); | ||||||
|  | 
 | ||||||
|  | } // namespace Web::CSS
 | ||||||
|  | 
 | ||||||
|  | namespace AK { | ||||||
|  | template<> | ||||||
|  | struct Traits<Web::CSS::PropertyID> : public GenericTraits<Web::CSS::PropertyID> { | ||||||
|  |     static unsigned hash(Web::CSS::PropertyID property_id) { return int_hash((unsigned)property_id); } | ||||||
|  | }; | ||||||
|  | } // namespace AK
 | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |     outln("{}", generator.as_string_view()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| #include <AK/GenericLexer.h> | #include <AK/GenericLexer.h> | ||||||
| #include <AK/HashMap.h> | #include <AK/HashMap.h> | ||||||
| #include <AK/LexicalPath.h> | #include <AK/LexicalPath.h> | ||||||
|  | #include <AK/SourceGenerator.h> | ||||||
| #include <AK/StringBuilder.h> | #include <AK/StringBuilder.h> | ||||||
| #include <LibCore/ArgsParser.h> | #include <LibCore/ArgsParser.h> | ||||||
| #include <LibCore/File.h> | #include <LibCore/File.h> | ||||||
|  | @ -286,7 +287,7 @@ int main(int argc, char** argv) | ||||||
|     auto interface = IDL::parse_interface(data); |     auto interface = IDL::parse_interface(data); | ||||||
| 
 | 
 | ||||||
|     if (!interface) { |     if (!interface) { | ||||||
|         fprintf(stderr, "Cannot parse %s\n", path); |         warnln("Cannot parse {}", path); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -366,201 +367,301 @@ static bool is_wrappable_type(const IDL::Type& type) | ||||||
| 
 | 
 | ||||||
| static void generate_header(const IDL::Interface& interface) | static void generate_header(const IDL::Interface& interface) | ||||||
| { | { | ||||||
|     auto& wrapper_class = interface.wrapper_class; |     StringBuilder builder; | ||||||
|     auto& wrapper_base_class = interface.wrapper_base_class; |     SourceGenerator generator { builder }; | ||||||
| 
 | 
 | ||||||
|     out() << "#pragma once"; |     generator.set("name", interface.name); | ||||||
|     out() << "#include <LibWeb/Bindings/Wrapper.h>"; |     generator.set("fully_qualified_name", interface.fully_qualified_name); | ||||||
|  |     generator.set("wrapper_base_class", interface.wrapper_base_class); | ||||||
|  |     generator.set("wrapper_class", interface.wrapper_class); | ||||||
|  |     generator.set("wrapper_class:snakecase", snake_name(interface.wrapper_class)); | ||||||
| 
 | 
 | ||||||
|     // FIXME: This is very strange.
 |     generator.append(R"~~~( | ||||||
|     out() << "#if __has_include(<LibWeb/DOM/" << interface.name << ".h>)"; | #pragma once | ||||||
|     out() << "#include <LibWeb/DOM/" << interface.name << ".h>"; |  | ||||||
|     out() << "#elif __has_include(<LibWeb/HTML/" << interface.name << ".h>)"; |  | ||||||
|     out() << "#include <LibWeb/HTML/" << interface.name << ".h>"; |  | ||||||
|     out() << "#elif __has_include(<LibWeb/UIEvents/" << interface.name << ".h>)"; |  | ||||||
|     out() << "#include <LibWeb/UIEvents/" << interface.name << ".h>"; |  | ||||||
|     out() << "#elif __has_include(<LibWeb/HighResolutionTime/" << interface.name << ".h>)"; |  | ||||||
|     out() << "#include <LibWeb/HighResolutionTime/" << interface.name << ".h>"; |  | ||||||
|     out() << "#elif __has_include(<LibWeb/SVG/" << interface.name << ".h>)"; |  | ||||||
|     out() << "#include <LibWeb/SVG/" << interface.name << ".h>"; |  | ||||||
|     out() << "#endif"; |  | ||||||
| 
 | 
 | ||||||
|     if (wrapper_base_class != "Wrapper") | #include <LibWeb/Bindings/Wrapper.h> | ||||||
|         out() << "#include <LibWeb/Bindings/" << wrapper_base_class << ".h>"; |  | ||||||
| 
 | 
 | ||||||
|     out() << "namespace Web::Bindings {"; | // FIXME: This is very strange.
 | ||||||
|  | #if __has_include(<LibWeb/DOM/@name@.h>) | ||||||
|  | #    include <LibWeb/DOM/@name@.h> | ||||||
|  | #elif __has_include(<LibWeb/HTML/@name@.h>) | ||||||
|  | #    include <LibWeb/HTML/@name@.h> | ||||||
|  | #elif __has_include(<LibWeb/UIEvents/@name@.h>) | ||||||
|  | #    include <LibWeb/UIEvents/@name@.h> | ||||||
|  | #elif __has_include(<LibWeb/HighResolutionTime/@name@.h>) | ||||||
|  | #    include <LibWeb/HighResolutionTime/@name@.h> | ||||||
|  | #elif __has_include(<LibWeb/SVG/@name@.h>) | ||||||
|  | #    include <LibWeb/SVG/@name@.h> | ||||||
|  | #endif | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|     out() << "class " << wrapper_class << " : public " << wrapper_base_class << " {"; |     if (interface.wrapper_base_class != "Wrapper") { | ||||||
|     out() << "    JS_OBJECT(" << wrapper_class << ", " << wrapper_base_class << ");"; |         generator.append(R"~~~( | ||||||
|     out() << "public:"; | #include <LibWeb/Bindings/@wrapper_base_class@.h> | ||||||
|     out() << "    " << wrapper_class << "(JS::GlobalObject&, " << interface.fully_qualified_name << "&);"; | )~~~"); | ||||||
|     out() << "    virtual void initialize(JS::GlobalObject&) override;"; |  | ||||||
|     out() << "    virtual ~" << wrapper_class << "() override;"; |  | ||||||
| 
 |  | ||||||
|     if (wrapper_base_class == "Wrapper") { |  | ||||||
|         out() << "    " << interface.fully_qualified_name << "& impl() { return *m_impl; }"; |  | ||||||
|         out() << "    const " << interface.fully_qualified_name << "& impl() const { return *m_impl; }"; |  | ||||||
|     } else { |  | ||||||
|         out() << "    " << interface.fully_qualified_name << "& impl() { return static_cast<" << interface.fully_qualified_name << "&>(" << wrapper_base_class << "::impl()); }"; |  | ||||||
|         out() << "    const " << interface.fully_qualified_name << "& impl() const { return static_cast<const " << interface.fully_qualified_name << "&>(" << wrapper_base_class << "::impl()); }"; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto is_foo_wrapper_name = snake_name(String::format("Is%s", wrapper_class.characters())); |     generator.append(R"~~~( | ||||||
|     out() << "    virtual bool " << is_foo_wrapper_name << "() const final { return true; }"; | namespace Web::Bindings { | ||||||
| 
 | 
 | ||||||
|     out() << "private:"; | class @wrapper_class@ : public @wrapper_base_class@ { | ||||||
|  |     JS_OBJECT(@wrapper_class@, @wrapper_base_class@); | ||||||
|  | public: | ||||||
|  |     @wrapper_class@(JS::GlobalObject&, @fully_qualified_name@&); | ||||||
|  |     virtual void initialize(JS::GlobalObject&) override; | ||||||
|  |     virtual ~@wrapper_class@() override; | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |     if (interface.wrapper_base_class == "Wrapper") { | ||||||
|  |         generator.append(R"~~~( | ||||||
|  |     @fully_qualified_name@& impl() { return *m_impl; } | ||||||
|  |     const @fully_qualified_name@& impl() const { return *m_impl; } | ||||||
|  | )~~~"); | ||||||
|  |     } else { | ||||||
|  |         generator.append(R"~~~( | ||||||
|  |     @fully_qualified_name@& impl() { return static_cast<@fully_qualified_name@&>(@wrapper_base_class@::impl()); } | ||||||
|  |     const @fully_qualified_name@& impl() const { return static_cast<const @fully_qualified_name@&>(@wrapper_base_class@::impl()); } | ||||||
|  | )~~~"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     generator.append(R"~~~( | ||||||
|  |     virtual bool is_@wrapper_class:snakecase@() const final { return true; } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|     for (auto& function : interface.functions) { |     for (auto& function : interface.functions) { | ||||||
|         out() << "    JS_DECLARE_NATIVE_FUNCTION(" << snake_name(function.name) << ");"; |         auto function_generator = generator.fork(); | ||||||
|  |         function_generator.set("function.name:snakecase", snake_name(function.name)); | ||||||
|  |         function_generator.append(R"~~~( | ||||||
|  |     JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@); | ||||||
|  |         )~~~"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (auto& attribute : interface.attributes) { |     for (auto& attribute : interface.attributes) { | ||||||
|         out() << "    JS_DECLARE_NATIVE_GETTER(" << snake_name(attribute.name) << "_getter);"; |         auto attribute_generator = generator.fork(); | ||||||
|         if (!attribute.readonly) |         attribute_generator.set("attribute.name:snakecase", snake_name(attribute.name)); | ||||||
|             out() << "    JS_DECLARE_NATIVE_SETTER(" << snake_name(attribute.name) << "_setter);"; |         attribute_generator.append(R"~~~( | ||||||
|  |     JS_DECLARE_NATIVE_GETTER(@attribute.name:snakecase@_getter); | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |         if (!attribute.readonly) { | ||||||
|  |             attribute_generator.append(R"~~~( | ||||||
|  |     JS_DECLARE_NATIVE_SETTER(@attribute.name:snakecase@_setter); | ||||||
|  | )~~~"); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (wrapper_base_class == "Wrapper") { |     if (interface.wrapper_base_class == "Wrapper") { | ||||||
|         out() << "    NonnullRefPtr<" << interface.fully_qualified_name << "> m_impl;"; |         generator.append(R"~~~( | ||||||
|  |     NonnullRefPtr<@fully_qualified_name@> m_impl; | ||||||
|  |         )~~~"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     out() << "};"; |     generator.append(R"~~~( | ||||||
|  | }; | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|     if (should_emit_wrapper_factory(interface)) { |     if (should_emit_wrapper_factory(interface)) { | ||||||
|         out() << wrapper_class << "* wrap(JS::GlobalObject&, " << interface.fully_qualified_name << "&);"; |         generator.append(R"~~~( | ||||||
|  | @wrapper_class@* wrap(JS::GlobalObject&, @fully_qualified_name@&); | ||||||
|  | )~~~"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     out() << "}"; |     generator.append(R"~~~( | ||||||
|  | } // namespace Web::Bindings
 | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |     outln("{}", generator.as_string_view()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void generate_implementation(const IDL::Interface& interface) | void generate_implementation(const IDL::Interface& interface) | ||||||
| { | { | ||||||
|     auto& wrapper_class = interface.wrapper_class; |     StringBuilder builder; | ||||||
|     auto& wrapper_base_class = interface.wrapper_base_class; |     SourceGenerator generator { builder }; | ||||||
| 
 | 
 | ||||||
|     out() << "#include <AK/FlyString.h>"; |     generator.set("wrapper_class", interface.wrapper_class); | ||||||
|     out() << "#include <LibJS/Runtime/Array.h>"; |     generator.set("wrapper_base_class", interface.wrapper_base_class); | ||||||
|     out() << "#include <LibJS/Runtime/Value.h>"; |     generator.set("fully_qualified_name", interface.fully_qualified_name); | ||||||
|     out() << "#include <LibJS/Runtime/GlobalObject.h>"; |  | ||||||
|     out() << "#include <LibJS/Runtime/Error.h>"; |  | ||||||
|     out() << "#include <LibJS/Runtime/Function.h>"; |  | ||||||
|     out() << "#include <LibJS/Runtime/Uint8ClampedArray.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/NodeWrapperFactory.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/" << wrapper_class << ".h>"; |  | ||||||
|     out() << "#include <LibWeb/DOM/Element.h>"; |  | ||||||
|     out() << "#include <LibWeb/DOM/EventListener.h>"; |  | ||||||
|     out() << "#include <LibWeb/HTML/HTMLElement.h>"; |  | ||||||
|     out() << "#include <LibWeb/Origin.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/CommentWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/DocumentWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/DocumentFragmentWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/DocumentTypeWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/HTMLHeadElementWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/HTMLImageElementWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/ImageDataWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/TextWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>"; |  | ||||||
|     out() << "#include <LibWeb/Bindings/WindowObject.h>"; |  | ||||||
| 
 | 
 | ||||||
|     // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 |     generator.append(R"~~~( | ||||||
|     out() << "using namespace Web::DOM;"; | #include <AK/FlyString.h> | ||||||
|     out() << "using namespace Web::HTML;"; | #include <LibJS/Runtime/Array.h> | ||||||
|  | #include <LibJS/Runtime/Error.h> | ||||||
|  | #include <LibJS/Runtime/Function.h> | ||||||
|  | #include <LibJS/Runtime/GlobalObject.h> | ||||||
|  | #include <LibJS/Runtime/Uint8ClampedArray.h> | ||||||
|  | #include <LibJS/Runtime/Value.h> | ||||||
|  | #include <LibWeb/Bindings/@wrapper_class@.h> | ||||||
|  | #include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/CommentWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/DocumentFragmentWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/DocumentTypeWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/DocumentWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/HTMLCanvasElementWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/HTMLHeadElementWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/HTMLImageElementWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/ImageDataWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/NodeWrapperFactory.h> | ||||||
|  | #include <LibWeb/Bindings/TextWrapper.h> | ||||||
|  | #include <LibWeb/Bindings/WindowObject.h> | ||||||
|  | #include <LibWeb/DOM/Element.h> | ||||||
|  | #include <LibWeb/DOM/EventListener.h> | ||||||
|  | #include <LibWeb/HTML/HTMLElement.h> | ||||||
|  | #include <LibWeb/Origin.h> | ||||||
| 
 | 
 | ||||||
|     out() << "namespace Web::Bindings {"; | // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 | ||||||
|  | using namespace Web::DOM; | ||||||
|  | using namespace Web::HTML; | ||||||
| 
 | 
 | ||||||
|     // Implementation: Wrapper constructor
 | namespace Web::Bindings { | ||||||
|     out() << wrapper_class << "::" << wrapper_class << "(JS::GlobalObject& global_object, " << interface.fully_qualified_name << "& impl)"; | 
 | ||||||
|     if (wrapper_base_class == "Wrapper") { | )~~~"); | ||||||
|         out() << "    : Wrapper(*global_object.object_prototype())"; | 
 | ||||||
|         out() << "    , m_impl(impl)"; |     if (interface.wrapper_base_class == "Wrapper") { | ||||||
|  |         generator.append(R"~~~( | ||||||
|  | @wrapper_class@::@wrapper_class@(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | ||||||
|  | : Wrapper(*global_object.object_prototype()) | ||||||
|  | , m_impl(impl) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | )~~~"); | ||||||
|     } else { |     } else { | ||||||
|         out() << "    : " << wrapper_base_class << "(global_object, impl)"; |         generator.append(R"~~~( | ||||||
|  | @wrapper_class@::@wrapper_class@(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | ||||||
|  | : @wrapper_base_class@(global_object, impl) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | )~~~"); | ||||||
|     } |     } | ||||||
|     out() << "{"; |  | ||||||
|     out() << "}"; |  | ||||||
| 
 | 
 | ||||||
|     // Implementation: Wrapper initialize()
 |     generator.append(R"~~~( | ||||||
|     out() << "void " << wrapper_class << "::initialize(JS::GlobalObject& global_object)"; | void @wrapper_class@::initialize(JS::GlobalObject& global_object) | ||||||
|     out() << "{"; | { | ||||||
|     out() << "    [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable;"; |     [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable; | ||||||
|     out() << "    " << wrapper_base_class << "::initialize(global_object);"; | 
 | ||||||
|  |     @wrapper_base_class@::initialize(global_object); | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|     for (auto& attribute : interface.attributes) { |     for (auto& attribute : interface.attributes) { | ||||||
|         out() << "    define_native_property(\"" << attribute.name << "\", " << attribute.getter_callback_name << ", " << (attribute.readonly ? "nullptr" : attribute.setter_callback_name) << ", default_attributes);"; |         auto attribute_generator = generator.fork(); | ||||||
|  |         attribute_generator.set("attribute.name", attribute.name); | ||||||
|  |         attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name); | ||||||
|  | 
 | ||||||
|  |         if (attribute.readonly) | ||||||
|  |             attribute_generator.set("attribute.setter_callback", "nullptr"); | ||||||
|  |         else | ||||||
|  |             attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name); | ||||||
|  | 
 | ||||||
|  |         attribute_generator.append(R"~~~( | ||||||
|  |     define_native_property("@attribute.name@", @attribute.getter_callback@, @attribute.setter_callback@, default_attributes); | ||||||
|  | )~~~"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (auto& function : interface.functions) { |     for (auto& function : interface.functions) { | ||||||
|         out() << "    define_native_function(\"" << function.name << "\", " << snake_name(function.name) << ", " << function.length() << ", default_attributes);"; |         auto function_generator = generator.fork(); | ||||||
|  |         function_generator.set("function.name", function.name); | ||||||
|  |         function_generator.set("function.name:snakecase", snake_name(function.name)); | ||||||
|  |         function_generator.set("function.name:length", String::number(function.name.length())); | ||||||
|  | 
 | ||||||
|  |         function_generator.append(R"~~~( | ||||||
|  |     define_native_function("@function.name@", @function.name:snakecase@, @function.name:length@, default_attributes); | ||||||
|  | )~~~"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     out() << "}"; |     generator.append(R"~~~( | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     // Implementation: Wrapper destructor
 | @wrapper_class@::~@wrapper_class@() | ||||||
|     out() << wrapper_class << "::~" << wrapper_class << "()"; | { | ||||||
|     out() << "{"; | } | ||||||
|     out() << "}"; | )~~~"); | ||||||
| 
 | 
 | ||||||
|     // Implementation: impl_from()
 |  | ||||||
|     if (!interface.attributes.is_empty() || !interface.functions.is_empty()) { |     if (!interface.attributes.is_empty() || !interface.functions.is_empty()) { | ||||||
|         out() << "static " << interface.fully_qualified_name << "* impl_from(JS::VM& vm, JS::GlobalObject& global_object)"; |         generator.append(R"~~~( | ||||||
|         out() << "{"; | static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_object) | ||||||
|         out() << "    auto* this_object = vm.this_value(global_object).to_object(global_object);"; | { | ||||||
|         out() << "    if (!this_object)"; |     auto* this_object = vm.this_value(global_object).to_object(global_object); | ||||||
|         out() << "        return {};"; |     if (!this_object) | ||||||
|         out() << "    if (!this_object->inherits(\"" << wrapper_class << "\")) {"; |         return {}; | ||||||
|         out() << "        vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, \"" << interface.fully_qualified_name << "\");"; |     if (!this_object->inherits("@wrapper_class@")) { | ||||||
|         out() << "        return nullptr;"; |         vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "@fully_qualified_name@"); | ||||||
|         out() << "    }"; |         return nullptr; | ||||||
|         out() << "    return &static_cast<" << wrapper_class << "*>(this_object)->impl();"; |  | ||||||
|         out() << "}"; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto generate_to_cpp = [&](auto& parameter, auto& js_name, auto& js_suffix, auto cpp_name, bool return_void = false) { |     return &static_cast<@wrapper_class@*>(this_object)->impl(); | ||||||
|         auto generate_return = [&] { |     } | ||||||
|             if (return_void) | )~~~"); | ||||||
|                 out() << "        return;"; |     } | ||||||
|             else | 
 | ||||||
|                 out() << "        return {};"; |     auto generate_to_cpp = [&](auto& parameter, auto& js_name, const auto& js_suffix, auto cpp_name, bool return_void = false) { | ||||||
|         }; |         auto scoped_generator = generator.fork(); | ||||||
|  |         scoped_generator.set("cpp_name", cpp_name); | ||||||
|  |         scoped_generator.set("js_name", js_name); | ||||||
|  |         scoped_generator.set("js_suffix", js_suffix); | ||||||
|  |         scoped_generator.set("parameter.type.name", parameter.type.name); | ||||||
|  | 
 | ||||||
|  |         if (return_void) | ||||||
|  |             scoped_generator.set("return_statement", "return;"); | ||||||
|  |         else | ||||||
|  |             scoped_generator.set("return_statement", "return {};"); | ||||||
|  | 
 | ||||||
|         if (parameter.type.name == "DOMString") { |         if (parameter.type.name == "DOMString") { | ||||||
|             out() << "    auto " << cpp_name << " = " << js_name << js_suffix << ".to_string(global_object);"; |             scoped_generator.append(R"~~~( | ||||||
|             out() << "    if (vm.exception())"; |     auto @cpp_name@ = @js_name@@js_suffix@.to_string(global_object); | ||||||
|             generate_return(); |     if (vm.exception()) | ||||||
|  |         @return_statement@ | ||||||
|  | )~~~"); | ||||||
|         } else if (parameter.type.name == "EventListener") { |         } else if (parameter.type.name == "EventListener") { | ||||||
|             out() << "    if (!" << js_name << js_suffix << ".is_function()) {"; |             scoped_generator.append(R"~~~( | ||||||
|             out() << "        vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, \"Function\");"; |     if (!@js_name@@js_suffix@.is_function()) { | ||||||
|             generate_return(); |         vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Function"); | ||||||
|             out() << "    }"; |         @return_statement@ | ||||||
|             out() << "    auto " << cpp_name << " = adopt(*new EventListener(JS::make_handle(&" << js_name << js_suffix << ".as_function())));"; |     } | ||||||
|  |     auto @cpp_name@ = adopt(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function()))); | ||||||
|  | )~~~"); | ||||||
|         } else if (is_wrappable_type(parameter.type)) { |         } else if (is_wrappable_type(parameter.type)) { | ||||||
|             out() << "    auto " << cpp_name << "_object = " << js_name << js_suffix << ".to_object(global_object);"; |             scoped_generator.append(R"~~~( | ||||||
|             out() << "    if (vm.exception())"; |     auto @cpp_name@_object = @js_name@@js_suffix@.to_object(global_object); | ||||||
|             generate_return(); |     if (vm.exception()) | ||||||
|             out() << "    if (!" << cpp_name << "_object->inherits(\"" << parameter.type.name << "Wrapper\")) {"; |         @return_statement@ | ||||||
|             out() << "        vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, \"" << parameter.type.name << "\");"; | 
 | ||||||
|             generate_return(); |     if (!@cpp_name@_object->inherits("@parameter.type.name@Wrapper")) { | ||||||
|             out() << "    }"; |         vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "@parameter.type.name@"); | ||||||
|             out() << "    auto& " << cpp_name << " = static_cast<" << parameter.type.name << "Wrapper*>(" << cpp_name << "_object)->impl();"; |         @return_statement@ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto& @cpp_name@ = static_cast<@parameter.type.name@Wrapper*>(@cpp_name@_object)->impl(); | ||||||
|  | )~~~"); | ||||||
|         } else if (parameter.type.name == "double") { |         } else if (parameter.type.name == "double") { | ||||||
|             out() << "    auto " << cpp_name << " = " << js_name << js_suffix << ".to_double(global_object);"; |             scoped_generator.append(R"~~~( | ||||||
|             out() << "    if (vm.exception())"; |     auto @cpp_name@ = @js_name@@js_suffix@.to_double(global_object); | ||||||
|             generate_return(); |     if (vm.exception()) | ||||||
|  |         @return_statement@ | ||||||
|  | )~~~"); | ||||||
|         } else if (parameter.type.name == "boolean") { |         } else if (parameter.type.name == "boolean") { | ||||||
|             out() << "    auto " << cpp_name << " = " << js_name << js_suffix << ".to_boolean();"; |             scoped_generator.append(R"~~~( | ||||||
|  |     auto @cpp_name@ = @js_name@@js_suffix@.to_boolean(); | ||||||
|  | )~~~"); | ||||||
|         } else { |         } else { | ||||||
|             dbg() << "Unimplemented JS-to-C++ conversion: " << parameter.type.name; |             dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name); | ||||||
|             ASSERT_NOT_REACHED(); |             ASSERT_NOT_REACHED(); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     auto generate_arguments = [&](auto& parameters, auto& arguments_builder, bool return_void = false) { |     auto generate_arguments = [&](auto& parameters, auto& arguments_builder, bool return_void = false) { | ||||||
|  |         auto arguments_generator = generator.fork(); | ||||||
|  | 
 | ||||||
|         Vector<String> parameter_names; |         Vector<String> parameter_names; | ||||||
|         size_t argument_index = 0; |         size_t argument_index = 0; | ||||||
|         for (auto& parameter : parameters) { |         for (auto& parameter : parameters) { | ||||||
|             parameter_names.append(snake_name(parameter.name)); |             parameter_names.append(snake_name(parameter.name)); | ||||||
|             out() << "    auto arg" << argument_index << " = vm.argument(" << argument_index << ");"; |             arguments_generator.set("argument.index", String::number(argument_index)); | ||||||
|             generate_to_cpp(parameter, "arg", argument_index, snake_name(parameter.name), return_void); | 
 | ||||||
|  |             arguments_generator.append(R"~~~( | ||||||
|  |     auto arg@argument.index@ = vm.argument(@argument.index@); | ||||||
|  | )~~~"); | ||||||
|  |             generate_to_cpp(parameter, "arg", String::number(argument_index), snake_name(parameter.name), return_void); | ||||||
|             ++argument_index; |             ++argument_index; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -568,126 +669,200 @@ void generate_implementation(const IDL::Interface& interface) | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     auto generate_return_statement = [&](auto& return_type) { |     auto generate_return_statement = [&](auto& return_type) { | ||||||
|  |         auto scoped_generator = generator.fork(); | ||||||
|  |         scoped_generator.set("return_type", return_type.name); | ||||||
|  | 
 | ||||||
|         if (return_type.name == "void") { |         if (return_type.name == "void") { | ||||||
|             out() << "    return JS::js_undefined();"; |             scoped_generator.append(R"~~~( | ||||||
|  |     return JS::js_undefined(); | ||||||
|  | )~~~"); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (return_type.nullable) { |         if (return_type.nullable) { | ||||||
|             if (return_type.name == "DOMString") { |             if (return_type.name == "DOMString") { | ||||||
|                 out() << "    if (retval.is_null())"; |                 scoped_generator.append(R"~~~( | ||||||
|  |     if (retval.is_null()) | ||||||
|  |         return JS::js_null(); | ||||||
|  | )~~~"); | ||||||
|             } else { |             } else { | ||||||
|                 out() << "    if (!retval)"; |                 scoped_generator.append(R"~~~( | ||||||
|  |     if (!retval) | ||||||
|  |         return JS::js_null(); | ||||||
|  | )~~~"); | ||||||
|             } |             } | ||||||
|             out() << "        return JS::js_null();"; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (return_type.name == "DOMString") { |         if (return_type.name == "DOMString") { | ||||||
|             out() << "    return JS::js_string(vm, retval);"; |             scoped_generator.append(R"~~~( | ||||||
|  |     return JS::js_string(vm, retval); | ||||||
|  | )~~~"); | ||||||
|         } else if (return_type.name == "ArrayFromVector") { |         } else if (return_type.name == "ArrayFromVector") { | ||||||
|             // FIXME: Remove this fake type hack once it's no longer needed.
 |             // FIXME: Remove this fake type hack once it's no longer needed.
 | ||||||
|             //        Basically once we have NodeList we can throw this out.
 |             //        Basically once we have NodeList we can throw this out.
 | ||||||
|             out() << "    auto* new_array = JS::Array::create(global_object);"; |             scoped_generator.append(R"~~~( | ||||||
|             out() << "    for (auto& element : retval) {"; |     auto* new_array = JS::Array::create(global_object); | ||||||
|             out() << "        new_array->indexed_properties().append(wrap(global_object, element));"; |     for (auto& element : retval) | ||||||
|             out() << "    }"; |         new_array->indexed_properties().append(wrap(global_object, element)); | ||||||
|             out() << "    return new_array;"; | 
 | ||||||
|         } else if (return_type.name == "long" || return_type.name == "double") { |     return new_array; | ||||||
|             out() << "    return JS::Value(retval);"; | )~~~"); | ||||||
|  |         } else if (return_type.name == "long" || return_type.name == "double" || return_type.name == "boolean") { | ||||||
|  |             scoped_generator.append(R"~~~( | ||||||
|  |     return JS::Value(retval); | ||||||
|  | )~~~"); | ||||||
|         } else if (return_type.name == "Uint8ClampedArray") { |         } else if (return_type.name == "Uint8ClampedArray") { | ||||||
|             out() << "    return retval;"; |             scoped_generator.append(R"~~~( | ||||||
|         } else if (return_type.name == "boolean") { |     return retval; | ||||||
|             out() << "    return JS::Value(retval);"; | )~~~"); | ||||||
|         } else { |         } else { | ||||||
|             out() << "    return wrap(global_object, const_cast<" << return_type.name << "&>(*retval));"; |             scoped_generator.append(R"~~~( | ||||||
|  |     return wrap(global_object, const_cast<@return_type@&>(*retval)); | ||||||
|  | )~~~"); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Implementation: Attributes
 |  | ||||||
|     for (auto& attribute : interface.attributes) { |     for (auto& attribute : interface.attributes) { | ||||||
|         out() << "JS_DEFINE_NATIVE_GETTER(" << wrapper_class << "::" << attribute.getter_callback_name << ")"; |         auto attribute_generator = generator.fork(); | ||||||
|         out() << "{"; |         attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name); | ||||||
|         out() << "    auto* impl = impl_from(vm, global_object);"; |         attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name); | ||||||
|         out() << "    if (!impl)"; |         attribute_generator.set("attribute.name:snakecase", snake_name(attribute.name)); | ||||||
|         out() << "        return {};"; |  | ||||||
| 
 |  | ||||||
|         if (attribute.extended_attributes.contains("ReturnNullIfCrossOrigin")) { |  | ||||||
|             out() << "    if (!impl->may_access_from_origin(static_cast<WindowObject&>(global_object).origin()))"; |  | ||||||
|             out() << "        return JS::js_null();"; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (attribute.extended_attributes.contains("Reflect")) { |         if (attribute.extended_attributes.contains("Reflect")) { | ||||||
|             auto attribute_name = attribute.extended_attributes.get("Reflect").value(); |             auto attribute_name = attribute.extended_attributes.get("Reflect").value(); | ||||||
|             if (attribute_name.is_null()) |             if (attribute_name.is_null()) | ||||||
|                 attribute_name = attribute.name; |                 attribute_name = attribute.name; | ||||||
|             attribute_name = make_input_acceptable_cpp(attribute_name); |             attribute_name = make_input_acceptable_cpp(attribute_name); | ||||||
|             out() << "    auto retval = impl->attribute(HTML::AttributeNames::" << attribute_name << ");"; | 
 | ||||||
|  |             attribute_generator.set("attribute.reflect_name", attribute_name); | ||||||
|         } else { |         } else { | ||||||
|             out() << "    auto retval = impl->" << snake_name(attribute.name) << "();"; |             attribute_generator.set("attribute.reflect_name", snake_name(attribute.name)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         attribute_generator.append(R"~~~( | ||||||
|  | JS_DEFINE_NATIVE_GETTER(@wrapper_class@::@attribute.getter_callback@) | ||||||
|  | { | ||||||
|  |     auto* impl = impl_from(vm, global_object); | ||||||
|  |     if (!impl) | ||||||
|  |         return {}; | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |         if (attribute.extended_attributes.contains("ReturnNullIfCrossOrigin")) { | ||||||
|  |             attribute_generator.append(R"~~~( | ||||||
|  |     if (!impl->may_access_from_origin(static_cast<WindowObject&>(global_object).origin())) | ||||||
|  |         return JS::js_null(); | ||||||
|  | )~~~"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (attribute.extended_attributes.contains("Reflect")) { | ||||||
|  |             attribute_generator.append(R"~~~( | ||||||
|  |     auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@); | ||||||
|  | )~~~"); | ||||||
|  |         } else { | ||||||
|  |             attribute_generator.append(R"~~~( | ||||||
|  |     auto retval = impl->@attribute.name:snakecase@(); | ||||||
|  | )~~~"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         generate_return_statement(attribute.type); |         generate_return_statement(attribute.type); | ||||||
|         out() << "}"; | 
 | ||||||
|  |         attribute_generator.append(R"~~~( | ||||||
|  | } | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|         if (!attribute.readonly) { |         if (!attribute.readonly) { | ||||||
|             out() << "JS_DEFINE_NATIVE_SETTER(" << wrapper_class << "::" << attribute.setter_callback_name << ")"; |             attribute_generator.append(R"~~~( | ||||||
|             out() << "{"; | JS_DEFINE_NATIVE_SETTER(@wrapper_class@::@attribute.setter_callback@) | ||||||
|             out() << "    auto* impl = impl_from(vm, global_object);"; | { | ||||||
|             out() << "    if (!impl)"; |     auto* impl = impl_from(vm, global_object); | ||||||
|             out() << "        return;"; |     if (!impl) | ||||||
|  |         return; | ||||||
|  | )~~~"); | ||||||
| 
 | 
 | ||||||
|             generate_to_cpp(attribute, "value", "", "cpp_value", true); |             generate_to_cpp(attribute, "value", "", "cpp_value", true); | ||||||
| 
 | 
 | ||||||
|             if (attribute.extended_attributes.contains("Reflect")) { |             if (attribute.extended_attributes.contains("Reflect")) { | ||||||
|                 auto attribute_name = attribute.extended_attributes.get("Reflect").value(); |                 attribute_generator.append(R"~~~( | ||||||
|                 if (attribute_name.is_null()) |     impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value); | ||||||
|                     attribute_name = attribute.name; | )~~~"); | ||||||
|                 attribute_name = make_input_acceptable_cpp(attribute_name); |  | ||||||
|                 out() << "    impl->set_attribute(HTML::AttributeNames::" << attribute_name << ", cpp_value);"; |  | ||||||
|             } else { |             } else { | ||||||
|                 out() << "    impl->set_" << snake_name(attribute.name) << "(cpp_value);"; |                 attribute_generator.append(R"~~~( | ||||||
|  |     impl->set_@attribute.name:snakecase@(cpp_value); | ||||||
|  | )~~~"); | ||||||
|             } |             } | ||||||
|             out() << "}"; | 
 | ||||||
|  |             attribute_generator.append(R"~~~( | ||||||
|  | } | ||||||
|  | )~~~"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Implementation: Functions
 |     // Implementation: Functions
 | ||||||
|     for (auto& function : interface.functions) { |     for (auto& function : interface.functions) { | ||||||
|         out() << "JS_DEFINE_NATIVE_FUNCTION(" << wrapper_class << "::" << snake_name(function.name) << ")"; |         auto function_generator = generator.fork(); | ||||||
|         out() << "{"; |         function_generator.set("function.name", function.name); | ||||||
|         out() << "    auto* impl = impl_from(vm, global_object);"; |         function_generator.set("function.name:snakecase", snake_name(function.name)); | ||||||
|         out() << "    if (!impl)"; |         function_generator.set("function.nargs", String::number(function.length())); | ||||||
|         out() << "        return {};"; | 
 | ||||||
|  |         function_generator.append(R"~~~(\
 | ||||||
|  | JS_DEFINE_NATIVE_FUNCTION(@wrapper_class@::@function.name:snakecase@) | ||||||
|  | { | ||||||
|  |     auto* impl = impl_from(vm, global_object); | ||||||
|  |     if (!impl) | ||||||
|  |         return {}; | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|         if (function.length() > 0) { |         if (function.length() > 0) { | ||||||
|             out() << "    if (vm.argument_count() < " << function.length() << ") {"; |             if (function.length() == 1) { | ||||||
|             if (function.length() == 1) |                 function_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountOne"); | ||||||
|                 out() << "        vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountOne, \"" << function.name << "\");"; |                 function_generator.set(".arg_count_suffix", ""); | ||||||
|             else |             } else { | ||||||
|                 out() << "        vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");"; |                 function_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountMany"); | ||||||
|             out() << "        return {};"; |                 function_generator.set(".arg_count_suffix", String::formatted(", \"{}\"", function.length())); | ||||||
|             out() << "    }"; |             } | ||||||
|  | 
 | ||||||
|  |             function_generator.append(R"~~~( | ||||||
|  |     if (vm.argument_count() < @function.nargs@) { | ||||||
|  |         vm.throw_exception<JS::TypeError>(global_object, @.bad_arg_count@, "@function.name@"@.arg_count_suffix@); | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  | )~~~"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         StringBuilder arguments_builder; |         StringBuilder arguments_builder; | ||||||
|         generate_arguments(function.parameters, arguments_builder); |         generate_arguments(function.parameters, arguments_builder); | ||||||
| 
 | 
 | ||||||
|  |         function_generator.set(".arguments", arguments_builder.string_view()); | ||||||
|  | 
 | ||||||
|         if (function.return_type.name != "void") { |         if (function.return_type.name != "void") { | ||||||
|             out() << "    auto retval = impl->" << snake_name(function.name) << "(" << arguments_builder.to_string() << ");"; |             function_generator.append(R"~~~( | ||||||
|  |     auto retval = impl->@function.name:snakecase@(@.arguments@); | ||||||
|  | )~~~"); | ||||||
|         } else { |         } else { | ||||||
|             out() << "    impl->" << snake_name(function.name) << "(" << arguments_builder.to_string() << ");"; |             function_generator.append(R"~~~( | ||||||
|  |     impl->@function.name:snakecase@(@.arguments@); | ||||||
|  | )~~~"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         generate_return_statement(function.return_type); |         generate_return_statement(function.return_type); | ||||||
|         out() << "}"; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // Implementation: Wrapper factory
 |         function_generator.append(R"~~~( | ||||||
|     if (should_emit_wrapper_factory(interface)) { | } | ||||||
|         out() << wrapper_class << "* wrap(JS::GlobalObject& global_object, " << interface.fully_qualified_name << "& impl)"; | )~~~"); | ||||||
|         out() << "{"; |     } | ||||||
|         out() << "    return static_cast<" << wrapper_class << "*>(wrap_impl(global_object, impl));"; | 
 | ||||||
|         out() << "}"; |     if (should_emit_wrapper_factory(interface)) { | ||||||
|     } |         generator.append(R"~~~( | ||||||
| 
 | @wrapper_class@* wrap(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | ||||||
|     out() << "}"; | { | ||||||
|  |     return static_cast<@wrapper_class@*>(wrap_impl(global_object, impl)); | ||||||
|  | } | ||||||
|  | )~~~"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     generator.append(R"~~~( | ||||||
|  | } // namespace Web::Bindings
 | ||||||
|  | )~~~"); | ||||||
|  | 
 | ||||||
|  |     outln("{}", generator.as_string_view()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -34,6 +34,6 @@ int main(int argc, char** argv) | ||||||
|     args_parser.add_positional_argument(path, "Path", "path"); |     args_parser.add_positional_argument(path, "Path", "path"); | ||||||
|     args_parser.parse(argc, argv); |     args_parser.parse(argc, argv); | ||||||
| 
 | 
 | ||||||
|     out() << LexicalPath(path).dirname().characters(); |     outln("{}", LexicalPath(path).dirname()); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -126,7 +126,7 @@ int main(int argc, char** argv) | ||||||
|         if (current_symbol < symbols.end() && !current_symbol->contains(virtual_offset)) { |         if (current_symbol < symbols.end() && !current_symbol->contains(virtual_offset)) { | ||||||
|             if (!is_first_symbol && current_instruction_is_in_symbol) { |             if (!is_first_symbol && current_instruction_is_in_symbol) { | ||||||
|                 // The previous instruction was part of a symbol that doesn't cover the current instruction, so separate it from the current instruction with a newline.
 |                 // The previous instruction was part of a symbol that doesn't cover the current instruction, so separate it from the current instruction with a newline.
 | ||||||
|                 out(); |                 outln(); | ||||||
|                 current_instruction_is_in_symbol = (current_symbol + 1 < symbols.end() && (current_symbol + 1)->contains(virtual_offset)); |                 current_instruction_is_in_symbol = (current_symbol + 1 < symbols.end() && (current_symbol + 1)->contains(virtual_offset)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -134,21 +134,19 @@ int main(int argc, char** argv) | ||||||
|             while (current_symbol + 1 < symbols.end() && !(current_symbol + 1)->contains(virtual_offset) && (current_symbol + 1)->address() <= virtual_offset) { |             while (current_symbol + 1 < symbols.end() && !(current_symbol + 1)->contains(virtual_offset) && (current_symbol + 1)->address() <= virtual_offset) { | ||||||
|                 ++current_symbol; |                 ++current_symbol; | ||||||
|                 if (!is_first_symbol) |                 if (!is_first_symbol) | ||||||
|                     out() << "\n(" << current_symbol->name << " (" << String::format("%08x-%08x", current_symbol->address(), current_symbol->address_end()) << "))\n"; |                     outln("\n({} ({:p}-{:p}))\n", current_symbol->name, current_symbol->address(), current_symbol->address_end()); | ||||||
|             } |             } | ||||||
|             while (current_symbol + 1 < symbols.end() && (current_symbol + 1)->contains(virtual_offset)) { |             while (current_symbol + 1 < symbols.end() && (current_symbol + 1)->contains(virtual_offset)) { | ||||||
|                 if (!is_first_symbol && !current_instruction_is_in_symbol) |                 if (!is_first_symbol && !current_instruction_is_in_symbol) | ||||||
|                     out(); |                     outln(); | ||||||
|                 ++current_symbol; |                 ++current_symbol; | ||||||
|                 current_instruction_is_in_symbol = true; |                 current_instruction_is_in_symbol = true; | ||||||
|                 out() << current_symbol->name << " (" << String::format("%08x-%08x", current_symbol->address(), current_symbol->address_end()) << "):"; |                 outln("{} ({:p}-{:p}):", current_symbol->name, current_symbol->address(), current_symbol->address_end()); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             is_first_symbol = false; |             is_first_symbol = false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         out() << String::format("%08x", virtual_offset) << "  " << insn.value().to_string(virtual_offset, symbol_provider); |         outln("{:p}  {}", virtual_offset, insn.value().to_string(virtual_offset, symbol_provider)); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -85,7 +85,7 @@ int main(int argc, char** argv) | ||||||
|         } |         } | ||||||
|         for (; !tar_stream.finished(); tar_stream.advance()) { |         for (; !tar_stream.finished(); tar_stream.advance()) { | ||||||
|             if (list || verbose) |             if (list || verbose) | ||||||
|                 out() << tar_stream.header().file_name(); |                 outln("{}", tar_stream.header().file_name()); | ||||||
| 
 | 
 | ||||||
|             if (extract) { |             if (extract) { | ||||||
|                 Tar::TarFileStream file_stream = tar_stream.file_contents(); |                 Tar::TarFileStream file_stream = tar_stream.file_contents(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 asynts
						asynts