IDLGenerators: Support generating dictionary to value converter helpers

This is useful when returning dictionaries as a Promise.
This commit is contained in:
Idan Horowitz 2025-08-05 20:24:27 +03:00 committed by Tim Flynn
commit dc1b7b1925
Notes: github-actions[bot] 2025-08-08 17:12:32 +00:00
4 changed files with 45 additions and 9 deletions

View file

@ -919,7 +919,7 @@ void Parser::parse_typedef(Interface& interface)
consume_whitespace();
}
void Parser::parse_dictionary(Interface& interface)
void Parser::parse_dictionary(HashMap<ByteString, ByteString> 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<ByteString, ByteString> extended_attributes;
HashMap<ByteString, ByteString> 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<ByteString>(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);

View file

@ -51,7 +51,7 @@ private:
void parse_enumeration(HashMap<ByteString, ByteString>, Interface&);
void parse_typedef(Interface&);
void parse_interface_mixin(Interface&);
void parse_dictionary(Interface&);
void parse_dictionary(HashMap<ByteString, ByteString> extended_attributes, Interface&);
void parse_callback_function(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
void parse_constructor(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
void parse_getter(HashMap<ByteString, ByteString>& extended_attributes, Interface&);

View file

@ -208,6 +208,8 @@ struct DictionaryMember {
struct Dictionary {
ByteString parent_name;
Vector<DictionaryMember> members;
HashMap<ByteString, ByteString> 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&);

View file

@ -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<ByteString, Enumeration> 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)