diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp index a07022e787..151e36d942 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.cpp @@ -681,6 +681,25 @@ void Parser::parse_dictionary(Interface& interface) consume_whitespace(); } +void Parser::parse_interface_mixin(Interface& interface) +{ + auto mixin_interface = make(); + mixin_interface->module_own_path = interface.module_own_path; + mixin_interface->is_mixin = true; + + assert_string("interface"); + consume_whitespace(); + assert_string("mixin"); + auto offset = lexer.tell(); + + parse_interface(*mixin_interface); + if (!mixin_interface->parent_name.is_empty()) + report_parsing_error("Mixin interfaces are not allowed to have inherited parents", filename, input, offset); + + auto name = mixin_interface->name; + interface.mixins.set(move(name), move(mixin_interface)); +} + void Parser::parse_non_interface_entities(bool allow_interface, Interface& interface) { while (!lexer.is_eof()) { @@ -688,8 +707,22 @@ void Parser::parse_non_interface_entities(bool allow_interface, Interface& inter parse_dictionary(interface); } else if (lexer.next_is("enum")) { parse_enumeration(interface); + } else if (lexer.next_is("interface mixin")) { + parse_interface_mixin(interface); } else if ((allow_interface && !lexer.next_is("interface")) || !allow_interface) { - report_parsing_error("expected 'enum' or 'dictionary'", filename, input, lexer.tell()); + auto current_offset = lexer.tell(); + auto name = lexer.consume_until([](auto ch) { return is_ascii_space(ch); }); + consume_whitespace(); + if (lexer.consume_specific("includes")) { + consume_whitespace(); + auto mixin_name = lexer.consume_until([](auto ch) { return is_ascii_space(ch) || ch == ';'; }); + interface.included_mixins.ensure(name).set(mixin_name); + consume_whitespace(); + assert_specific(';'); + consume_whitespace(); + } else { + report_parsing_error("expected 'enum' or 'dictionary'", filename, input, current_offset); + } } else { break; } @@ -740,7 +773,36 @@ NonnullOwnPtr Parser::parse() enumeration_copy.is_original_definition = false; interface->enumerations.set(enumeration.key, move(enumeration_copy)); } + + for (auto& mixin : import.mixins) { + if (interface->mixins.contains(mixin.key)) + 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)); + } } + + // Resolve mixins + if (auto it = interface->included_mixins.find(interface->name); it != interface->included_mixins.end()) { + for (auto& entry : it->value) { + auto mixin_it = interface->mixins.find(entry); + if (mixin_it == interface->mixins.end()) + report_parsing_error(String::formatted("Mixin '{}' was never defined", entry), filename, input, lexer.tell()); + + auto& mixin = mixin_it->value; + interface->attributes.extend(mixin->attributes); + interface->constants.extend(mixin->constants); + interface->functions.extend(mixin->functions); + interface->static_functions.extend(mixin->static_functions); + if (interface->has_stringifier && mixin->has_stringifier) + report_parsing_error(String::formatted("Both interface '{}' and mixin '{}' have defined stringifier attributes", interface->name, mixin->name), filename, input, lexer.tell()); + + if (mixin->has_stringifier) { + interface->stringifier_attribute = mixin->stringifier_attribute; + interface->has_stringifier = true; + } + } + } + interface->imported_modules = move(imports); return interface; diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h index 5c408e1153..f2f4fe63bf 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLParser.h @@ -38,6 +38,7 @@ private: void parse_interface(Interface&); void parse_non_interface_entities(bool allow_interface, Interface&); void parse_enumeration(Interface&); + void parse_interface_mixin(Interface&); void parse_dictionary(Interface&); void parse_constructor(Interface&); void parse_getter(HashMap& extended_attributes, Interface&); diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h index f4a98bf0d1..ce90bf927c 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLTypes.h @@ -271,6 +271,8 @@ struct Interface { String name; String parent_name; + bool is_mixin { false }; + HashMap extended_attributes; Vector attributes; @@ -295,6 +297,7 @@ struct Interface { HashMap dictionaries; HashMap enumerations; + HashMap> mixins; // Added for convenience after parsing String wrapper_class; @@ -303,6 +306,7 @@ struct Interface { String constructor_class; String prototype_class; String prototype_base_class; + HashMap> included_mixins; String module_own_path; HashTable imported_paths;