| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  |  * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> | 
					
						
							| 
									
										
										
										
											2021-04-22 22:51:19 +02:00
										 |  |  |  * Copyright (c) 2021, Linus Groh <linusg@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/ByteBuffer.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-17 16:57:17 +01:00
										 |  |  | #include <AK/Debug.h>
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  | #include <AK/GenericLexer.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  | #include <AK/HashMap.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  | #include <AK/LexicalPath.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-19 14:35:34 +02:00
										 |  |  | #include <AK/OwnPtr.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #include <AK/SourceGenerator.h>
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							|  |  |  | #include <LibCore/ArgsParser.h>
 | 
					
						
							|  |  |  | #include <LibCore/File.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 17:10:41 +01:00
										 |  |  | static String make_input_acceptable_cpp(const String& input) | 
					
						
							| 
									
										
										
										
											2020-07-24 13:23:47 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-28 20:15:04 +00:00
										 |  |  |     if (input.is_one_of("class", "template", "for", "default", "char", "namespace")) { | 
					
						
							| 
									
										
										
										
											2020-07-24 13:23:47 +02:00
										 |  |  |         StringBuilder builder; | 
					
						
							|  |  |  |         builder.append(input); | 
					
						
							|  |  |  |         builder.append('_'); | 
					
						
							|  |  |  |         return builder.to_string(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-09 17:10:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     String input_without_dashes = input; | 
					
						
							|  |  |  |     input_without_dashes.replace("-", "_"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return input_without_dashes; | 
					
						
							| 
									
										
										
										
											2020-07-24 13:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 19:36:03 +01:00
										 |  |  | static void report_parsing_error(StringView message, StringView filename, StringView input, size_t offset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // FIXME: Spaghetti code ahead.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size_t lineno = 1; | 
					
						
							|  |  |  |     size_t colno = 1; | 
					
						
							|  |  |  |     size_t start_line = 0; | 
					
						
							|  |  |  |     size_t line_length = 0; | 
					
						
							|  |  |  |     for (size_t index = 0; index < input.length(); ++index) { | 
					
						
							|  |  |  |         if (offset == index) | 
					
						
							|  |  |  |             colno = index - start_line + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (input[index] == '\n') { | 
					
						
							|  |  |  |             if (index >= offset) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             start_line = index + 1; | 
					
						
							|  |  |  |             line_length = 0; | 
					
						
							|  |  |  |             ++lineno; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             ++line_length; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     StringBuilder error_message; | 
					
						
							|  |  |  |     error_message.appendff("{}\n", input.substring_view(start_line, line_length)); | 
					
						
							|  |  |  |     for (size_t i = 0; i < colno - 1; ++i) | 
					
						
							|  |  |  |         error_message.append(' '); | 
					
						
							|  |  |  |     error_message.append("\033[1;31m^\n"); | 
					
						
							|  |  |  |     error_message.appendff("{}:{}: error: {}\033[0m\n", filename, lineno, message); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     warnln("{}", error_message.string_view()); | 
					
						
							|  |  |  |     exit(EXIT_FAILURE); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | namespace IDL { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  | template<typename FunctionType> | 
					
						
							|  |  |  | static size_t get_function_length(FunctionType& function) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     size_t length = 0; | 
					
						
							|  |  |  |     for (auto& parameter : function.parameters) { | 
					
						
							|  |  |  |         if (!parameter.optional) | 
					
						
							|  |  |  |             length++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return length; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | struct Type { | 
					
						
							|  |  |  |     String name; | 
					
						
							|  |  |  |     bool nullable { false }; | 
					
						
							| 
									
										
										
										
											2021-04-03 15:51:15 +02:00
										 |  |  |     bool is_string() const { return name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Parameter { | 
					
						
							|  |  |  |     Type type; | 
					
						
							|  |  |  |     String name; | 
					
						
							| 
									
										
										
										
											2020-11-13 06:08:06 +00:00
										 |  |  |     bool optional { false }; | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |     Optional<String> optional_default_value; | 
					
						
							| 
									
										
										
										
											2021-05-04 21:38:07 +01:00
										 |  |  |     HashMap<String, String> extended_attributes; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Function { | 
					
						
							|  |  |  |     Type return_type; | 
					
						
							|  |  |  |     String name; | 
					
						
							|  |  |  |     Vector<Parameter> parameters; | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |     HashMap<String, String> extended_attributes; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |     size_t length() const { return get_function_length(*this); } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Constructor { | 
					
						
							|  |  |  |     String name; | 
					
						
							|  |  |  |     Vector<Parameter> parameters; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size_t length() const { return get_function_length(*this); } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  | struct Constant { | 
					
						
							|  |  |  |     Type type; | 
					
						
							|  |  |  |     String name; | 
					
						
							|  |  |  |     String value; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | struct Attribute { | 
					
						
							|  |  |  |     bool readonly { false }; | 
					
						
							|  |  |  |     Type type; | 
					
						
							|  |  |  |     String name; | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |     HashMap<String, String> extended_attributes; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Added for convenience after parsing
 | 
					
						
							|  |  |  |     String getter_callback_name; | 
					
						
							|  |  |  |     String setter_callback_name; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Interface { | 
					
						
							|  |  |  |     String name; | 
					
						
							|  |  |  |     String parent_name; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 17:03:43 +01:00
										 |  |  |     HashMap<String, String> extended_attributes; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     Vector<Attribute> attributes; | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  |     Vector<Constant> constants; | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |     Vector<Constructor> constructors; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     Vector<Function> functions; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Added for convenience after parsing
 | 
					
						
							|  |  |  |     String wrapper_class; | 
					
						
							|  |  |  |     String wrapper_base_class; | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  |     String fully_qualified_name; | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  |     String constructor_class; | 
					
						
							|  |  |  |     String prototype_class; | 
					
						
							| 
									
										
										
										
											2021-01-18 11:36:34 +01:00
										 |  |  |     String prototype_base_class; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 19:36:03 +01:00
										 |  |  | static OwnPtr<Interface> parse_interface(StringView filename, const StringView& input) | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     auto interface = make<Interface>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     GenericLexer lexer(input); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     auto assert_specific = [&](char ch) { | 
					
						
							| 
									
										
										
										
											2020-12-04 19:36:03 +01:00
										 |  |  |         if (!lexer.consume_specific(ch)) | 
					
						
							|  |  |  |             report_parsing_error(String::formatted("expected '{}'", ch), filename, input, lexer.tell()); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto consume_whitespace = [&] { | 
					
						
							| 
									
										
										
										
											2020-12-04 19:36:03 +01:00
										 |  |  |         bool consumed = true; | 
					
						
							|  |  |  |         while (consumed) { | 
					
						
							|  |  |  |             consumed = lexer.consume_while([](char ch) { return isspace(ch); }).length() > 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (lexer.consume_specific("//")) { | 
					
						
							|  |  |  |                 lexer.consume_until('\n'); | 
					
						
							|  |  |  |                 consumed = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     auto assert_string = [&](const StringView& expected) { | 
					
						
							| 
									
										
										
										
											2020-12-04 19:36:03 +01:00
										 |  |  |         if (!lexer.consume_specific(expected)) | 
					
						
							|  |  |  |             report_parsing_error(String::formatted("expected '{}'", expected), filename, input, lexer.tell()); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 17:03:43 +01:00
										 |  |  |     auto parse_extended_attributes = [&] { | 
					
						
							|  |  |  |         HashMap<String, String> extended_attributes; | 
					
						
							|  |  |  |         for (;;) { | 
					
						
							|  |  |  |             consume_whitespace(); | 
					
						
							|  |  |  |             if (lexer.consume_specific(']')) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             auto name = lexer.consume_until([](auto ch) { return ch == ']' || ch == '=' || ch == ','; }); | 
					
						
							|  |  |  |             if (lexer.consume_specific('=')) { | 
					
						
							|  |  |  |                 auto value = lexer.consume_until([](auto ch) { return ch == ']' || ch == ','; }); | 
					
						
							|  |  |  |                 extended_attributes.set(name, value); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 extended_attributes.set(name, {}); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             lexer.consume_specific(','); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         return extended_attributes; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (lexer.consume_specific('[')) | 
					
						
							|  |  |  |         interface->extended_attributes = parse_extended_attributes(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     assert_string("interface"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     interface->name = lexer.consume_until([](auto ch) { return isspace(ch); }); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     if (lexer.consume_specific(':')) { | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         interface->parent_name = lexer.consume_until([](auto ch) { return isspace(ch); }); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |     assert_specific('{'); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto parse_type = [&] { | 
					
						
							| 
									
										
										
										
											2021-01-23 17:56:55 +01:00
										 |  |  |         bool unsigned_ = lexer.consume_specific("unsigned"); | 
					
						
							|  |  |  |         if (unsigned_) | 
					
						
							|  |  |  |             consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '?'; }); | 
					
						
							|  |  |  |         auto nullable = lexer.consume_specific('?'); | 
					
						
							| 
									
										
										
										
											2021-01-23 17:56:55 +01:00
										 |  |  |         StringBuilder builder; | 
					
						
							|  |  |  |         if (unsigned_) | 
					
						
							|  |  |  |             builder.append("unsigned "); | 
					
						
							|  |  |  |         builder.append(name); | 
					
						
							|  |  |  |         return Type { builder.to_string(), nullable }; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |     auto parse_attribute = [&](HashMap<String, String>& extended_attributes) { | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         bool readonly = lexer.consume_specific("readonly"); | 
					
						
							|  |  |  |         if (readonly) | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |             consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (lexer.consume_specific("attribute")) | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |             consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         auto type = parse_type(); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; }); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2021-01-23 13:23:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         assert_specific(';'); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         Attribute attribute; | 
					
						
							|  |  |  |         attribute.readonly = readonly; | 
					
						
							|  |  |  |         attribute.type = type; | 
					
						
							|  |  |  |         attribute.name = name; | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         attribute.getter_callback_name = String::formatted("{}_getter", attribute.name.to_snakecase()); | 
					
						
							|  |  |  |         attribute.setter_callback_name = String::formatted("{}_setter", attribute.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         attribute.extended_attributes = move(extended_attributes); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         interface->attributes.append(move(attribute)); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  |     auto parse_constant = [&] { | 
					
						
							|  |  |  |         lexer.consume_specific("const"); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Constant constant; | 
					
						
							|  |  |  |         constant.type = parse_type(); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         constant.name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '='; }); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         lexer.consume_specific('='); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         constant.value = lexer.consume_while([](auto ch) { return !isspace(ch) && ch != ';'; }); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         assert_specific(';'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         interface->constants.append(move(constant)); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |     auto parse_parameters = [&] { | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         Vector<Parameter> parameters; | 
					
						
							|  |  |  |         for (;;) { | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |             if (lexer.next_is(')')) | 
					
						
							| 
									
										
										
										
											2020-06-22 18:39:22 +02:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2021-05-04 21:38:07 +01:00
										 |  |  |             HashMap<String, String> extended_attributes; | 
					
						
							|  |  |  |             if (lexer.consume_specific('[')) | 
					
						
							|  |  |  |                 extended_attributes = parse_extended_attributes(); | 
					
						
							| 
									
										
										
										
											2020-11-13 06:08:06 +00:00
										 |  |  |             bool optional = lexer.consume_specific("optional"); | 
					
						
							|  |  |  |             if (optional) | 
					
						
							|  |  |  |                 consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |             auto type = parse_type(); | 
					
						
							|  |  |  |             consume_whitespace(); | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |             auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ',' || ch == ')' || ch == '='; }); | 
					
						
							| 
									
										
										
										
											2021-05-04 21:38:07 +01:00
										 |  |  |             Parameter parameter = { move(type), move(name), optional, {}, extended_attributes }; | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |             consume_whitespace(); | 
					
						
							|  |  |  |             if (lexer.next_is(')')) { | 
					
						
							|  |  |  |                 parameters.append(parameter); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (lexer.next_is('=') && optional) { | 
					
						
							|  |  |  |                 assert_specific('='); | 
					
						
							|  |  |  |                 consume_whitespace(); | 
					
						
							|  |  |  |                 auto default_value = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ',' || ch == ')'; }); | 
					
						
							|  |  |  |                 parameter.optional_default_value = default_value; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             parameters.append(parameter); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |             if (lexer.next_is(')')) | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |             assert_specific(','); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |             consume_whitespace(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |         return parameters; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |     auto parse_function = [&](HashMap<String, String>& extended_attributes) { | 
					
						
							|  |  |  |         auto return_type = parse_type(); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '('; }); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         assert_specific('('); | 
					
						
							|  |  |  |         auto parameters = parse_parameters(); | 
					
						
							|  |  |  |         assert_specific(')'); | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         assert_specific(';'); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         interface->functions.append(Function { return_type, name, move(parameters), move(extended_attributes) }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |     auto parse_constructor = [&] { | 
					
						
							|  |  |  |         assert_string("constructor"); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         assert_specific('('); | 
					
						
							|  |  |  |         auto parameters = parse_parameters(); | 
					
						
							|  |  |  |         assert_specific(')'); | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  |         assert_specific(';'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         interface->constructors.append(Constructor { interface->name, move(parameters) }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         HashMap<String, String> extended_attributes; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         consume_whitespace(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-09 21:26:42 +00:00
										 |  |  |         if (lexer.consume_specific('}')) { | 
					
						
							|  |  |  |             consume_whitespace(); | 
					
						
							|  |  |  |             assert_specific(';'); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2020-12-09 21:26:42 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         if (lexer.consume_specific('[')) { | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |             extended_attributes = parse_extended_attributes(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:25:51 +01:00
										 |  |  |         if (lexer.next_is("constructor")) { | 
					
						
							|  |  |  |             parse_constructor(); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  |         if (lexer.next_is("const")) { | 
					
						
							|  |  |  |             parse_constant(); | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 09:51:57 -04:00
										 |  |  |         if (lexer.next_is("readonly") || lexer.next_is("attribute")) { | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |             parse_attribute(extended_attributes); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         parse_function(extended_attributes); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 14:05:46 +01:00
										 |  |  |     interface->wrapper_class = String::formatted("{}Wrapper", interface->name); | 
					
						
							|  |  |  |     interface->wrapper_base_class = String::formatted("{}Wrapper", interface->parent_name.is_empty() ? String::empty() : interface->parent_name); | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  |     interface->constructor_class = String::formatted("{}Constructor", interface->name); | 
					
						
							|  |  |  |     interface->prototype_class = String::formatted("{}Prototype", interface->name); | 
					
						
							| 
									
										
										
										
											2021-01-18 11:36:34 +01:00
										 |  |  |     interface->prototype_base_class = String::formatted("{}Prototype", interface->parent_name.is_empty() ? "Object" : interface->parent_name); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return interface; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  | static void generate_constructor_header(const IDL::Interface&); | 
					
						
							|  |  |  | static void generate_constructor_implementation(const IDL::Interface&); | 
					
						
							|  |  |  | static void generate_prototype_header(const IDL::Interface&); | 
					
						
							|  |  |  | static void generate_prototype_implementation(const IDL::Interface&); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | static void generate_header(const IDL::Interface&); | 
					
						
							|  |  |  | static void generate_implementation(const IDL::Interface&); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char** argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Core::ArgsParser args_parser; | 
					
						
							|  |  |  |     const char* path = nullptr; | 
					
						
							|  |  |  |     bool header_mode = false; | 
					
						
							|  |  |  |     bool implementation_mode = false; | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  |     bool constructor_header_mode = false; | 
					
						
							|  |  |  |     bool constructor_implementation_mode = false; | 
					
						
							|  |  |  |     bool prototype_header_mode = false; | 
					
						
							|  |  |  |     bool prototype_implementation_mode = false; | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     args_parser.add_option(header_mode, "Generate the wrapper .h file", "header", 'H'); | 
					
						
							|  |  |  |     args_parser.add_option(implementation_mode, "Generate the wrapper .cpp file", "implementation", 'I'); | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  |     args_parser.add_option(constructor_header_mode, "Generate the constructor .h file", "constructor-header", 'C'); | 
					
						
							|  |  |  |     args_parser.add_option(constructor_implementation_mode, "Generate the constructor .cpp file", "constructor-implementation", 'O'); | 
					
						
							|  |  |  |     args_parser.add_option(prototype_header_mode, "Generate the prototype .h file", "prototype-header", 'P'); | 
					
						
							|  |  |  |     args_parser.add_option(prototype_implementation_mode, "Generate the prototype .cpp file", "prototype-implementation", 'R'); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     args_parser.add_positional_argument(path, "IDL file", "idl-file"); | 
					
						
							|  |  |  |     args_parser.parse(argc, argv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 13:56:43 +04:30
										 |  |  |     auto file_or_error = Core::File::open(path, Core::OpenMode::ReadOnly); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     if (file_or_error.is_error()) { | 
					
						
							| 
									
										
										
										
											2021-05-31 15:10:43 +01:00
										 |  |  |         warnln("Failed to open {}: {}", path, file_or_error.error()); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  |     LexicalPath lexical_path(path); | 
					
						
							|  |  |  |     auto namespace_ = lexical_path.parts().at(lexical_path.parts().size() - 2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     auto data = file_or_error.value()->read_all(); | 
					
						
							| 
									
										
										
										
											2020-12-04 19:36:03 +01:00
										 |  |  |     auto interface = IDL::parse_interface(path, data); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!interface) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         warnln("Cannot parse {}", path); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  |     if (namespace_.is_one_of("CSS", "DOM", "HTML", "UIEvents", "HighResolutionTime", "NavigationTiming", "SVG", "XHR")) { | 
					
						
							| 
									
										
										
										
											2020-07-26 19:37:56 +02:00
										 |  |  |         StringBuilder builder; | 
					
						
							|  |  |  |         builder.append(namespace_); | 
					
						
							|  |  |  |         builder.append("::"); | 
					
						
							|  |  |  |         builder.append(interface->name); | 
					
						
							|  |  |  |         interface->fully_qualified_name = builder.to_string(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         interface->fully_qualified_name = interface->name; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 23:59:27 +01:00
										 |  |  |     if constexpr (WRAPPER_GENERATOR_DEBUG) { | 
					
						
							| 
									
										
										
										
											2021-01-17 16:57:17 +01:00
										 |  |  |         dbgln("Attributes:"); | 
					
						
							|  |  |  |         for (auto& attribute : interface->attributes) { | 
					
						
							|  |  |  |             dbgln("  {}{}{} {}", | 
					
						
							|  |  |  |                 attribute.readonly ? "readonly " : "", | 
					
						
							|  |  |  |                 attribute.type.name, | 
					
						
							|  |  |  |                 attribute.type.nullable ? "?" : "", | 
					
						
							|  |  |  |                 attribute.name); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-17 16:57:17 +01:00
										 |  |  |         dbgln("Functions:"); | 
					
						
							|  |  |  |         for (auto& function : interface->functions) { | 
					
						
							|  |  |  |             dbgln("  {}{} {}", | 
					
						
							|  |  |  |                 function.return_type.name, | 
					
						
							|  |  |  |                 function.return_type.nullable ? "?" : "", | 
					
						
							|  |  |  |                 function.name); | 
					
						
							|  |  |  |             for (auto& parameter : function.parameters) { | 
					
						
							|  |  |  |                 dbgln("    {}{} {}", | 
					
						
							|  |  |  |                     parameter.type.name, | 
					
						
							|  |  |  |                     parameter.type.nullable ? "?" : "", | 
					
						
							|  |  |  |                     parameter.name); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (header_mode) | 
					
						
							|  |  |  |         generate_header(*interface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (implementation_mode) | 
					
						
							|  |  |  |         generate_implementation(*interface); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  |     if (constructor_header_mode) | 
					
						
							|  |  |  |         generate_constructor_header(*interface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (constructor_implementation_mode) | 
					
						
							|  |  |  |         generate_constructor_implementation(*interface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (prototype_header_mode) | 
					
						
							|  |  |  |         generate_prototype_header(*interface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (prototype_implementation_mode) | 
					
						
							|  |  |  |         generate_prototype_implementation(*interface); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  | static bool should_emit_wrapper_factory(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // FIXME: This is very hackish.
 | 
					
						
							| 
									
										
										
										
											2020-11-27 13:54:58 +01:00
										 |  |  |     if (interface.name == "Event") | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  |     if (interface.name == "EventTarget") | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (interface.name == "Node") | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (interface.name == "Text") | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (interface.name == "Document") | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (interface.name == "DocumentType") | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (interface.name.ends_with("Element")) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-22 18:39:22 +02:00
										 |  |  | static bool is_wrappable_type(const IDL::Type& type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (type.name == "Node") | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (type.name == "Document") | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (type.name == "Text") | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (type.name == "DocumentType") | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (type.name.ends_with("Element")) | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2021-05-04 22:38:36 +01:00
										 |  |  |     if (type.name.ends_with("Event")) | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2020-06-22 18:39:22 +02:00
										 |  |  |     if (type.name == "ImageData") | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | template<typename ParameterType> | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  | static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, const String& js_name, const String& js_suffix, const String& cpp_name, bool return_void = false, bool legacy_null_to_empty_string = false, bool optional = false, Optional<String> optional_default_value = {}) | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     auto scoped_generator = generator.fork(); | 
					
						
							|  |  |  |     scoped_generator.set("cpp_name", make_input_acceptable_cpp(cpp_name)); | 
					
						
							|  |  |  |     scoped_generator.set("js_name", js_name); | 
					
						
							|  |  |  |     scoped_generator.set("js_suffix", js_suffix); | 
					
						
							|  |  |  |     scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false"); | 
					
						
							|  |  |  |     scoped_generator.set("parameter.type.name", parameter.type.name); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |     if (optional_default_value.has_value()) | 
					
						
							|  |  |  |         scoped_generator.set("parameter.optional_default_value", *optional_default_value); | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     if (return_void) | 
					
						
							|  |  |  |         scoped_generator.set("return_statement", "return;"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         scoped_generator.set("return_statement", "return {};"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |     // FIXME: Add support for optional, nullable and default values to all types
 | 
					
						
							| 
									
										
										
										
											2021-03-08 16:14:56 +01:00
										 |  |  |     if (parameter.type.is_string()) { | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         if (!optional) { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto @cpp_name@ = @js_name@@js_suffix@.to_string(global_object, @legacy_null_to_empty_string@); | 
					
						
							|  |  |  |     if (vm.exception()) | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     String @cpp_name@; | 
					
						
							|  |  |  |     if (!@js_name@@js_suffix@.is_undefined()) { | 
					
						
							|  |  |  |         @cpp_name@ = @js_name@@js_suffix@.to_string(global_object, @legacy_null_to_empty_string@); | 
					
						
							|  |  |  |         if (vm.exception()) | 
					
						
							|  |  |  |             @return_statement@ | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |     })~~~"); | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |             if (optional_default_value.has_value()) { | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |                 scoped_generator.append(R"~~~( else { | 
					
						
							|  |  |  |         @cpp_name@ = @parameter.optional_default_value@; | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } else if (parameter.type.name == "EventListener") { | 
					
						
							| 
									
										
										
										
											2021-04-10 18:51:29 +02:00
										 |  |  |         if (parameter.type.nullable) { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     RefPtr<EventListener> @cpp_name@; | 
					
						
							|  |  |  |     if (!@js_name@@js_suffix@.is_null()) { | 
					
						
							|  |  |  |         if (!@js_name@@js_suffix@.is_function()) { | 
					
						
							|  |  |  |             vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Function"); | 
					
						
							|  |  |  |             @return_statement@ | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-04-23 16:46:57 +02:00
										 |  |  |         @cpp_name@ = adopt_ref(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function()))); | 
					
						
							| 
									
										
										
										
											2021-04-10 18:51:29 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     if (!@js_name@@js_suffix@.is_function()) { | 
					
						
							|  |  |  |         vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "Function"); | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-23 16:46:57 +02:00
										 |  |  |     auto @cpp_name@ = adopt_ref(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function()))); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-04-10 18:51:29 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     } else if (is_wrappable_type(parameter.type)) { | 
					
						
							|  |  |  |         scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto @cpp_name@_object = @js_name@@js_suffix@.to_object(global_object); | 
					
						
							|  |  |  |     if (vm.exception()) | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!is<@parameter.type.name@Wrapper>(@cpp_name@_object)) { | 
					
						
							|  |  |  |         vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "@parameter.type.name@"); | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& @cpp_name@ = static_cast<@parameter.type.name@Wrapper*>(@cpp_name@_object)->impl(); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } else if (parameter.type.name == "double") { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:34:44 +03:00
										 |  |  |         if (!optional) { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     double @cpp_name@ = @js_name@@js_suffix@.to_double(global_object); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     if (vm.exception()) | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-04-15 20:34:44 +03:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |             if (optional_default_value.has_value()) { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:34:44 +03:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     double @cpp_name@; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     Optional<double> @cpp_name@; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     if (!@js_name@@js_suffix@.is_undefined()) { | 
					
						
							|  |  |  |         @cpp_name@ = @js_name@@js_suffix@.to_double(global_object); | 
					
						
							|  |  |  |         if (vm.exception()) | 
					
						
							|  |  |  |             @return_statement@ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |             if (optional_default_value.has_value()) { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:34:44 +03:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         @cpp_name@ = @parameter.optional_default_value@; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     } else if (parameter.type.name == "boolean") { | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |         if (!optional) { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     bool @cpp_name@ = @js_name@@js_suffix@.to_boolean(); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |             if (optional_default_value.has_value()) { | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     bool @cpp_name@; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:32:15 +03:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |     Optional<bool> @cpp_name@; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     if (!@js_name@@js_suffix@.is_undefined()) | 
					
						
							|  |  |  |         @cpp_name@ = @js_name@@js_suffix@.to_boolean();)~~~"); | 
					
						
							| 
									
										
										
										
											2021-06-15 13:37:49 +02:00
										 |  |  |             if (optional_default_value.has_value()) { | 
					
						
							| 
									
										
										
										
											2021-04-10 19:28:07 +01:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         @cpp_name@ = @parameter.optional_default_value@; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     } else if (parameter.type.name == "unsigned long") { | 
					
						
							|  |  |  |         scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto @cpp_name@ = @js_name@@js_suffix@.to_u32(global_object); | 
					
						
							|  |  |  |     if (vm.exception()) | 
					
						
							| 
									
										
										
										
											2021-04-24 13:54:24 +02:00
										 |  |  |         @return_statement@ | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } else if (parameter.type.name == "unsigned short") { | 
					
						
							|  |  |  |         scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto @cpp_name@ = (u16)@js_name@@js_suffix@.to_u32(global_object); | 
					
						
							|  |  |  |     if (vm.exception()) | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         @return_statement@ | 
					
						
							| 
									
										
										
										
											2021-04-26 16:36:40 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |     } else if (parameter.type.name == "long") { | 
					
						
							|  |  |  |         scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto @cpp_name@ = @js_name@@js_suffix@.to_i32(global_object); | 
					
						
							|  |  |  |     if (vm.exception()) | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |     } else if (parameter.type.name == "EventHandler") { | 
					
						
							|  |  |  |         // x.onfoo = function() { ... }
 | 
					
						
							|  |  |  |         scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     HTML::EventHandler @cpp_name@; | 
					
						
							|  |  |  |     if (@js_name@@js_suffix@.is_function()) { | 
					
						
							|  |  |  |         @cpp_name@.callback = JS::make_handle(&@js_name@@js_suffix@.as_function()); | 
					
						
							|  |  |  |     } else if (@js_name@@js_suffix@.is_string()) { | 
					
						
							|  |  |  |         @cpp_name@.string = @js_name@@js_suffix@.as_string().string(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         @return_statement@ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name); | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |         VERIFY_NOT_REACHED(); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-11 01:33:18 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | template<typename FunctionType> | 
					
						
							|  |  |  | static void generate_argument_count_check(SourceGenerator& generator, FunctionType& function) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto argument_count_check_generator = generator.fork(); | 
					
						
							|  |  |  |     argument_count_check_generator.set("function.name", function.name); | 
					
						
							|  |  |  |     argument_count_check_generator.set("function.nargs", String::number(function.length())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (function.length() == 0) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if (function.length() == 1) { | 
					
						
							|  |  |  |         argument_count_check_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountOne"); | 
					
						
							|  |  |  |         argument_count_check_generator.set(".arg_count_suffix", ""); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         argument_count_check_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountMany"); | 
					
						
							|  |  |  |         argument_count_check_generator.set(".arg_count_suffix", String::formatted(", \"{}\"", function.length())); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     argument_count_check_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 {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-04-11 01:33:18 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void generate_arguments(SourceGenerator& generator, const Vector<IDL::Parameter>& parameters, StringBuilder& arguments_builder, bool return_void = false) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto arguments_generator = generator.fork(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<String> parameter_names; | 
					
						
							|  |  |  |     size_t argument_index = 0; | 
					
						
							|  |  |  |     for (auto& parameter : parameters) { | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         parameter_names.append(make_input_acceptable_cpp(parameter.name.to_snakecase())); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         arguments_generator.set("argument.index", String::number(argument_index)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         arguments_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto arg@argument.index@ = vm.argument(@argument.index@); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-05-04 21:38:07 +01:00
										 |  |  |         bool legacy_null_to_empty_string = parameter.extended_attributes.contains("LegacyNullToEmptyString"); | 
					
						
							|  |  |  |         generate_to_cpp(generator, parameter, "arg", String::number(argument_index), parameter.name.to_snakecase(), return_void, legacy_null_to_empty_string, parameter.optional, parameter.optional_default_value); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         ++argument_index; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     arguments_builder.join(", ", parameter_names); | 
					
						
							| 
									
										
										
										
											2021-04-11 01:33:18 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | static void generate_header(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     SourceGenerator generator { builder }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.set("name", interface.name); | 
					
						
							|  |  |  |     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); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |     generator.set("wrapper_class:snakecase", interface.wrapper_class.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/Wrapper.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FIXME: This is very strange.
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | #if __has_include(<LibWeb/CSS/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/CSS/@name@.h>
 | 
					
						
							|  |  |  | #elif __has_include(<LibWeb/DOM/@name@.h>)
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #    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>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  | #elif __has_include(<LibWeb/NavigationTiming/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/NavigationTiming/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #elif __has_include(<LibWeb/SVG/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/SVG/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:23:17 +01:00
										 |  |  | #elif __has_include(<LibWeb/XHR/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/XHR/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (interface.wrapper_base_class != "Wrapper") { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  | #include <LibWeb/Bindings/@wrapper_base_class@.h>
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class @wrapper_class@ : public @wrapper_base_class@ { | 
					
						
							| 
									
										
										
										
											2021-04-20 11:47:57 +02:00
										 |  |  |     JS_OBJECT(@name@, @wrapper_base_class@); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     static @wrapper_class@* create(JS::GlobalObject&, @fully_qualified_name@&); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     @wrapper_class@(JS::GlobalObject&, @fully_qualified_name@&); | 
					
						
							|  |  |  |     virtual void initialize(JS::GlobalObject&) override; | 
					
						
							|  |  |  |     virtual ~@wrapper_class@() override; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 17:03:43 +01:00
										 |  |  |     if (interface.extended_attributes.contains("CustomGet")) { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-04-12 00:08:28 +02:00
										 |  |  |     virtual JS::Value get(const JS::PropertyName&, JS::Value receiver = {}, bool without_side_effects = false) const override; | 
					
						
							| 
									
										
										
										
											2021-04-22 20:44:30 +02:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (interface.extended_attributes.contains("CustomGetByIndex")) { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-06-16 20:39:39 +03:00
										 |  |  |     virtual JS::Value get_by_index(u32 property_index, bool without_side_effects = false) const override; | 
					
						
							| 
									
										
										
										
											2021-03-14 17:03:43 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (interface.extended_attributes.contains("CustomPut")) { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  |     virtual bool put(const JS::PropertyName&, JS::Value, JS::Value receiver = {}) override; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     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; } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         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()); } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     if (interface.wrapper_base_class == "Wrapper") { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  |     NonnullRefPtr<@fully_qualified_name@> m_impl; | 
					
						
							|  |  |  |         )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:27:41 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (should_emit_wrapper_factory(interface)) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  | @wrapper_class@* wrap(JS::GlobalObject&, @fully_qualified_name@&); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | } // namespace Web::Bindings
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     outln("{}", generator.as_string_view()); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void generate_implementation(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     SourceGenerator generator { builder }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 09:50:00 +01:00
										 |  |  |     generator.set("name", interface.name); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.set("wrapper_class", interface.wrapper_class); | 
					
						
							|  |  |  |     generator.set("wrapper_base_class", interface.wrapper_base_class); | 
					
						
							| 
									
										
										
										
											2021-01-18 11:36:34 +01:00
										 |  |  |     generator.set("prototype_class", interface.prototype_class); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.set("fully_qualified_name", interface.fully_qualified_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | #include <AK/FlyString.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Array.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Error.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Function.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:33:26 +04:30
										 |  |  | #include <LibJS/Runtime/TypedArray.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #include <LibJS/Runtime/Value.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 11:36:34 +01:00
										 |  |  | #include <LibWeb/Bindings/@prototype_class@.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #include <LibWeb/Bindings/@wrapper_class@.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/CommentWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-13 06:08:06 +00:00
										 |  |  | #include <LibWeb/Bindings/DOMImplementationWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #include <LibWeb/Bindings/DocumentFragmentWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/DocumentTypeWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/DocumentWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-21 18:32:39 +00:00
										 |  |  | #include <LibWeb/Bindings/EventTargetWrapperFactory.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-10 18:51:29 +02:00
										 |  |  | #include <LibWeb/Bindings/EventWrapperFactory.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-22 21:11:20 +02:00
										 |  |  | #include <LibWeb/Bindings/HTMLCollectionWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-20 11:50:29 +02:00
										 |  |  | #include <LibWeb/Bindings/HTMLFormElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #include <LibWeb/Bindings/HTMLHeadElementWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/HTMLImageElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-02 17:43:42 +01:00
										 |  |  | #include <LibWeb/Bindings/HTMLTableCaptionElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-02 18:03:47 +01:00
										 |  |  | #include <LibWeb/Bindings/HTMLTableSectionElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | #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>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | using namespace Web::CSS; | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | using namespace Web::DOM; | 
					
						
							|  |  |  | using namespace Web::HTML; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | @wrapper_class@* @wrapper_class@::create(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return global_object.heap().allocate<@wrapper_class@>(global_object, global_object, impl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (interface.wrapper_base_class == "Wrapper") { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  | @wrapper_class@::@wrapper_class@(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  |     : Wrapper(static_cast<WindowObject&>(global_object).ensure_web_prototype<@prototype_class@>("@name@")) | 
					
						
							| 
									
										
										
										
											2021-01-18 09:50:00 +01:00
										 |  |  |     , m_impl(impl) | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  | @wrapper_class@::@wrapper_class@(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | 
					
						
							|  |  |  |     : @wrapper_base_class@(global_object, impl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     set_prototype(&static_cast<WindowObject&>(global_object).ensure_web_prototype<@prototype_class@>("@name@")); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | void @wrapper_class@::initialize(JS::GlobalObject& global_object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     @wrapper_base_class@::initialize(global_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @wrapper_class@::~@wrapper_class@() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (should_emit_wrapper_factory(interface)) { | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  | @wrapper_class@* wrap(JS::GlobalObject& global_object, @fully_qualified_name@& impl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return static_cast<@wrapper_class@*>(wrap_impl(global_object, impl)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | } // namespace Web::Bindings
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     outln("{}", generator.as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void generate_constructor_header(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     SourceGenerator generator { builder }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.set("name", interface.name); | 
					
						
							|  |  |  |     generator.set("fully_qualified_name", interface.fully_qualified_name); | 
					
						
							|  |  |  |     generator.set("constructor_class", interface.constructor_class); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |     generator.set("constructor_class:snakecase", interface.constructor_class.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/NativeFunction.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class @constructor_class@ : public JS::NativeFunction { | 
					
						
							|  |  |  |     JS_OBJECT(@constructor_class@, JS::NativeFunction); | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     explicit @constructor_class@(JS::GlobalObject&); | 
					
						
							|  |  |  |     virtual void initialize(JS::GlobalObject&) override; | 
					
						
							|  |  |  |     virtual ~@constructor_class@() override; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual JS::Value call() override; | 
					
						
							|  |  |  |     virtual JS::Value construct(JS::Function& new_target) override; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     virtual bool has_constructor() const override { return true; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Web::Bindings
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     outln("{}", generator.as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void generate_constructor_implementation(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     SourceGenerator generator { builder }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.set("name", interface.name); | 
					
						
							|  |  |  |     generator.set("prototype_class", interface.prototype_class); | 
					
						
							|  |  |  |     generator.set("wrapper_class", interface.wrapper_class); | 
					
						
							|  |  |  |     generator.set("constructor_class", interface.constructor_class); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |     generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |     generator.set("fully_qualified_name", interface.fully_qualified_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | #include <LibJS/Heap/Heap.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/@constructor_class@.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/@prototype_class@.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/@wrapper_class@.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-24 13:49:53 +02:00
										 |  |  | #include <LibWeb/Bindings/ExceptionOrUtils.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/WindowObject.h>
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | #if __has_include(<LibWeb/CSS/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/CSS/@name@.h>
 | 
					
						
							|  |  |  | #elif __has_include(<LibWeb/DOM/@name@.h>)
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #    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>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  | #elif __has_include(<LibWeb/NavigationTiming/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/NavigationTiming/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #elif __has_include(<LibWeb/SVG/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/SVG/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:23:17 +01:00
										 |  |  | #elif __has_include(<LibWeb/XHR/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/XHR/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | using namespace Web::CSS; | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | using namespace Web::DOM; | 
					
						
							|  |  |  | using namespace Web::HTML; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @constructor_class@::@constructor_class@(JS::GlobalObject& global_object) | 
					
						
							|  |  |  |     : NativeFunction(*global_object.function_prototype()) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @constructor_class@::~@constructor_class@() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | JS::Value @constructor_class@::call() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vm().throw_exception<JS::TypeError>(global_object(), JS::ErrorType::ConstructorWithoutNew, "@name@"); | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | JS::Value @constructor_class@::construct(Function&) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (interface.constructors.is_empty()) { | 
					
						
							|  |  |  |         // No constructor
 | 
					
						
							|  |  |  |         generator.set("constructor.length", "0"); | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  |     vm().throw_exception<JS::TypeError>(global_object(), JS::ErrorType::NotAConstructor, "@name@"); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |     } else if (interface.constructors.size() == 1) { | 
					
						
							|  |  |  |         // Single constructor
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto& constructor = interface.constructors[0]; | 
					
						
							|  |  |  |         generator.set("constructor.length", String::number(constructor.length())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  |     [[maybe_unused]] auto& vm = this->vm(); | 
					
						
							|  |  |  |     auto& global_object = this->global_object(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& window = static_cast<WindowObject&>(global_object); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!constructor.parameters.is_empty()) { | 
					
						
							|  |  |  |             generate_argument_count_check(generator, constructor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             StringBuilder arguments_builder; | 
					
						
							|  |  |  |             generate_arguments(generator, constructor.parameters, arguments_builder); | 
					
						
							|  |  |  |             generator.set(".constructor_arguments", arguments_builder.string_view()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-04-24 13:49:53 +02:00
										 |  |  |     auto impl = throw_dom_exception_if_needed(vm, global_object, [&] { return @fully_qualified_name@::create_with_global_object(window, @.constructor_arguments@); }); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-04-24 13:49:53 +02:00
										 |  |  |     auto impl = throw_dom_exception_if_needed(vm, global_object, [&] { return @fully_qualified_name@::create_with_global_object(window); }); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-04-24 13:49:53 +02:00
										 |  |  |     if (should_return_empty(impl)) | 
					
						
							|  |  |  |         return JS::Value(); | 
					
						
							|  |  |  |     return @wrapper_class@::create(global_object, impl.release_value()); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // Multiple constructor overloads - can't do that yet.
 | 
					
						
							|  |  |  |         TODO(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void @constructor_class@::initialize(JS::GlobalObject& global_object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto& vm = this->vm(); | 
					
						
							|  |  |  |     auto& window = static_cast<WindowObject&>(global_object); | 
					
						
							|  |  |  |     [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     NativeFunction::initialize(global_object); | 
					
						
							|  |  |  |     define_property(vm.names.prototype, &window.ensure_web_prototype<@prototype_class@>("@name@"), 0); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |     define_property(vm.names.length, JS::Value(@constructor.length@), JS::Attribute::Configurable); | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& constant : interface.constants) { | 
					
						
							|  |  |  |         auto constant_generator = generator.fork(); | 
					
						
							|  |  |  |         constant_generator.set("constant.name", constant.name); | 
					
						
							|  |  |  |         constant_generator.set("constant.value", constant.value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         constant_generator.append(R"~~~( | 
					
						
							|  |  |  | define_property("@constant.name@", JS::Value((i32)@constant.value@), JS::Attribute::Enumerable); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Web::Bindings
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     outln("{}", generator.as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void generate_prototype_header(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     SourceGenerator generator { builder }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.set("name", interface.name); | 
					
						
							|  |  |  |     generator.set("fully_qualified_name", interface.fully_qualified_name); | 
					
						
							|  |  |  |     generator.set("prototype_class", interface.prototype_class); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |     generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Object.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class @prototype_class@ : public JS::Object { | 
					
						
							|  |  |  |     JS_OBJECT(@prototype_class@, JS::Object); | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     explicit @prototype_class@(JS::GlobalObject&); | 
					
						
							|  |  |  |     virtual void initialize(JS::GlobalObject&) override; | 
					
						
							|  |  |  |     virtual ~@prototype_class@() override; | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& function : interface.functions) { | 
					
						
							|  |  |  |         auto function_generator = generator.fork(); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         function_generator.set("function.name:snakecase", function.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |         function_generator.append(R"~~~( | 
					
						
							|  |  |  |     JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@); | 
					
						
							|  |  |  |         )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& attribute : interface.attributes) { | 
					
						
							|  |  |  |         auto attribute_generator = generator.fork(); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         attribute_generator.set("attribute.name:snakecase", attribute.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |         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); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Web::Bindings
 | 
					
						
							|  |  |  |     )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     outln("{}", generator.as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void generate_prototype_implementation(const IDL::Interface& interface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     StringBuilder builder; | 
					
						
							|  |  |  |     SourceGenerator generator { builder }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.set("name", interface.name); | 
					
						
							|  |  |  |     generator.set("parent_name", interface.parent_name); | 
					
						
							|  |  |  |     generator.set("prototype_class", interface.prototype_class); | 
					
						
							|  |  |  |     generator.set("prototype_base_class", interface.prototype_base_class); | 
					
						
							|  |  |  |     generator.set("wrapper_class", interface.wrapper_class); | 
					
						
							|  |  |  |     generator.set("constructor_class", interface.constructor_class); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |     generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |     generator.set("fully_qualified_name", interface.fully_qualified_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     generator.append(R"~~~( | 
					
						
							|  |  |  | #include <AK/Function.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Array.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Error.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/Function.h>
 | 
					
						
							|  |  |  | #include <LibJS/Runtime/GlobalObject.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:33:26 +04:30
										 |  |  | #include <LibJS/Runtime/TypedArray.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/@prototype_class@.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/@wrapper_class@.h>
 | 
					
						
							| 
									
										
										
										
											2021-03-13 22:39:55 +01:00
										 |  |  | #include <LibWeb/Bindings/CSSStyleDeclarationWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | #include <LibWeb/Bindings/CSSStyleSheetWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/CommentWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/DOMImplementationWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/DocumentFragmentWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/DocumentTypeWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/DocumentWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/EventTargetWrapperFactory.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-10 18:51:29 +02:00
										 |  |  | #include <LibWeb/Bindings/EventWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/EventWrapperFactory.h>
 | 
					
						
							| 
									
										
										
										
											2021-02-20 13:06:03 +01:00
										 |  |  | #include <LibWeb/Bindings/ExceptionOrUtils.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-22 21:11:20 +02:00
										 |  |  | #include <LibWeb/Bindings/HTMLCollectionWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-04-20 11:50:29 +02:00
										 |  |  | #include <LibWeb/Bindings/HTMLFormElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/HTMLHeadElementWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/HTMLImageElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-02 17:43:42 +01:00
										 |  |  | #include <LibWeb/Bindings/HTMLTableCaptionElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-02 18:03:47 +01:00
										 |  |  | #include <LibWeb/Bindings/HTMLTableSectionElementWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/ImageDataWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/NodeWrapperFactory.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  | #include <LibWeb/Bindings/PerformanceTimingWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-02-21 23:41:54 +01:00
										 |  |  | #include <LibWeb/Bindings/RangeWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | #include <LibWeb/Bindings/StyleSheetListWrapper.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Bindings/TextWrapper.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Bindings/WindowObject.h>
 | 
					
						
							|  |  |  | #include <LibWeb/DOM/Element.h>
 | 
					
						
							|  |  |  | #include <LibWeb/DOM/EventListener.h>
 | 
					
						
							| 
									
										
										
										
											2021-02-21 23:41:54 +01:00
										 |  |  | #include <LibWeb/DOM/Range.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:15:02 +01:00
										 |  |  | #include <LibWeb/DOM/Window.h>
 | 
					
						
							| 
									
										
										
										
											2021-02-03 22:47:50 +01:00
										 |  |  | #include <LibWeb/HTML/EventHandler.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/HTML/HTMLElement.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  | #include <LibWeb/NavigationTiming/PerformanceTiming.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #include <LibWeb/Origin.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/Bindings/@prototype_base_class@.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | #if __has_include(<LibWeb/CSS/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/CSS/@name@.h>
 | 
					
						
							|  |  |  | #elif __has_include(<LibWeb/DOM/@name@.h>)
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #    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>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  | #elif __has_include(<LibWeb/NavigationTiming/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/NavigationTiming/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #elif __has_include(<LibWeb/SVG/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/SVG/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:23:17 +01:00
										 |  |  | #elif __has_include(<LibWeb/XHR/@name@.h>)
 | 
					
						
							|  |  |  | #    include <LibWeb/XHR/@name@.h>
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:22:18 +01:00
										 |  |  | using namespace Web::CSS; | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | using namespace Web::DOM; | 
					
						
							|  |  |  | using namespace Web::HTML; | 
					
						
							| 
									
										
										
										
											2021-01-18 15:06:13 +01:00
										 |  |  | using namespace Web::NavigationTiming; | 
					
						
							| 
									
										
										
										
											2021-01-23 13:23:17 +01:00
										 |  |  | using namespace Web::XHR; | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Bindings { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @prototype_class@::@prototype_class@(JS::GlobalObject& global_object) | 
					
						
							|  |  |  |     : Object(*global_object.object_prototype()) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 19:04:41 +01:00
										 |  |  |     if (interface.name == "DOMException") { | 
					
						
							|  |  |  |         // https://heycam.github.io/webidl/#es-DOMException-specialness
 | 
					
						
							|  |  |  |         // Object.getPrototypeOf(DOMException.prototype) === Error.prototype
 | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  |     set_prototype(global_object.error_prototype()); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } else if (!interface.parent_name.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |     set_prototype(&static_cast<WindowObject&>(global_object).ensure_web_prototype<@prototype_base_class@>("@parent_name@")); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 12:27:41 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @prototype_class@::~@prototype_class@() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void @prototype_class@::initialize(JS::GlobalObject& global_object) | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |     [[maybe_unused]] auto& vm = this->vm(); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto& attribute : interface.attributes) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         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); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  |     for (auto& constant : interface.constants) { | 
					
						
							|  |  |  |         auto constant_generator = generator.fork(); | 
					
						
							|  |  |  |         constant_generator.set("constant.name", constant.name); | 
					
						
							|  |  |  |         constant_generator.set("constant.value", constant.value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         constant_generator.append(R"~~~( | 
					
						
							|  |  |  |     define_property("@constant.name@", JS::Value((i32)@constant.value@), JS::Attribute::Enumerable); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     for (auto& function : interface.functions) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         auto function_generator = generator.fork(); | 
					
						
							|  |  |  |         function_generator.set("function.name", function.name); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         function_generator.set("function.name:snakecase", function.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2021-02-17 22:21:39 +01:00
										 |  |  |         function_generator.set("function.length", String::number(function.length())); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         function_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-02-17 22:21:39 +01:00
										 |  |  |     define_native_function("@function.name@", @function.name:snakecase@, @function.length@, default_attributes); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |     Object::initialize(global_object); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-21 15:26:09 +02:00
										 |  |  |     if (!interface.attributes.is_empty() || !interface.functions.is_empty()) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         generator.append(R"~~~( | 
					
						
							|  |  |  | static @fully_qualified_name@* impl_from(JS::VM& vm, JS::GlobalObject& global_object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto* this_object = vm.this_value(global_object).to_object(global_object); | 
					
						
							|  |  |  |     if (!this_object) | 
					
						
							|  |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2021-01-18 12:15:02 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (interface.name == "EventTarget") { | 
					
						
							|  |  |  |             generator.append(R"~~~( | 
					
						
							|  |  |  |     if (is<WindowObject>(this_object)) { | 
					
						
							|  |  |  |         return &static_cast<WindowObject*>(this_object)->impl(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-01 17:00:20 +01:00
										 |  |  |     if (!is<@wrapper_class@>(this_object)) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "@fully_qualified_name@"); | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return &static_cast<@wrapper_class@*>(this_object)->impl(); | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 15:26:09 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto generate_return_statement = [&](auto& return_type) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         auto scoped_generator = generator.fork(); | 
					
						
							|  |  |  |         scoped_generator.set("return_type", return_type.name); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-09 21:32:04 +00:00
										 |  |  |         if (return_type.name == "undefined") { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return JS::js_undefined(); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         if (return_type.nullable) { | 
					
						
							| 
									
										
										
										
											2021-03-08 16:14:56 +01:00
										 |  |  |             if (return_type.is_string()) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     if (retval.is_null()) | 
					
						
							|  |  |  |         return JS::js_null(); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |                 scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     if (!retval) | 
					
						
							|  |  |  |         return JS::js_null(); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 16:14:56 +01:00
										 |  |  |         if (return_type.is_string()) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return JS::js_string(vm, retval); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         } else if (return_type.name == "ArrayFromVector") { | 
					
						
							|  |  |  |             // FIXME: Remove this fake type hack once it's no longer needed.
 | 
					
						
							|  |  |  |             //        Basically once we have NodeList we can throw this out.
 | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto* new_array = JS::Array::create(global_object); | 
					
						
							|  |  |  |     for (auto& element : retval) | 
					
						
							|  |  |  |         new_array->indexed_properties().append(wrap(global_object, element)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return new_array; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-03-08 11:09:08 +01:00
										 |  |  |         } else if (return_type.name == "boolean" || return_type.name == "double") { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return JS::Value(retval); | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2021-03-08 11:09:08 +01:00
										 |  |  |         } else if (return_type.name == "short" || return_type.name == "unsigned short" || return_type.name == "long" || return_type.name == "unsigned long") { | 
					
						
							| 
									
										
										
										
											2021-01-23 13:20:24 +01:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return JS::Value((i32)retval); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 15:57:10 +02:00
										 |  |  |         } else if (return_type.name == "Uint8ClampedArray") { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return retval; | 
					
						
							| 
									
										
										
										
											2021-02-03 22:47:50 +01:00
										 |  |  | )~~~"); | 
					
						
							|  |  |  |         } else if (return_type.name == "EventHandler") { | 
					
						
							|  |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return retval.callback.cell(); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             scoped_generator.append(R"~~~( | 
					
						
							|  |  |  |     return wrap(global_object, const_cast<@return_type@&>(*retval)); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& attribute : interface.attributes) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         auto attribute_generator = generator.fork(); | 
					
						
							|  |  |  |         attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name); | 
					
						
							|  |  |  |         attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         attribute_generator.set("attribute.name:snakecase", attribute.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2020-09-22 18:26:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-08 11:16:06 +01:00
										 |  |  |         if (attribute.extended_attributes.contains("ImplementedAs")) { | 
					
						
							|  |  |  |             auto implemented_as = attribute.extended_attributes.get("ImplementedAs").value(); | 
					
						
							|  |  |  |             attribute_generator.set("attribute.cpp_getter_name", implemented_as); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             attribute_generator.set("attribute.cpp_getter_name", attribute.name.to_snakecase()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         if (attribute.extended_attributes.contains("Reflect")) { | 
					
						
							| 
									
										
										
										
											2020-07-24 13:23:47 +02:00
										 |  |  |             auto attribute_name = attribute.extended_attributes.get("Reflect").value(); | 
					
						
							|  |  |  |             if (attribute_name.is_null()) | 
					
						
							|  |  |  |                 attribute_name = attribute.name; | 
					
						
							| 
									
										
										
										
											2020-08-09 17:10:41 +01:00
										 |  |  |             attribute_name = make_input_acceptable_cpp(attribute_name); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             attribute_generator.set("attribute.reflect_name", attribute_name); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |             attribute_generator.set("attribute.reflect_name", attribute.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         attribute_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | JS_DEFINE_NATIVE_GETTER(@prototype_class@::@attribute.getter_callback@) | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     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")) { | 
					
						
							| 
									
										
										
										
											2020-11-09 08:15:10 +00:00
										 |  |  |             if (attribute.type.name != "boolean") { | 
					
						
							|  |  |  |                 attribute_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-11-09 08:15:10 +00:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 attribute_generator.append(R"~~~( | 
					
						
							|  |  |  |     auto retval = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             attribute_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-03-08 11:16:06 +01:00
										 |  |  |     auto retval = impl->@attribute.cpp_getter_name@(); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |         generate_return_statement(attribute.type); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         attribute_generator.append(R"~~~( | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!attribute.readonly) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |             attribute_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  | JS_DEFINE_NATIVE_SETTER(@prototype_class@::@attribute.setter_callback@) | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     auto* impl = impl_from(vm, global_object); | 
					
						
							|  |  |  |     if (!impl) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |             generate_to_cpp(generator, attribute, "value", "", "cpp_value", true, attribute.extended_attributes.contains("LegacyNullToEmptyString")); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |             if (attribute.extended_attributes.contains("Reflect")) { | 
					
						
							| 
									
										
										
										
											2020-11-09 08:15:10 +00:00
										 |  |  |                 if (attribute.type.name != "boolean") { | 
					
						
							|  |  |  |                     attribute_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |     impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-11-09 08:15:10 +00:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     attribute_generator.append(R"~~~( | 
					
						
							|  |  |  |     if (!cpp_value) | 
					
						
							|  |  |  |         impl->remove_attribute(HTML::AttributeNames::@attribute.reflect_name@); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, String::empty()); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |                 attribute_generator.append(R"~~~( | 
					
						
							|  |  |  |     impl->set_@attribute.name:snakecase@(cpp_value); | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-07-24 12:59:47 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             attribute_generator.append(R"~~~( | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-21 11:39:32 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Implementation: Functions
 | 
					
						
							|  |  |  |     for (auto& function : interface.functions) { | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         auto function_generator = generator.fork(); | 
					
						
							|  |  |  |         function_generator.set("function.name", function.name); | 
					
						
							| 
									
										
										
										
											2021-02-20 22:59:53 +01:00
										 |  |  |         function_generator.set("function.name:snakecase", function.name.to_snakecase()); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-06 17:08:29 +01:00
										 |  |  |         if (function.extended_attributes.contains("ImplementedAs")) { | 
					
						
							|  |  |  |             auto implemented_as = function.extended_attributes.get("ImplementedAs").value(); | 
					
						
							|  |  |  |             function_generator.set("function.cpp_name", implemented_as); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             function_generator.set("function.cpp_name", function.name.to_snakecase()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 12:02:28 +01:00
										 |  |  |         function_generator.append(R"~~~( | 
					
						
							|  |  |  | JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@function.name:snakecase@) | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     auto* impl = impl_from(vm, global_object); | 
					
						
							|  |  |  |     if (!impl) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         generate_argument_count_check(generator, function); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         StringBuilder arguments_builder; | 
					
						
							| 
									
										
										
										
											2021-02-17 22:36:59 +01:00
										 |  |  |         generate_arguments(generator, function.parameters, arguments_builder); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  |         function_generator.set(".arguments", arguments_builder.string_view()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 19:10:44 +01:00
										 |  |  |         function_generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-04-13 23:48:25 +04:30
										 |  |  |     auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->@function.cpp_name@(@.arguments@); }); | 
					
						
							|  |  |  |     if (should_return_empty(result)) | 
					
						
							| 
									
										
										
										
											2021-02-19 19:10:44 +01:00
										 |  |  |         return JS::Value(); | 
					
						
							| 
									
										
										
										
											2021-04-13 23:48:25 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  |     [[maybe_unused]] auto retval = result.release_value(); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         generate_return_statement(function.return_type); | 
					
						
							| 
									
										
										
										
											2020-10-23 18:37:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         function_generator.append(R"~~~( | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | )~~~"); | 
					
						
							| 
									
										
										
										
											2020-06-20 22:09:38 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-18 11:36:34 +01:00
										 |  |  |     generator.append(R"~~~( | 
					
						
							| 
									
										
										
										
											2021-01-18 08:35:46 +01:00
										 |  |  | } // namespace Web::Bindings
 | 
					
						
							|  |  |  | )~~~"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     outln("{}", generator.as_string_view()); | 
					
						
							|  |  |  | } |