mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
LibWeb: Add support for converting IDL dictionaries to native structs
This commit is contained in:
parent
5ce468338e
commit
071a358ffb
1 changed files with 59 additions and 11 deletions
|
@ -818,7 +818,7 @@ static bool is_wrappable_type(IDL::Type const& type)
|
|||
}
|
||||
|
||||
template<typename ParameterType>
|
||||
static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, String const& js_name, String const& js_suffix, String const& cpp_name, bool return_void = false, bool legacy_null_to_empty_string = false, bool optional = false, Optional<String> optional_default_value = {})
|
||||
static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, String const& js_name, String const& js_suffix, String const& cpp_name, HashMap<String, IDL::Dictionary> const& dictionaries, bool return_void = false, bool legacy_null_to_empty_string = false, bool optional = false, Optional<String> optional_default_value = {})
|
||||
{
|
||||
auto scoped_generator = generator.fork();
|
||||
scoped_generator.set("cpp_name", make_input_acceptable_cpp(cpp_name));
|
||||
|
@ -1038,6 +1038,54 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (dictionaries.contains(parameter.type.name)) {
|
||||
if (optional_default_value.has_value() && optional_default_value != "{}")
|
||||
TODO();
|
||||
auto dictionary_generator = scoped_generator.fork();
|
||||
dictionary_generator.append(R"~~~(
|
||||
if (!@js_name@@js_suffix@.is_nullish() && !@js_name@@js_suffix@.is_object()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
|
||||
@return_statement@
|
||||
}
|
||||
@parameter.type.name@ @cpp_name@ {};
|
||||
)~~~");
|
||||
auto* current_dictionary = &dictionaries.find(parameter.type.name)->value;
|
||||
while (true) {
|
||||
for (auto& member : current_dictionary->members) {
|
||||
dictionary_generator.set("member_key", member.name);
|
||||
auto member_js_name = make_input_acceptable_cpp(member.name.to_snakecase());
|
||||
dictionary_generator.set("member_name", member_js_name);
|
||||
dictionary_generator.append(R"~~~(
|
||||
JS::Value @member_name@;
|
||||
if (@js_name@@js_suffix@.is_nullish()) {
|
||||
@member_name@ = JS::js_undefined();
|
||||
} else {
|
||||
@member_name@ = @js_name@@js_suffix@.as_object().get("@member_key@");
|
||||
if (vm.exception())
|
||||
@return_statement@
|
||||
}
|
||||
)~~~");
|
||||
if (member.required) {
|
||||
dictionary_generator.append(R"~~~(
|
||||
if (@member_name@.is_undefined()) {
|
||||
vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::MissingRequiredProperty, "@member_key@");
|
||||
@return_statement@
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
auto member_value_name = String::formatted("{}_value", member_js_name);
|
||||
dictionary_generator.set("member_value_name", member_value_name);
|
||||
generate_to_cpp(dictionary_generator, member, member_js_name, "", member_value_name, dictionaries, return_void, member.extended_attributes.contains("LegacyNullToEmptyString"), !member.required, member.default_value);
|
||||
dictionary_generator.append(R"~~~(
|
||||
@cpp_name@.@member_name@ = @member_value_name@;
|
||||
)~~~");
|
||||
}
|
||||
if (current_dictionary->parent_name.is_null())
|
||||
break;
|
||||
VERIFY(dictionaries.contains(current_dictionary->parent_name));
|
||||
current_dictionary = &dictionaries.find(current_dictionary->parent_name)->value;
|
||||
}
|
||||
} else {
|
||||
dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type.name);
|
||||
VERIFY_NOT_REACHED();
|
||||
|
@ -1069,7 +1117,7 @@ static void generate_argument_count_check(SourceGenerator& generator, FunctionTy
|
|||
)~~~");
|
||||
}
|
||||
|
||||
static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter> const& parameters, StringBuilder& arguments_builder, bool return_void = false)
|
||||
static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter> const& parameters, StringBuilder& arguments_builder, HashMap<String, IDL::Dictionary> const& dictionaries, bool return_void = false)
|
||||
{
|
||||
auto arguments_generator = generator.fork();
|
||||
|
||||
|
@ -1083,7 +1131,7 @@ static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter
|
|||
auto arg@argument.index@ = vm.argument(@argument.index@);
|
||||
)~~~");
|
||||
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);
|
||||
generate_to_cpp(generator, parameter, "arg", String::number(argument_index), parameter.name.to_snakecase(), dictionaries, return_void, legacy_null_to_empty_string, parameter.optional, parameter.optional_default_value);
|
||||
++argument_index;
|
||||
}
|
||||
|
||||
|
@ -1191,7 +1239,7 @@ static void generate_variable_statement(SourceGenerator& generator, String const
|
|||
return generate_wrap_statement(generator, value_name, value_type, String::formatted("{} = ", variable_name));
|
||||
}
|
||||
|
||||
static void generate_function(SourceGenerator& generator, IDL::Function const& function, StaticFunction is_static_function, String const& class_name, String const& interface_fully_qualified_name)
|
||||
static void generate_function(SourceGenerator& generator, IDL::Function const& function, StaticFunction is_static_function, String const& class_name, String const& interface_fully_qualified_name, HashMap<String, IDL::Dictionary> const& dictionaries)
|
||||
{
|
||||
auto function_generator = generator.fork();
|
||||
function_generator.set("class_name", class_name);
|
||||
|
@ -1222,7 +1270,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
|
|||
generate_argument_count_check(generator, function);
|
||||
|
||||
StringBuilder arguments_builder;
|
||||
generate_arguments(generator, function.parameters, arguments_builder);
|
||||
generate_arguments(generator, function.parameters, arguments_builder, dictionaries);
|
||||
function_generator.set(".arguments", arguments_builder.string_view());
|
||||
|
||||
if (is_static_function == StaticFunction::No) {
|
||||
|
@ -1802,7 +1850,7 @@ static void invoke_named_property_setter(JS::GlobalObject& global_object, @fully
|
|||
|
||||
// 4. Let value be the result of converting V to an IDL value of type T.
|
||||
// NOTE: This takes the last parameter as it's enforced that there's only two parameters.
|
||||
generate_to_cpp(scoped_generator, interface.named_property_setter->parameters.last(), "value", "", "converted_value", true);
|
||||
generate_to_cpp(scoped_generator, interface.named_property_setter->parameters.last(), "value", "", "converted_value", interface.dictionaries, true);
|
||||
|
||||
// 5. If operation was defined without an identifier, then:
|
||||
if (interface.named_property_setter->name.is_empty()) {
|
||||
|
@ -1860,7 +1908,7 @@ static void invoke_indexed_property_setter(JS::GlobalObject& global_object, @ful
|
|||
|
||||
// 5. Let value be the result of converting V to an IDL value of type T.
|
||||
// NOTE: This takes the last parameter as it's enforced that there's only two parameters.
|
||||
generate_to_cpp(scoped_generator, interface.named_property_setter->parameters.last(), "value", "", "converted_value", true);
|
||||
generate_to_cpp(scoped_generator, interface.named_property_setter->parameters.last(), "value", "", "converted_value", interface.dictionaries, true);
|
||||
|
||||
// 6. If operation was defined without an identifier, then:
|
||||
if (interface.indexed_property_setter->name.is_empty()) {
|
||||
|
@ -2425,7 +2473,7 @@ JS::Value @constructor_class@::construct(FunctionObject&)
|
|||
generate_argument_count_check(generator, constructor);
|
||||
|
||||
StringBuilder arguments_builder;
|
||||
generate_arguments(generator, constructor.parameters, arguments_builder);
|
||||
generate_arguments(generator, constructor.parameters, arguments_builder, interface.dictionaries);
|
||||
generator.set(".constructor_arguments", arguments_builder.string_view());
|
||||
|
||||
generator.append(R"~~~(
|
||||
|
@ -2489,7 +2537,7 @@ define_direct_property("@constant.name@", JS::Value((i32)@constant.value@), JS::
|
|||
|
||||
// Implementation: Static Functions
|
||||
for (auto& function : interface.static_functions) {
|
||||
generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name);
|
||||
generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name, interface.dictionaries);
|
||||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
|
@ -2914,7 +2962,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@)
|
|||
auto value = vm.argument(0);
|
||||
)~~~");
|
||||
|
||||
generate_to_cpp(generator, attribute, "value", "", "cpp_value", false, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
|
||||
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") {
|
||||
|
@ -2947,7 +2995,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@)
|
|||
|
||||
// Implementation: Functions
|
||||
for (auto& function : interface.functions) {
|
||||
generate_function(generator, function, StaticFunction::No, interface.prototype_class, interface.fully_qualified_name);
|
||||
generate_function(generator, function, StaticFunction::No, interface.prototype_class, interface.fully_qualified_name, interface.dictionaries);
|
||||
}
|
||||
|
||||
if (interface.has_stringifier) {
|
||||
|
|
Loading…
Add table
Reference in a new issue