From 067a53b7e7984d193abb0d0b69aad9ddfbd2745a Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Sat, 8 Oct 2022 16:48:04 -0600 Subject: [PATCH] LibIDL: Remove static maps for interfaces and resolved imports Instead, create a tree of Parsers all pointing to a top-level Parser. All module imports and interfaces are stored at the top level, instead of in a static map. This allows creating multiple IDL::Parsers in the same process without them stepping on each others toes. --- .../LibWeb/BindingsGenerator/main.cpp | 3 +- Userland/Libraries/LibIDL/IDLParser.cpp | 48 +++++++++++++++---- Userland/Libraries/LibIDL/IDLParser.h | 12 +++-- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp index 52dbbd9d59..7e46159158 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp @@ -71,7 +71,8 @@ int main(int argc, char** argv) if (import_base_path.is_null()) import_base_path = lexical_path.dirname(); - auto& interface = IDL::Parser(path, data, import_base_path).parse(); + IDL::Parser parser(path, data, import_base_path); + auto& interface = parser.parse(); static constexpr Array libweb_interface_namespaces = { "CSS"sv, diff --git a/Userland/Libraries/LibIDL/IDLParser.cpp b/Userland/Libraries/LibIDL/IDLParser.cpp index 6f840f9b29..531bf764cf 100644 --- a/Userland/Libraries/LibIDL/IDLParser.cpp +++ b/Userland/Libraries/LibIDL/IDLParser.cpp @@ -8,6 +8,7 @@ */ #include "IDLParser.h" +#include #include #include #include @@ -76,9 +77,6 @@ static String convert_enumeration_value_to_cpp_enum_member(String const& value, namespace IDL { -HashTable> Parser::s_interfaces {}; -HashMap Parser::s_resolved_imports {}; - void Parser::assert_specific(char ch) { if (!lexer.consume_specific(ch)) @@ -143,8 +141,8 @@ Optional Parser::resolve_import(auto path) report_parsing_error(String::formatted("{}: No such file or directory", include_path), filename, input, lexer.tell()); auto real_path = Core::File::real_path_for(include_path); - if (s_resolved_imports.contains(real_path)) - return *s_resolved_imports.find(real_path)->value; + if (top_level_resolved_imports().contains(real_path)) + return *top_level_resolved_imports().find(real_path)->value; if (import_stack.contains(real_path)) report_parsing_error(String::formatted("Circular import detected: {}", include_path), filename, input, lexer.tell()); @@ -155,10 +153,10 @@ Optional Parser::resolve_import(auto path) report_parsing_error(String::formatted("Failed to open {}: {}", real_path, file_or_error.error()), filename, input, lexer.tell()); auto data = file_or_error.value()->read_all(); - auto& result = Parser(real_path, data, import_base_path).parse(); + auto& result = Parser(this, real_path, data, import_base_path).parse(); import_stack.remove(real_path); - s_resolved_imports.set(real_path, &result); + top_level_resolved_imports().set(real_path, &result); return result; } @@ -736,7 +734,7 @@ void Parser::parse_interface_mixin(Interface& interface) { auto mixin_interface_ptr = make(); auto& mixin_interface = *mixin_interface_ptr; - VERIFY(s_interfaces.set(move(mixin_interface_ptr)) == AK::HashSetResult::InsertedNewEntry); + VERIFY(top_level_interfaces().set(move(mixin_interface_ptr)) == AK::HashSetResult::InsertedNewEntry); mixin_interface.module_own_path = interface.module_own_path; mixin_interface.is_mixin = true; @@ -856,9 +854,9 @@ Interface& Parser::parse() auto interface_ptr = make(); auto& interface = *interface_ptr; - VERIFY(s_interfaces.set(move(interface_ptr)) == AK::HashSetResult::InsertedNewEntry); + VERIFY(top_level_interfaces().set(move(interface_ptr)) == AK::HashSetResult::InsertedNewEntry); interface.module_own_path = this_module; - s_resolved_imports.set(this_module, &interface); + top_level_resolved_imports().set(this_module, &interface); Vector imports; HashTable required_imported_paths; @@ -998,6 +996,9 @@ Interface& Parser::parse() interface.required_imported_paths.set(this_module); interface.imported_modules = move(imports); + if (top_level_parser() == this) + VERIFY(import_stack.is_empty()); + return interface; } @@ -1009,4 +1010,31 @@ Parser::Parser(String filename, StringView contents, String import_base_path) { } +Parser::Parser(Parser* parent, String filename, StringView contents, String import_base_path) + : import_base_path(move(import_base_path)) + , filename(move(filename)) + , input(contents) + , lexer(input) + , parent(parent) +{ +} + +Parser* Parser::top_level_parser() +{ + Parser* current = this; + for (Parser* next = this; next; next = next->parent) + current = next; + return current; +} + +HashMap& Parser::top_level_resolved_imports() +{ + return top_level_parser()->resolved_imports; +} + +HashTable>& Parser::top_level_interfaces() +{ + return top_level_parser()->interfaces; +} + } diff --git a/Userland/Libraries/LibIDL/IDLParser.h b/Userland/Libraries/LibIDL/IDLParser.h index 9cf488513b..4c72030dcf 100644 --- a/Userland/Libraries/LibIDL/IDLParser.h +++ b/Userland/Libraries/LibIDL/IDLParser.h @@ -28,6 +28,8 @@ private: Yes, }; + Parser(Parser* parent, String filename, StringView contents, String import_base_path); + void assert_specific(char ch); void assert_string(StringView expected); void consume_whitespace(); @@ -53,13 +55,17 @@ private: NonnullRefPtr parse_type(); void parse_constant(Interface&); - static HashTable> s_interfaces; - static HashMap s_resolved_imports; - String import_base_path; String filename; StringView input; GenericLexer lexer; + + HashTable>& top_level_interfaces(); + HashTable> interfaces; + HashMap& top_level_resolved_imports(); + HashMap resolved_imports; + Parser* top_level_parser(); + Parser* parent = nullptr; }; }