summaryrefslogtreecommitdiff
path: root/Meta
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2022-03-30 23:35:13 +0300
committerAndreas Kling <kling@serenityos.org>2022-03-31 01:10:47 +0200
commit1c4f128fd126ea70c557114fe80d54ee4a7f8757 (patch)
treecb4635b10070062feb2707a3cd0168ab0850b9c5 /Meta
parent9ff79c9d54dba1591968df6e39f57c8e8dc73fce (diff)
downloadserenity-1c4f128fd126ea70c557114fe80d54ee4a7f8757.zip
LibWeb: Add support for IDL callback functions
Diffstat (limited to 'Meta')
-rw-r--r--Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp48
-rw-r--r--Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp28
-rw-r--r--Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h1
-rw-r--r--Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h7
4 files changed, 84 insertions, 0 deletions
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp
index 1cf8c31387..0b6cdd61d4 100644
--- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp
+++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp
@@ -640,6 +640,32 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
}
+ } else if (interface.callback_functions.contains(parameter.type->name)) {
+ // https://webidl.spec.whatwg.org/#es-callback-function
+
+ auto callback_function_generator = scoped_generator.fork();
+ auto& callback_function = interface.callback_functions.find(parameter.type->name)->value;
+
+ // An ECMAScript value V is converted to an IDL callback function type value by running the following algorithm:
+ // 1. If the result of calling IsCallable(V) is false and the conversion to an IDL value is not being performed due to V being assigned to an attribute whose type is a nullable callback function that is annotated with [LegacyTreatNonObjectAsNull], then throw a TypeError.
+ if (!callback_function.is_legacy_treat_non_object_as_null) {
+ callback_function_generator.append(R"~~~(
+ if (!@js_name@@js_suffix@.is_function())
+ return vm.throw_completion<JS::TypeError>(global_object, JS::ErrorType::NotAFunction, @js_name@@js_suffix@.to_string_without_side_effects());
+)~~~");
+ }
+ // 2. Return the IDL callback function type value that represents a reference to the same object that V represents, with the incumbent settings object as the callback context.
+ if (callback_function.is_legacy_treat_non_object_as_null) {
+ callback_function_generator.append(R"~~~(
+ Optional<Bindings::CallbackType> @cpp_name@;
+ if (@js_name@@js_suffix@.is_object())
+ @cpp_name@ = Bindings::CallbackType { JS::make_handle(&@js_name@@js_suffix@.as_object()), HTML::incumbent_settings_object() };
+)~~~");
+ } else {
+ callback_function_generator.append(R"~~~(
+ auto @cpp_name@ = Bindings::CallbackType { JS::make_handle(&@js_name@@js_suffix@.as_object()), HTML::incumbent_settings_object() };
+)~~~");
+ }
} else if (parameter.type->name == "sequence") {
// https://webidl.spec.whatwg.org/#es-sequence
@@ -1342,6 +1368,28 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va
scoped_generator.append(R"~~~(
@result_expression@ JS::js_string(global_object.heap(), Bindings::idl_enum_to_string(@value@));
)~~~");
+ } else if (interface.callback_functions.contains(type.name)) {
+ // https://webidl.spec.whatwg.org/#es-callback-function
+
+ auto& callback_function = interface.callback_functions.find(type.name)->value;
+
+ // The result of converting an IDL callback function type value to an ECMAScript value is a reference to the same object that the IDL callback function type value represents.
+
+ if (callback_function.is_legacy_treat_non_object_as_null && !type.nullable) {
+ scoped_generator.append(R"~~~(
+ if (!@value@) {
+ @result_expression@ JS::js_null();
+ } else {
+ VERIFY(!@value@->callback.is_null());
+ @result_expression@ @value@->callback.cell();
+ }
+)~~~");
+ } else {
+ scoped_generator.append(R"~~~(
+ VERIFY(!@value@->callback.is_null());
+ @result_expression@ @value@->callback.cell();
+)~~~");
+ }
} else {
if (wrapping_reference == WrappingReference::No) {
scoped_generator.append(R"~~~(
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp
index 08a391dfaf..8c1fe69851 100644
--- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp
+++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp
@@ -722,6 +722,29 @@ void Parser::parse_interface_mixin(Interface& interface)
interface.mixins.set(move(name), move(mixin_interface));
}
+void Parser::parse_callback_function(HashMap<String, String>& extended_attributes, Interface& interface)
+{
+ assert_string("callback");
+ consume_whitespace();
+
+ auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); });
+ consume_whitespace();
+
+ assert_specific('=');
+ consume_whitespace();
+
+ auto return_type = parse_type();
+ consume_whitespace();
+ assert_specific('(');
+ auto parameters = parse_parameters();
+ assert_specific(')');
+ consume_whitespace();
+ assert_specific(';');
+
+ interface.callback_functions.set(name, CallbackFunction { move(return_type), move(parameters), extended_attributes.contains("LegacyTreatNonObjectAsNull") });
+ consume_whitespace();
+}
+
void Parser::parse_non_interface_entities(bool allow_interface, Interface& interface)
{
while (!lexer.is_eof()) {
@@ -736,6 +759,8 @@ void Parser::parse_non_interface_entities(bool allow_interface, Interface& inter
parse_typedef(interface);
} else if (lexer.next_is("interface mixin")) {
parse_interface_mixin(interface);
+ } else if (lexer.next_is("callback")) {
+ parse_callback_function(extended_attributes, interface);
} else if ((allow_interface && !lexer.next_is("interface")) || !allow_interface) {
auto current_offset = lexer.tell();
auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); });
@@ -841,6 +866,9 @@ NonnullOwnPtr<Interface> Parser::parse()
report_parsing_error(String::formatted("Mixin '{}' was already defined in {}", mixin.key, mixin.value->module_own_path), filename, input, lexer.tell());
interface->mixins.set(mixin.key, move(mixin.value));
}
+
+ for (auto& callback_function : import.callback_functions)
+ interface->callback_functions.set(callback_function.key, move(callback_function.value));
}
// Resolve mixins
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h
index 4ce432772c..db8148bcc3 100644
--- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h
+++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h
@@ -41,6 +41,7 @@ private:
void parse_typedef(Interface&);
void parse_interface_mixin(Interface&);
void parse_dictionary(Interface&);
+ void parse_callback_function(HashMap<String, String>& extended_attributes, Interface&);
void parse_constructor(Interface&);
void parse_getter(HashMap<String, String>& extended_attributes, Interface&);
void parse_setter(HashMap<String, String>& extended_attributes, Interface&);
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h
index 39faff027f..391891d335 100644
--- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h
+++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h
@@ -133,6 +133,12 @@ struct Enumeration {
bool is_original_definition { true };
};
+struct CallbackFunction {
+ NonnullRefPtr<Type> return_type;
+ Vector<Parameter> parameters;
+ bool is_legacy_treat_non_object_as_null { false };
+};
+
struct Interface;
struct ParameterizedType : public Type {
@@ -191,6 +197,7 @@ struct Interface {
HashMap<String, Enumeration> enumerations;
HashMap<String, Typedef> typedefs;
HashMap<String, NonnullOwnPtr<Interface>> mixins;
+ HashMap<String, CallbackFunction> callback_functions;
// Added for convenience after parsing
String wrapper_class;