1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-19 09:27:34 +00:00

LibWeb: Cache and reuse resolved IDL imports instead of rejecting them

This ensures that transitive imports succeed even if they were directly
imported beforehand.
This commit is contained in:
Idan Horowitz 2022-04-01 21:43:02 +03:00 committed by Ali Mohammad Pur
parent 14dbd28033
commit 3ee8b5e534
3 changed files with 27 additions and 28 deletions

View file

@ -76,7 +76,7 @@ static String convert_enumeration_value_to_cpp_enum_member(String const& value,
namespace IDL { namespace IDL {
HashTable<String> Parser::s_all_imported_paths {}; HashMap<String, NonnullRefPtr<Interface>> Parser::s_resolved_imports {};
void Parser::assert_specific(char ch) void Parser::assert_specific(char ch)
{ {
@ -124,17 +124,20 @@ HashMap<String, String> Parser::parse_extended_attributes()
return extended_attributes; return extended_attributes;
} }
Optional<NonnullOwnPtr<Interface>> Parser::resolve_import(auto path) static HashTable<String> import_stack;
Optional<NonnullRefPtr<Interface>> Parser::resolve_import(auto path)
{ {
auto include_path = LexicalPath::join(import_base_path, path).string(); auto include_path = LexicalPath::join(import_base_path, path).string();
if (!Core::File::exists(include_path)) if (!Core::File::exists(include_path))
report_parsing_error(String::formatted("{}: No such file or directory", include_path), filename, input, lexer.tell()); 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); auto real_path = Core::File::real_path_for(include_path);
if (s_all_imported_paths.contains(real_path)) if (s_resolved_imports.contains(real_path))
return {}; return s_resolved_imports.find(real_path)->value;
s_all_imported_paths.set(real_path); if (import_stack.contains(real_path))
report_parsing_error(String::formatted("Circular import detected: {}", include_path), filename, input, lexer.tell());
import_stack.set(real_path);
auto file_or_error = Core::File::open(real_path, Core::OpenMode::ReadOnly); auto file_or_error = Core::File::open(real_path, Core::OpenMode::ReadOnly);
if (file_or_error.is_error()) if (file_or_error.is_error())
@ -142,8 +145,9 @@ Optional<NonnullOwnPtr<Interface>> Parser::resolve_import(auto path)
auto data = file_or_error.value()->read_all(); auto data = file_or_error.value()->read_all();
auto result = Parser(real_path, data, import_base_path).parse(); auto result = Parser(real_path, data, import_base_path).parse();
if (result->will_generate_code()) import_stack.remove(real_path);
required_imported_paths.set(real_path);
s_resolved_imports.set(real_path, result);
return result; return result;
} }
@ -705,7 +709,7 @@ void Parser::parse_dictionary(Interface& interface)
void Parser::parse_interface_mixin(Interface& interface) void Parser::parse_interface_mixin(Interface& interface)
{ {
auto mixin_interface = make<Interface>(); auto mixin_interface = make_ref_counted<Interface>();
mixin_interface->module_own_path = interface.module_own_path; mixin_interface->module_own_path = interface.module_own_path;
mixin_interface->is_mixin = true; mixin_interface->is_mixin = true;
@ -813,15 +817,15 @@ void resolve_function_typedefs(Interface& interface, FunctionType& function)
resolve_parameters_typedefs(interface, function.parameters); resolve_parameters_typedefs(interface, function.parameters);
} }
NonnullOwnPtr<Interface> Parser::parse() NonnullRefPtr<Interface> Parser::parse()
{ {
auto this_module = Core::File::real_path_for(filename); auto this_module = Core::File::real_path_for(filename);
s_all_imported_paths.set(this_module);
auto interface = make<Interface>(); auto interface = make_ref_counted<Interface>();
interface->module_own_path = this_module; interface->module_own_path = this_module;
s_resolved_imports.set(this_module, interface);
NonnullOwnPtrVector<Interface> imports; NonnullRefPtrVector<Interface> imports;
while (lexer.consume_specific("#import")) { while (lexer.consume_specific("#import")) {
consume_whitespace(); consume_whitespace();
assert_specific('<'); assert_specific('<');
@ -829,15 +833,12 @@ NonnullOwnPtr<Interface> Parser::parse()
lexer.ignore(); lexer.ignore();
auto maybe_interface = resolve_import(path); auto maybe_interface = resolve_import(path);
if (maybe_interface.has_value()) { if (maybe_interface.has_value()) {
for (auto& entry : maybe_interface.value()->all_imported_paths)
s_all_imported_paths.set(entry);
for (auto& entry : maybe_interface.value()->required_imported_paths) for (auto& entry : maybe_interface.value()->required_imported_paths)
required_imported_paths.set(entry); required_imported_paths.set(entry);
imports.append(maybe_interface.release_value()); imports.append(maybe_interface.release_value());
} }
consume_whitespace(); consume_whitespace();
} }
interface->all_imported_paths = s_all_imported_paths;
interface->required_imported_paths = required_imported_paths; interface->required_imported_paths = required_imported_paths;
parse_non_interface_entities(true, *interface); parse_non_interface_entities(true, *interface);
@ -859,16 +860,16 @@ NonnullOwnPtr<Interface> Parser::parse()
} }
for (auto& typedef_ : import.typedefs) for (auto& typedef_ : import.typedefs)
interface->typedefs.set(typedef_.key, move(typedef_.value)); interface->typedefs.set(typedef_.key, typedef_.value);
for (auto& mixin : import.mixins) { for (auto& mixin : import.mixins) {
if (interface->mixins.contains(mixin.key)) if (auto it = interface->mixins.find(mixin.key); it != interface->mixins.end() && it->value.ptr() != mixin.value.ptr())
report_parsing_error(String::formatted("Mixin '{}' was already defined in {}", mixin.key, mixin.value->module_own_path), filename, input, lexer.tell()); 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)); interface->mixins.set(mixin.key, mixin.value);
} }
for (auto& callback_function : import.callback_functions) for (auto& callback_function : import.callback_functions)
interface->callback_functions.set(callback_function.key, move(callback_function.value)); interface->callback_functions.set(callback_function.key, callback_function.value);
} }
// Resolve mixins // Resolve mixins

View file

@ -18,7 +18,7 @@ namespace IDL {
class Parser { class Parser {
public: public:
Parser(String filename, StringView contents, String import_base_path); Parser(String filename, StringView contents, String import_base_path);
NonnullOwnPtr<Interface> parse(); NonnullRefPtr<Interface> parse();
private: private:
// https://webidl.spec.whatwg.org/#dfn-special-operation // https://webidl.spec.whatwg.org/#dfn-special-operation
@ -31,7 +31,7 @@ private:
void assert_specific(char ch); void assert_specific(char ch);
void assert_string(StringView expected); void assert_string(StringView expected);
void consume_whitespace(); void consume_whitespace();
Optional<NonnullOwnPtr<Interface>> resolve_import(auto path); Optional<NonnullRefPtr<Interface>> resolve_import(auto path);
HashMap<String, String> parse_extended_attributes(); HashMap<String, String> parse_extended_attributes();
void parse_attribute(HashMap<String, String>& extended_attributes, Interface&); void parse_attribute(HashMap<String, String>& extended_attributes, Interface&);
@ -53,7 +53,7 @@ private:
NonnullRefPtr<Type> parse_type(); NonnullRefPtr<Type> parse_type();
void parse_constant(Interface&); void parse_constant(Interface&);
static HashTable<String> s_all_imported_paths; static HashMap<String, NonnullRefPtr<Interface>> s_resolved_imports;
HashTable<String> required_imported_paths; HashTable<String> required_imported_paths;
String import_base_path; String import_base_path;
String filename; String filename;

View file

@ -10,9 +10,8 @@
#pragma once #pragma once
#include <AK/HashMap.h> #include <AK/HashMap.h>
#include <AK/NonnullOwnPtrVector.h> #include <AK/NonnullRefPtr.h>
#include <AK/NonnullRefPtrVector.h> #include <AK/NonnullRefPtrVector.h>
#include <AK/OwnPtr.h>
#include <AK/SourceGenerator.h> #include <AK/SourceGenerator.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
@ -165,7 +164,7 @@ static inline size_t get_shortest_function_length(Vector<Function&> const& overl
return longest_length; return longest_length;
} }
struct Interface { struct Interface : public RefCounted<Interface> {
String name; String name;
String parent_name; String parent_name;
@ -196,7 +195,7 @@ struct Interface {
HashMap<String, Dictionary> dictionaries; HashMap<String, Dictionary> dictionaries;
HashMap<String, Enumeration> enumerations; HashMap<String, Enumeration> enumerations;
HashMap<String, Typedef> typedefs; HashMap<String, Typedef> typedefs;
HashMap<String, NonnullOwnPtr<Interface>> mixins; HashMap<String, NonnullRefPtr<Interface>> mixins;
HashMap<String, CallbackFunction> callback_functions; HashMap<String, CallbackFunction> callback_functions;
// Added for convenience after parsing // Added for convenience after parsing
@ -209,9 +208,8 @@ struct Interface {
HashMap<String, HashTable<String>> included_mixins; HashMap<String, HashTable<String>> included_mixins;
String module_own_path; String module_own_path;
HashTable<String> all_imported_paths;
HashTable<String> required_imported_paths; HashTable<String> required_imported_paths;
NonnullOwnPtrVector<Interface> imported_modules; NonnullRefPtrVector<Interface> imported_modules;
HashMap<String, Vector<Function&>> overload_sets; HashMap<String, Vector<Function&>> overload_sets;
HashMap<String, Vector<Function&>> static_overload_sets; HashMap<String, Vector<Function&>> static_overload_sets;