From 300f212044e5475a8e14c585a79c0b5bb56688f4 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Thu, 14 Nov 2024 16:13:44 +0000 Subject: [PATCH] LibIDL: Support multiple import base paths for resolving imports This allows us to specify multiple base paths to look for imported IDL files in. This will allow us to import IDL files from sources and from the Build directory (i.e. for generated IDL files). --- Libraries/LibIDL/IDLParser.cpp | 29 ++++++++++++++----- Libraries/LibIDL/IDLParser.h | 6 ++-- .../LibWeb/BindingsGenerator/main.cpp | 10 +++---- .../GenerateWindowOrWorkerInterfaces.cpp | 25 ++++++++++++---- 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/Libraries/LibIDL/IDLParser.cpp b/Libraries/LibIDL/IDLParser.cpp index 8c419463825..937b1ed7440 100644 --- a/Libraries/LibIDL/IDLParser.cpp +++ b/Libraries/LibIDL/IDLParser.cpp @@ -160,9 +160,22 @@ HashMap Parser::parse_extended_attributes() static HashTable import_stack; Optional Parser::resolve_import(auto path) { - auto include_path = LexicalPath::join(import_base_path, path).string(); - if (!FileSystem::exists(include_path)) - report_parsing_error(ByteString::formatted("{}: No such file or directory", include_path), filename, input, lexer.tell()); + ByteString include_path; + for (auto import_base_path : import_base_paths) { + auto maybe_include_path = LexicalPath::join(import_base_path, path).string(); + if (!FileSystem::exists(maybe_include_path)) + continue; + + include_path = maybe_include_path; + break; + } + + if (include_path.is_empty()) { + StringBuilder error_message; + error_message.appendff("Failed to find {} in the following directories:\n", path); + error_message.join('\n', import_base_paths); + report_parsing_error(error_message.to_byte_string(), filename, input, lexer.tell()); + } auto real_path_error_or = FileSystem::real_path(include_path); if (real_path_error_or.is_error()) @@ -183,7 +196,7 @@ Optional Parser::resolve_import(auto path) auto data_or_error = file_or_error.value()->read_until_eof(); if (data_or_error.is_error()) report_parsing_error(ByteString::formatted("Failed to read {}: {}", real_path, data_or_error.error()), filename, input, lexer.tell()); - auto& result = Parser(this, real_path, data_or_error.value(), import_base_path).parse(); + auto& result = Parser(this, real_path, data_or_error.value(), import_base_paths).parse(); import_stack.remove(real_path); top_level_resolved_imports().set(real_path, &result); @@ -1229,16 +1242,16 @@ Interface& Parser::parse() return interface; } -Parser::Parser(ByteString filename, StringView contents, ByteString import_base_path) - : import_base_path(move(import_base_path)) +Parser::Parser(ByteString filename, StringView contents, Vector import_base_paths) + : import_base_paths(move(import_base_paths)) , filename(move(filename)) , input(contents) , lexer(input) { } -Parser::Parser(Parser* parent, ByteString filename, StringView contents, ByteString import_base_path) - : import_base_path(move(import_base_path)) +Parser::Parser(Parser* parent, ByteString filename, StringView contents, Vector import_base_paths) + : import_base_paths(move(import_base_paths)) , filename(move(filename)) , input(contents) , lexer(input) diff --git a/Libraries/LibIDL/IDLParser.h b/Libraries/LibIDL/IDLParser.h index 997f735059a..eff941706ab 100644 --- a/Libraries/LibIDL/IDLParser.h +++ b/Libraries/LibIDL/IDLParser.h @@ -17,7 +17,7 @@ namespace IDL { class Parser { public: - Parser(ByteString filename, StringView contents, ByteString import_base_path); + Parser(ByteString filename, StringView contents, Vector import_base_paths); Interface& parse(); Vector imported_files() const; @@ -35,7 +35,7 @@ private: Yes, }; - Parser(Parser* parent, ByteString filename, StringView contents, ByteString import_base_path); + Parser(Parser* parent, ByteString filename, StringView contents, Vector import_base_path); void assert_specific(char ch); void assert_string(StringView expected); @@ -68,7 +68,7 @@ private: ByteString parse_identifier_ending_with_space(); ByteString parse_identifier_ending_with_space_or(auto... possible_terminating_characters); - ByteString import_base_path; + Vector import_base_paths; ByteString filename; StringView input; LineTrackingLexer lexer; diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp index fb9cfd87f67..6fa4f401fcd 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/main.cpp @@ -21,7 +21,7 @@ ErrorOr serenity_main(Main::Arguments arguments) { Core::ArgsParser args_parser; StringView path; - StringView import_base_path; + Vector import_base_paths; StringView output_path = "-"sv; StringView depfile_path; StringView depfile_prefix; @@ -41,7 +41,7 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.add_option(depfile_path, "Path to write dependency file to", "depfile", 'd', "depfile-path"); args_parser.add_option(depfile_prefix, "Prefix to prepend to relative paths in dependency file", "depfile-prefix", 'p', "depfile-prefix"); args_parser.add_positional_argument(path, "IDL file", "idl-file"); - args_parser.add_positional_argument(import_base_path, "Import base path", "import-base-path", Core::ArgsParser::Required::No); + args_parser.add_positional_argument(import_base_paths, "Import base path", "import-base-path", Core::ArgsParser::Required::No); args_parser.parse(arguments); auto idl_file = TRY(Core::File::open(path, Core::File::OpenMode::Read)); @@ -51,10 +51,10 @@ ErrorOr serenity_main(Main::Arguments arguments) auto data = TRY(idl_file->read_until_eof()); - if (import_base_path.is_null()) - import_base_path = lexical_path.dirname(); + if (import_base_paths.is_empty()) + import_base_paths.append(lexical_path.dirname()); - IDL::Parser parser(path, data, import_base_path); + IDL::Parser parser(path, data, move(import_base_paths)); auto& interface = parser.parse(); // If the interface name is the same as its namespace, qualify the name in the generated code. diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWindowOrWorkerInterfaces.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWindowOrWorkerInterfaces.cpp index 08573a62a0a..0f7438acf79 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWindowOrWorkerInterfaces.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWindowOrWorkerInterfaces.cpp @@ -335,18 +335,33 @@ ErrorOr serenity_main(Main::Arguments arguments) Core::ArgsParser args_parser; StringView output_path; - StringView base_path; + Vector base_paths; Vector paths; args_parser.add_option(output_path, "Path to output generated files into", "output-path", 'o', "output-path"); - args_parser.add_option(base_path, "Path to root of IDL file tree", "base-path", 'b', "base-path"); + args_parser.add_option(Core::ArgsParser::Option { + .argument_mode = Core::ArgsParser::OptionArgumentMode::Required, + .help_string = "Path to root of IDL file tree(s)", + .long_name = "base-path", + .short_name = 'b', + .value_name = "base-path", + .accept_value = [&](StringView s) { + base_paths.append(s); + return true; + }, + }); args_parser.add_positional_argument(paths, "Paths of every IDL file that could be Exposed", "paths"); args_parser.parse(arguments); VERIFY(!paths.is_empty()); - VERIFY(!base_path.is_empty()); + VERIFY(!base_paths.is_empty()); - LexicalPath const lexical_base(base_path); + Vector lexical_bases; + for (auto const& base_path : base_paths) { + VERIFY(!base_path.is_empty()); + LexicalPath lexical_path(base_path); + lexical_bases.append(lexical_path.string()); + } // Read in all IDL files, we must own the storage for all of these for the lifetime of the program Vector file_contents; @@ -372,7 +387,7 @@ ErrorOr serenity_main(Main::Arguments arguments) for (size_t i = 0; i < paths.size(); ++i) { auto const& path = paths[i]; - IDL::Parser parser(path, file_contents[i], lexical_base.string()); + IDL::Parser parser(path, file_contents[i], lexical_bases); auto& interface = parser.parse(); if (interface.name.is_empty()) { s_error_string = ByteString::formatted("Interface for file {} missing", path);