diff --git a/Libraries/LibIDL/IDLParser.cpp b/Libraries/LibIDL/IDLParser.cpp index 31106c8e69c..8cda82eeebf 100644 --- a/Libraries/LibIDL/IDLParser.cpp +++ b/Libraries/LibIDL/IDLParser.cpp @@ -919,7 +919,7 @@ void Parser::parse_typedef(Interface& interface) consume_whitespace(); } -void Parser::parse_dictionary(Interface& interface) +void Parser::parse_dictionary(HashMap extended_attributes, Interface& interface) { bool partial = false; if (lexer.next_is("partial")) { @@ -932,6 +932,7 @@ void Parser::parse_dictionary(Interface& interface) consume_whitespace(); Dictionary dictionary {}; + dictionary.extended_attributes = move(extended_attributes); auto name = parse_identifier_ending_with_space(); consume_whitespace(); @@ -953,10 +954,10 @@ void Parser::parse_dictionary(Interface& interface) } bool required = false; - HashMap extended_attributes; + HashMap member_extended_attributes; if (lexer.consume_specific('[')) - extended_attributes = parse_extended_attributes(); + member_extended_attributes = parse_extended_attributes(); if (lexer.consume_specific("required"sv)) { required = true; @@ -964,7 +965,7 @@ void Parser::parse_dictionary(Interface& interface) } if (lexer.consume_specific('[')) - extended_attributes.update(parse_extended_attributes()); + member_extended_attributes.update(parse_extended_attributes()); auto type = parse_type(); consume_whitespace(); @@ -987,7 +988,7 @@ void Parser::parse_dictionary(Interface& interface) required, move(type), move(name), - move(extended_attributes), + move(member_extended_attributes), Optional(move(default_value)), }; dictionary.members.append(move(member)); @@ -1061,7 +1062,7 @@ void Parser::parse_non_interface_entities(bool allow_interface, Interface& inter if (lexer.consume_specific('[')) extended_attributes = parse_extended_attributes(); if (lexer.next_is("dictionary") || lexer.next_is("partial dictionary")) { - parse_dictionary(interface); + parse_dictionary(extended_attributes, interface); } else if (lexer.next_is("enum")) { parse_enumeration(extended_attributes, interface); } else if (lexer.next_is("typedef")) { @@ -1205,7 +1206,11 @@ Interface& Parser::parse() interface.extend_with_partial_interface(*partial_interface); } - interface.dictionaries.update(import.dictionaries); + for (auto& dictionary : import.dictionaries) { + auto dictionary_copy = dictionary.value; + dictionary_copy.is_original_definition = false; + interface.dictionaries.set(dictionary.key, move(dictionary_copy)); + } for (auto& partial_dictionary : import.partial_dictionaries) { auto& it = interface.partial_dictionaries.ensure(partial_dictionary.key); diff --git a/Libraries/LibIDL/IDLParser.h b/Libraries/LibIDL/IDLParser.h index 16ae1998da6..cf6fc465db8 100644 --- a/Libraries/LibIDL/IDLParser.h +++ b/Libraries/LibIDL/IDLParser.h @@ -51,7 +51,7 @@ private: void parse_enumeration(HashMap, Interface&); void parse_typedef(Interface&); void parse_interface_mixin(Interface&); - void parse_dictionary(Interface&); + void parse_dictionary(HashMap extended_attributes, Interface&); void parse_callback_function(HashMap& extended_attributes, Interface&); void parse_constructor(HashMap& extended_attributes, Interface&); void parse_getter(HashMap& extended_attributes, Interface&); diff --git a/Libraries/LibIDL/Types.h b/Libraries/LibIDL/Types.h index 790b85a9d52..e9ca0c423f1 100644 --- a/Libraries/LibIDL/Types.h +++ b/Libraries/LibIDL/Types.h @@ -208,6 +208,8 @@ struct DictionaryMember { struct Dictionary { ByteString parent_name; Vector members; + HashMap extended_attributes; + bool is_original_definition { true }; }; struct Typedef { @@ -336,7 +338,7 @@ public: bool will_generate_code() const { - return !name.is_empty() || any_of(enumerations, [](auto& entry) { return entry.value.is_original_definition; }); + return !name.is_empty() || any_of(dictionaries, [](auto& entry) { return entry.value.is_original_definition; }) || any_of(enumerations, [](auto& entry) { return entry.value.is_original_definition; }); } void extend_with_partial_interface(Interface const&); diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 6a91bc36a7f..6c9ab144878 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -2953,6 +2953,33 @@ static ByteString get_best_value_for_underlying_enum_type(size_t size) VERIFY_NOT_REACHED(); } +static void generate_dictionaries(SourceGenerator& generator, IDL::Interface const& interface) +{ + for (auto const& it : interface.dictionaries) { + if (!it.value.is_original_definition) + continue; + if (!it.value.extended_attributes.contains("GenerateToValue"sv)) + continue; + auto dictionary_generator = generator.fork(); + dictionary_generator.set("dictionary.name", make_input_acceptable_cpp(it.key)); + dictionary_generator.set("dictionary.name:snakecase", make_input_acceptable_cpp(it.key.to_snakecase())); + dictionary_generator.append(R"~~~( +JS::Value @dictionary.name:snakecase@_to_value(JS::Realm&, @dictionary.name@ const&); +JS::Value @dictionary.name:snakecase@_to_value(JS::Realm& realm, @dictionary.name@ const& dictionary) +{ + auto& vm = realm.vm(); + @dictionary.name@ copy = dictionary; +)~~~"); + // FIXME: Support generating wrap statements for lvalues and get rid of the copy above + auto dictionary_type = adopt_ref(*new Type(it.key, false)); + generate_wrap_statement(dictionary_generator, "copy", dictionary_type, interface, "return"sv); + + dictionary_generator.append(R"~~~( +} +)~~~"); + } +} + static void generate_enumerations(HashMap const& enumerations, StringBuilder& builder) { SourceGenerator generator { builder }; @@ -4748,6 +4775,8 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::clear) )~~~"); } } + + generate_dictionaries(generator, interface); } void generate_namespace_header(IDL::Interface const& interface, StringBuilder& builder)