mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	LibWeb: Convert ArrayFromVector wrapper to instead be sequence<T>
This adds the ParamatizedType, as `Vector<String>` doesn't encode the full type information. It is a separate struct as you can't have `Vector<Type>` inside of `Type`. This also makes Type RefCounted because I had to make parse_type return a pointer to make dynamic casting work correctly. The reason I made it RefCounted instead of using a NonnullOwnPtr is because it causes compiler errors that I don't want to figure out right now.
This commit is contained in:
		
							parent
							
								
									8e4d53f216
								
							
						
					
					
						commit
						cb821e1539
					
				
					 1 changed files with 163 additions and 91 deletions
				
			
		|  | @ -81,15 +81,38 @@ static size_t get_function_length(FunctionType& function) | |||
|     return length; | ||||
| } | ||||
| 
 | ||||
| struct Type { | ||||
| struct Type : public RefCounted<Type> { | ||||
|     Type() = default; | ||||
| 
 | ||||
|     Type(String name, bool nullable) | ||||
|         : name(move(name)) | ||||
|         , nullable(nullable) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     virtual ~Type() = default; | ||||
| 
 | ||||
|     String name; | ||||
|     Vector<String> parameters; | ||||
|     bool nullable { false }; | ||||
|     bool is_string() const { return name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); } | ||||
| }; | ||||
| 
 | ||||
| struct ParameterizedType : public Type { | ||||
|     ParameterizedType() = default; | ||||
| 
 | ||||
|     ParameterizedType(String name, bool nullable, NonnullRefPtrVector<Type> parameters) | ||||
|         : Type(move(name), nullable) | ||||
|         , parameters(move(parameters)) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     virtual ~ParameterizedType() override = default; | ||||
| 
 | ||||
|     NonnullRefPtrVector<Type> parameters; | ||||
| }; | ||||
| 
 | ||||
| struct Parameter { | ||||
|     Type type; | ||||
|     NonnullRefPtr<Type> type; | ||||
|     String name; | ||||
|     bool optional { false }; | ||||
|     Optional<String> optional_default_value; | ||||
|  | @ -97,7 +120,7 @@ struct Parameter { | |||
| }; | ||||
| 
 | ||||
| struct Function { | ||||
|     Type return_type; | ||||
|     NonnullRefPtr<Type> return_type; | ||||
|     String name; | ||||
|     Vector<Parameter> parameters; | ||||
|     HashMap<String, String> extended_attributes; | ||||
|  | @ -113,14 +136,14 @@ struct Constructor { | |||
| }; | ||||
| 
 | ||||
| struct Constant { | ||||
|     Type type; | ||||
|     NonnullRefPtr<Type> type; | ||||
|     String name; | ||||
|     String value; | ||||
| }; | ||||
| 
 | ||||
| struct Attribute { | ||||
|     bool readonly { false }; | ||||
|     Type type; | ||||
|     NonnullRefPtr<Type> type; | ||||
|     String name; | ||||
|     HashMap<String, String> extended_attributes; | ||||
| 
 | ||||
|  | @ -131,7 +154,7 @@ struct Attribute { | |||
| 
 | ||||
| struct DictionaryMember { | ||||
|     bool required { false }; | ||||
|     Type type; | ||||
|     NonnullRefPtr<Type> type; | ||||
|     String name; | ||||
|     HashMap<String, String> extended_attributes; | ||||
|     Optional<String> default_value; | ||||
|  | @ -157,8 +180,8 @@ struct Interface { | |||
|     Optional<String> stringifier_attribute; | ||||
|     bool has_unscopable_member { false }; | ||||
| 
 | ||||
|     Optional<Type> value_iterator_type; | ||||
|     Optional<Tuple<Type, Type>> pair_iterator_types; | ||||
|     Optional<NonnullRefPtr<Type>> value_iterator_type; | ||||
|     Optional<Tuple<NonnullRefPtr<Type>, NonnullRefPtr<Type>>> pair_iterator_types; | ||||
| 
 | ||||
|     Optional<Function> named_property_getter; | ||||
|     Optional<Function> named_property_setter; | ||||
|  | @ -259,7 +282,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|     if (lexer.consume_specific('[')) | ||||
|         interface->extended_attributes = parse_extended_attributes(); | ||||
| 
 | ||||
|     auto parse_type = [&] { | ||||
|     AK::Function<NonnullRefPtr<Type>()> parse_type = [&]() -> NonnullRefPtr<Type> { | ||||
|         auto consume_name = [&] { | ||||
|             return lexer.consume_until([](auto ch) { return !isalnum(ch) && ch != '_'; }); | ||||
|         }; | ||||
|  | @ -267,10 +290,12 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|         if (unsigned_) | ||||
|             consume_whitespace(); | ||||
|         auto name = consume_name(); | ||||
|         Vector<String> parameters; | ||||
|         NonnullRefPtrVector<Type> parameters; | ||||
|         bool is_parameterized_type = false; | ||||
|         if (lexer.consume_specific('<')) { | ||||
|             is_parameterized_type = true; | ||||
|             // TODO: Parse multiple parameters if necessary
 | ||||
|             parameters.append(consume_name()); | ||||
|             parameters.append(parse_type()); | ||||
|             lexer.consume_specific('>'); | ||||
|         } | ||||
|         auto nullable = lexer.consume_specific('?'); | ||||
|  | @ -278,7 +303,11 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|         if (unsigned_) | ||||
|             builder.append("unsigned "); | ||||
|         builder.append(name); | ||||
|         return Type { builder.to_string(), parameters, nullable }; | ||||
| 
 | ||||
|         if (is_parameterized_type) | ||||
|             return adopt_ref(*new ParameterizedType(builder.to_string(), nullable, move(parameters))); | ||||
| 
 | ||||
|         return adopt_ref(*new Type(builder.to_string(), nullable)); | ||||
|     }; | ||||
| 
 | ||||
|     auto parse_attribute = [&](HashMap<String, String>& extended_attributes) { | ||||
|  | @ -295,13 +324,19 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|         consume_whitespace(); | ||||
| 
 | ||||
|         assert_specific(';'); | ||||
|         Attribute attribute; | ||||
|         attribute.readonly = readonly; | ||||
|         attribute.type = type; | ||||
|         attribute.name = name; | ||||
|         attribute.getter_callback_name = String::formatted("{}_getter", attribute.name.to_snakecase()); | ||||
|         attribute.setter_callback_name = String::formatted("{}_setter", attribute.name.to_snakecase()); | ||||
|         attribute.extended_attributes = move(extended_attributes); | ||||
| 
 | ||||
|         auto name_as_string = name.to_string(); | ||||
|         auto getter_callback_name = String::formatted("{}_getter", name_as_string.to_snakecase()); | ||||
|         auto setter_callback_name = String::formatted("{}_setter", name_as_string.to_snakecase()); | ||||
| 
 | ||||
|         Attribute attribute { | ||||
|             readonly, | ||||
|             move(type), | ||||
|             move(name_as_string), | ||||
|             move(extended_attributes), | ||||
|             move(getter_callback_name), | ||||
|             move(setter_callback_name), | ||||
|         }; | ||||
|         interface->attributes.append(move(attribute)); | ||||
|     }; | ||||
| 
 | ||||
|  | @ -309,17 +344,21 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|         lexer.consume_specific("const"); | ||||
|         consume_whitespace(); | ||||
| 
 | ||||
|         Constant constant; | ||||
|         constant.type = parse_type(); | ||||
|         auto type = parse_type(); | ||||
|         consume_whitespace(); | ||||
|         constant.name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == '='; }); | ||||
|         auto 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 != ';'; }); | ||||
|         auto value = lexer.consume_while([](auto ch) { return !isspace(ch) && ch != ';'; }); | ||||
|         consume_whitespace(); | ||||
|         assert_specific(';'); | ||||
| 
 | ||||
|         Constant constant { | ||||
|             move(type), | ||||
|             move(name), | ||||
|             move(value), | ||||
|         }; | ||||
|         interface->constants.append(move(constant)); | ||||
|     }; | ||||
| 
 | ||||
|  | @ -452,7 +491,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|         auto& identifier = function.parameters.first(); | ||||
| 
 | ||||
|         if (identifier.type.nullable) | ||||
|         if (identifier.type->nullable) | ||||
|             report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|         if (identifier.optional) | ||||
|  | @ -460,18 +499,18 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|         // FIXME: Disallow variadic functions once they're supported.
 | ||||
| 
 | ||||
|         if (identifier.type.name == "DOMString") { | ||||
|         if (identifier.type->name == "DOMString") { | ||||
|             if (interface->named_property_getter.has_value()) | ||||
|                 report_parsing_error("An interface can only have one named property getter.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|             interface->named_property_getter = move(function); | ||||
|         } else if (identifier.type.name == "unsigned long") { | ||||
|         } else if (identifier.type->name == "unsigned long") { | ||||
|             if (interface->indexed_property_getter.has_value()) | ||||
|                 report_parsing_error("An interface can only have one indexed property getter.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|             interface->indexed_property_getter = move(function); | ||||
|         } else { | ||||
|             report_parsing_error(String::formatted("Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type.name), filename, input, lexer.tell()); | ||||
|             report_parsing_error(String::formatted("Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name), filename, input, lexer.tell()); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -485,7 +524,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|         auto& identifier = function.parameters.first(); | ||||
| 
 | ||||
|         if (identifier.type.nullable) | ||||
|         if (identifier.type->nullable) | ||||
|             report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|         if (identifier.optional) | ||||
|  | @ -493,7 +532,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|         // FIXME: Disallow variadic functions once they're supported.
 | ||||
| 
 | ||||
|         if (identifier.type.name == "DOMString") { | ||||
|         if (identifier.type->name == "DOMString") { | ||||
|             if (interface->named_property_setter.has_value()) | ||||
|                 report_parsing_error("An interface can only have one named property setter.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|  | @ -501,7 +540,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|                 report_parsing_error("A named property setter must be accompanied by a named property getter.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|             interface->named_property_setter = move(function); | ||||
|         } else if (identifier.type.name == "unsigned long") { | ||||
|         } else if (identifier.type->name == "unsigned long") { | ||||
|             if (interface->indexed_property_setter.has_value()) | ||||
|                 report_parsing_error("An interface can only have one indexed property setter.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|  | @ -510,7 +549,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|             interface->indexed_property_setter = move(function); | ||||
|         } else { | ||||
|             report_parsing_error(String::formatted("Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type.name), filename, input, lexer.tell()); | ||||
|             report_parsing_error(String::formatted("Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name), filename, input, lexer.tell()); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -524,7 +563,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|         auto& identifier = function.parameters.first(); | ||||
| 
 | ||||
|         if (identifier.type.nullable) | ||||
|         if (identifier.type->nullable) | ||||
|             report_parsing_error("identifier's type must not be nullable.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|         if (identifier.optional) | ||||
|  | @ -532,7 +571,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|         // FIXME: Disallow variadic functions once they're supported.
 | ||||
| 
 | ||||
|         if (identifier.type.name == "DOMString") { | ||||
|         if (identifier.type->name == "DOMString") { | ||||
|             if (interface->named_property_deleter.has_value()) | ||||
|                 report_parsing_error("An interface can only have one named property deleter.", filename, input, lexer.tell()); | ||||
| 
 | ||||
|  | @ -541,7 +580,7 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
| 
 | ||||
|             interface->named_property_deleter = move(function); | ||||
|         } else { | ||||
|             report_parsing_error(String::formatted("Named property deleter's identifier's type must be 'DOMString', got '{}'.", identifier.type.name), filename, input, lexer.tell()); | ||||
|             report_parsing_error(String::formatted("Named property deleter's identifier's type must be 'DOMString', got '{}'.", identifier.type->name), filename, input, lexer.tell()); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -649,29 +688,40 @@ static NonnullOwnPtr<Interface> parse_interface(StringView filename, StringView | |||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             DictionaryMember member {}; | ||||
|             bool required = false; | ||||
|             HashMap<String, String> extended_attributes; | ||||
| 
 | ||||
|             if (lexer.consume_specific("required")) { | ||||
|                 member.required = true; | ||||
|                 required = true; | ||||
|                 consume_whitespace(); | ||||
|                 if (lexer.consume_specific('[')) | ||||
|                     member.extended_attributes = parse_extended_attributes(); | ||||
|                     extended_attributes = parse_extended_attributes(); | ||||
|             } | ||||
| 
 | ||||
|             member.type = parse_type(); | ||||
|             auto type = parse_type(); | ||||
|             consume_whitespace(); | ||||
| 
 | ||||
|             member.name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; }); | ||||
|             auto name = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; }); | ||||
|             consume_whitespace(); | ||||
| 
 | ||||
|             Optional<StringView> default_value; | ||||
| 
 | ||||
|             if (lexer.consume_specific('=')) { | ||||
|                 VERIFY(!member.required); | ||||
|                 VERIFY(!required); | ||||
|                 consume_whitespace(); | ||||
|                 auto default_value = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; }); | ||||
|                 member.default_value = default_value; | ||||
|                 default_value = lexer.consume_until([](auto ch) { return isspace(ch) || ch == ';'; }); | ||||
|                 consume_whitespace(); | ||||
|             } | ||||
| 
 | ||||
|             assert_specific(';'); | ||||
| 
 | ||||
|             DictionaryMember member { | ||||
|                 required, | ||||
|                 move(type), | ||||
|                 move(name), | ||||
|                 move(extended_attributes), | ||||
|                 default_value.has_value() ? default_value.value() : Optional<String> {}, | ||||
|             }; | ||||
|             dictionary.members.append(move(member)); | ||||
|         } | ||||
| 
 | ||||
|  | @ -765,21 +815,21 @@ int main(int argc, char** argv) | |||
|         for (auto& attribute : interface->attributes) { | ||||
|             dbgln("  {}{}{} {}", | ||||
|                 attribute.readonly ? "readonly " : "", | ||||
|                 attribute.type.name, | ||||
|                 attribute.type.nullable ? "?" : "", | ||||
|                 attribute.type->name, | ||||
|                 attribute.type->nullable ? "?" : "", | ||||
|                 attribute.name); | ||||
|         } | ||||
| 
 | ||||
|         dbgln("Functions:"); | ||||
|         for (auto& function : interface->functions) { | ||||
|             dbgln("  {}{} {}", | ||||
|                 function.return_type.name, | ||||
|                 function.return_type.nullable ? "?" : "", | ||||
|                 function.return_type->name, | ||||
|                 function.return_type->nullable ? "?" : "", | ||||
|                 function.name); | ||||
|             for (auto& parameter : function.parameters) { | ||||
|                 dbgln("    {}{} {}", | ||||
|                     parameter.type.name, | ||||
|                     parameter.type.nullable ? "?" : "", | ||||
|                     parameter.type->name, | ||||
|                     parameter.type->nullable ? "?" : "", | ||||
|                     parameter.name); | ||||
|             } | ||||
|         } | ||||
|  | @ -787,13 +837,13 @@ int main(int argc, char** argv) | |||
|         dbgln("Static Functions:"); | ||||
|         for (auto& function : interface->static_functions) { | ||||
|             dbgln("  static {}{} {}", | ||||
|                 function.return_type.name, | ||||
|                 function.return_type.nullable ? "?" : "", | ||||
|                 function.return_type->name, | ||||
|                 function.return_type->nullable ? "?" : "", | ||||
|                 function.name); | ||||
|             for (auto& parameter : function.parameters) { | ||||
|                 dbgln("    {}{} {}", | ||||
|                     parameter.type.name, | ||||
|                     parameter.type.nullable ? "?" : "", | ||||
|                     parameter.type->name, | ||||
|                     parameter.type->nullable ? "?" : "", | ||||
|                     parameter.name); | ||||
|             } | ||||
|         } | ||||
|  | @ -887,11 +937,11 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|     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); | ||||
|     if (parameter.type.name == "Window") | ||||
|     scoped_generator.set("parameter.type.name", parameter.type->name); | ||||
|     if (parameter.type->name == "Window") | ||||
|         scoped_generator.set("wrapper_name", "WindowObject"); | ||||
|     else | ||||
|         scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type.name)); | ||||
|         scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type->name)); | ||||
| 
 | ||||
|     if (optional_default_value.has_value()) | ||||
|         scoped_generator.set("parameter.optional_default_value", *optional_default_value); | ||||
|  | @ -902,9 +952,9 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|         scoped_generator.set("return_statement", "return {};"); | ||||
| 
 | ||||
|     // FIXME: Add support for optional, nullable and default values to all types
 | ||||
|     if (parameter.type.is_string()) { | ||||
|     if (parameter.type->is_string()) { | ||||
|         if (!optional) { | ||||
|             if (!parameter.type.nullable) { | ||||
|             if (!parameter.type->nullable) { | ||||
|                 scoped_generator.append(R"~~~( | ||||
|     String @cpp_name@; | ||||
|     if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) { | ||||
|  | @ -940,7 +990,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|             @cpp_name@ = to_string_result.release_value(); | ||||
|         } | ||||
|     })~~~"); | ||||
|             if (optional_default_value.has_value() && (!parameter.type.nullable || optional_default_value.value() != "null")) { | ||||
|             if (optional_default_value.has_value() && (!parameter.type->nullable || optional_default_value.value() != "null")) { | ||||
|                 scoped_generator.append(R"~~~( else { | ||||
|         @cpp_name@ = @parameter.optional_default_value@; | ||||
|     } | ||||
|  | @ -950,8 +1000,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
| )~~~"); | ||||
|             } | ||||
|         } | ||||
|     } else if (parameter.type.name == "EventListener") { | ||||
|         if (parameter.type.nullable) { | ||||
|     } else if (parameter.type->name == "EventListener") { | ||||
|         if (parameter.type->nullable) { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     RefPtr<EventListener> @cpp_name@; | ||||
|     if (!@js_name@@js_suffix@.is_nullish()) { | ||||
|  | @ -971,8 +1021,8 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|     auto @cpp_name@ = adopt_ref(*new EventListener(JS::make_handle(&@js_name@@js_suffix@.as_function()))); | ||||
| )~~~"); | ||||
|         } | ||||
|     } else if (is_wrappable_type(parameter.type)) { | ||||
|         if (!parameter.type.nullable) { | ||||
|     } else if (is_wrappable_type(*parameter.type)) { | ||||
|         if (!parameter.type->nullable) { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     auto @cpp_name@_object_or_error = @js_name@@js_suffix@.to_object(global_object); | ||||
|     if (@cpp_name@_object_or_error.is_error()) | ||||
|  | @ -1004,7 +1054,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|     } | ||||
| )~~~"); | ||||
|         } | ||||
|     } else if (parameter.type.name == "double") { | ||||
|     } else if (parameter.type->name == "double") { | ||||
|         if (!optional) { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     double @cpp_name@ = @js_name@@js_suffix@.to_double(global_object); | ||||
|  | @ -1038,7 +1088,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
| )~~~"); | ||||
|             } | ||||
|         } | ||||
|     } else if (parameter.type.name == "boolean") { | ||||
|     } else if (parameter.type->name == "boolean") { | ||||
|         if (!optional) { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     bool @cpp_name@ = @js_name@@js_suffix@.to_boolean(); | ||||
|  | @ -1066,25 +1116,25 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
| )~~~"); | ||||
|             } | ||||
|         } | ||||
|     } else if (parameter.type.name == "unsigned long") { | ||||
|     } 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()) | ||||
|         @return_statement@ | ||||
| )~~~"); | ||||
|     } else if (parameter.type.name == "unsigned short") { | ||||
|     } 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()) | ||||
|         @return_statement@ | ||||
| )~~~"); | ||||
|     } else if (parameter.type.name == "long") { | ||||
|     } 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@ | ||||
| )~~~"); | ||||
|     } else if (parameter.type.name == "EventHandler") { | ||||
|     } else if (parameter.type->name == "EventHandler") { | ||||
|         // x.onfoo = function() { ... }
 | ||||
|         scoped_generator.append(R"~~~( | ||||
|     HTML::EventHandler @cpp_name@; | ||||
|  | @ -1096,7 +1146,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|         return JS::js_undefined(); | ||||
|     } | ||||
| )~~~"); | ||||
|     } else if (parameter.type.name == "Promise") { | ||||
|     } else if (parameter.type->name == "Promise") { | ||||
|         // NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
 | ||||
|         // Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say
 | ||||
|         // anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct.
 | ||||
|  | @ -1108,7 +1158,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|     } | ||||
|     auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object())); | ||||
| )~~~"); | ||||
|     } else if (parameter.type.name == "any") { | ||||
|     } else if (parameter.type->name == "any") { | ||||
|         if (!optional) { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     auto @cpp_name@ = @js_name@@js_suffix@; | ||||
|  | @ -1135,7 +1185,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } else if (dictionaries.contains(parameter.type.name)) { | ||||
|     } else if (dictionaries.contains(parameter.type->name)) { | ||||
|         if (optional_default_value.has_value() && optional_default_value != "{}") | ||||
|             TODO(); | ||||
|         auto dictionary_generator = scoped_generator.fork(); | ||||
|  | @ -1146,7 +1196,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|     } | ||||
|     @parameter.type.name@ @cpp_name@ {}; | ||||
| )~~~"); | ||||
|         auto* current_dictionary = &dictionaries.find(parameter.type.name)->value; | ||||
|         auto* current_dictionary = &dictionaries.find(parameter.type->name)->value; | ||||
|         while (true) { | ||||
|             for (auto& member : current_dictionary->members) { | ||||
|                 dictionary_generator.set("member_key", member.name); | ||||
|  | @ -1185,7 +1235,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter | |||
|             current_dictionary = &dictionaries.find(current_dictionary->parent_name)->value; | ||||
|         } | ||||
|     } else { | ||||
|         dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name); | ||||
|         dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name); | ||||
|         VERIFY_NOT_REACHED(); | ||||
|     } | ||||
| } | ||||
|  | @ -1236,12 +1286,18 @@ static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter | |||
|     arguments_builder.join(", ", parameter_names); | ||||
| } | ||||
| 
 | ||||
| static void generate_wrap_statement(SourceGenerator& generator, String const& value, IDL::Type const& type, StringView const& result_expression) | ||||
| enum class WrappingReference { | ||||
|     No, | ||||
|     Yes, | ||||
| }; | ||||
| 
 | ||||
| static void generate_wrap_statement(SourceGenerator& generator, String const& value, IDL::Type const& type, StringView const& result_expression, WrappingReference wrapping_reference = WrappingReference::No, size_t recursion_depth = 0) | ||||
| { | ||||
|     auto scoped_generator = generator.fork(); | ||||
|     scoped_generator.set("value", value); | ||||
|     scoped_generator.set("type", type.name); | ||||
|     scoped_generator.set("result_expression", result_expression); | ||||
|     scoped_generator.set("recursion_depth", String::number(recursion_depth)); | ||||
| 
 | ||||
|     if (type.name == "undefined") { | ||||
|         scoped_generator.append(R"~~~( | ||||
|  | @ -1270,15 +1326,25 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va | |||
|         scoped_generator.append(R"~~~( | ||||
|     @result_expression@ JS::js_string(vm, @value@); | ||||
| )~~~"); | ||||
|     } else if (type.name == "ArrayFromVector") { | ||||
|         // FIXME: Remove this fake type hack once it's no longer needed.
 | ||||
|         //        Basically once we have sequence<T> we can throw this out.
 | ||||
|         scoped_generator.append(R"~~~( | ||||
|     auto* new_array = JS::Array::create(global_object, 0); | ||||
|     for (auto& element : @value@) | ||||
|         new_array->indexed_properties().append(wrap(global_object, element)); | ||||
|     } else if (type.name == "sequence") { | ||||
|         // https://webidl.spec.whatwg.org/#es-sequence
 | ||||
|         auto& sequence_generic_type = verify_cast<IDL::ParameterizedType>(type); | ||||
| 
 | ||||
|     @result_expression@ new_array; | ||||
|         scoped_generator.append(R"~~~( | ||||
|     auto* new_array@recursion_depth@ = JS::Array::create(global_object, 0); | ||||
| 
 | ||||
|     for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@.size(); ++i@recursion_depth@) { | ||||
|         auto& element@recursion_depth@ = @value@.at(i@recursion_depth@); | ||||
| )~~~"); | ||||
| 
 | ||||
|         generate_wrap_statement(scoped_generator, String::formatted("element{}", recursion_depth), sequence_generic_type.parameters.first(), String::formatted("auto wrapped_element{} =", recursion_depth), WrappingReference::Yes, recursion_depth + 1); | ||||
| 
 | ||||
|         scoped_generator.append(R"~~~( | ||||
|         auto property_index@recursion_depth@ = JS::PropertyName { i@recursion_depth@ }; | ||||
|         MUST(new_array@recursion_depth@->create_data_property(property_index@recursion_depth@, wrapped_element@recursion_depth@)); | ||||
|     } | ||||
| 
 | ||||
|     @result_expression@ new_array@recursion_depth@; | ||||
| )~~~"); | ||||
|     } else if (type.name == "boolean" || type.name == "double") { | ||||
|         scoped_generator.append(R"~~~( | ||||
|  | @ -1300,9 +1366,15 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va | |||
|         @result_expression@ @value@.callback.cell(); | ||||
| )~~~"); | ||||
|     } else { | ||||
|         scoped_generator.append(R"~~~( | ||||
|         if (wrapping_reference == WrappingReference::No) { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     @result_expression@ wrap(global_object, const_cast<@type@&>(*@value@)); | ||||
| )~~~"); | ||||
|         } else { | ||||
|             scoped_generator.append(R"~~~( | ||||
|     @result_expression@ wrap(global_object, const_cast<@type@&>(@value@)); | ||||
| )~~~"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (type.nullable) { | ||||
|  | @ -1383,7 +1455,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@) | |||
|     [[maybe_unused]] auto retval = result.release_value(); | ||||
| )~~~"); | ||||
| 
 | ||||
|     generate_return_statement(generator, function.return_type); | ||||
|     generate_return_statement(generator, *function.return_type); | ||||
| 
 | ||||
|     function_generator.append(R"~~~( | ||||
| } | ||||
|  | @ -1675,10 +1747,10 @@ static JS::Value wrap_for_legacy_platform_object_get_own_property(JS::GlobalObje | |||
| )~~~"); | ||||
| 
 | ||||
|         if (interface.named_property_getter.has_value()) { | ||||
|             generate_return_statement(scoped_generator, interface.named_property_getter->return_type); | ||||
|             generate_return_statement(scoped_generator, *interface.named_property_getter->return_type); | ||||
|         } else { | ||||
|             VERIFY(interface.indexed_property_getter.has_value()); | ||||
|             generate_return_statement(scoped_generator, interface.indexed_property_getter->return_type); | ||||
|             generate_return_statement(scoped_generator, *interface.indexed_property_getter->return_type); | ||||
|         } | ||||
| 
 | ||||
|         scoped_generator.append(R"~~~( | ||||
|  | @ -2319,7 +2391,7 @@ JS::ThrowCompletionOr<bool> @class_name@::internal_delete(JS::PropertyName const | |||
| )~~~"); | ||||
| 
 | ||||
|                     // 2. If operation was declared with a return type of boolean and the steps returned false, then return false.
 | ||||
|                     if (interface.named_property_deleter->return_type.name == "boolean") { | ||||
|                     if (interface.named_property_deleter->return_type->name == "boolean") { | ||||
|                         function_scoped_generator.append(R"~~~( | ||||
|         bool succeeded = result.release_value(); | ||||
|         if (!succeeded) | ||||
|  | @ -3112,7 +3184,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.getter_callback@) | |||
|         } | ||||
| 
 | ||||
|         if (attribute.extended_attributes.contains("Reflect")) { | ||||
|             if (attribute.type.name != "boolean") { | ||||
|             if (attribute.type->name != "boolean") { | ||||
|                 attribute_generator.append(R"~~~( | ||||
|     auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@); | ||||
| )~~~"); | ||||
|  | @ -3127,7 +3199,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.getter_callback@) | |||
| )~~~"); | ||||
|         } | ||||
| 
 | ||||
|         generate_return_statement(generator, attribute.type); | ||||
|         generate_return_statement(generator, *attribute.type); | ||||
| 
 | ||||
|         attribute_generator.append(R"~~~( | ||||
| } | ||||
|  | @ -3147,7 +3219,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@) | |||
|             generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface.dictionaries, false, attribute.extended_attributes.contains("LegacyNullToEmptyString")); | ||||
| 
 | ||||
|             if (attribute.extended_attributes.contains("Reflect")) { | ||||
|                 if (attribute.type.name != "boolean") { | ||||
|                 if (attribute.type->name != "boolean") { | ||||
|                     attribute_generator.append(R"~~~( | ||||
|     impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value); | ||||
| )~~~"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Luke Wilde
						Luke Wilde