Browse Source

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.
Andrew Kaster 2 years ago
parent
commit
067a53b7e7

+ 2 - 1
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,

+ 38 - 10
Userland/Libraries/LibIDL/IDLParser.cpp

@@ -8,6 +8,7 @@
  */
 
 #include "IDLParser.h"
+#include <AK/Assertions.h>
 #include <AK/LexicalPath.h>
 #include <AK/QuickSort.h>
 #include <LibCore/File.h>
@@ -76,9 +77,6 @@ static String convert_enumeration_value_to_cpp_enum_member(String const& value,
 
 namespace IDL {
 
-HashTable<NonnullOwnPtr<Interface>> Parser::s_interfaces {};
-HashMap<String, Interface*> Parser::s_resolved_imports {};
-
 void Parser::assert_specific(char ch)
 {
     if (!lexer.consume_specific(ch))
@@ -143,8 +141,8 @@ Optional<Interface&> 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<Interface&> 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<Interface>();
     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<Interface>();
     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<Interface&> imports;
     HashTable<String> 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<String, Interface*>& Parser::top_level_resolved_imports()
+{
+    return top_level_parser()->resolved_imports;
+}
+
+HashTable<NonnullOwnPtr<Interface>>& Parser::top_level_interfaces()
+{
+    return top_level_parser()->interfaces;
+}
+
 }

+ 9 - 3
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<Type> parse_type();
     void parse_constant(Interface&);
 
-    static HashTable<NonnullOwnPtr<Interface>> s_interfaces;
-    static HashMap<String, Interface*> s_resolved_imports;
-
     String import_base_path;
     String filename;
     StringView input;
     GenericLexer lexer;
+
+    HashTable<NonnullOwnPtr<Interface>>& top_level_interfaces();
+    HashTable<NonnullOwnPtr<Interface>> interfaces;
+    HashMap<String, Interface*>& top_level_resolved_imports();
+    HashMap<String, Interface*> resolved_imports;
+    Parser* top_level_parser();
+    Parser* parent = nullptr;
 };
 
 }