From c13ada4e0c9c3b196e69c7a9ac6b5a12b4efc1a6 Mon Sep 17 00:00:00 2001 From: Justus Garbe Date: Sun, 19 Nov 2023 23:21:55 +0100 Subject: [PATCH] resolver: rework resolvers & parser manager --- lib/CMakeLists.txt | 3 +- lib/include/pl/api.hpp | 2 -- lib/include/pl/core/parser.hpp | 7 +++-- lib/include/pl/core/parser_manager.hpp | 17 +++++++---- lib/include/pl/core/preprocessor.hpp | 11 ++++--- lib/include/pl/core/resolver.hpp | 36 +++++----------------- lib/include/pl/core/resolvers.hpp | 28 ++++++++++++++++++ lib/include/pl/pattern_language.hpp | 14 +++++++-- lib/source/pl/core/preprocessor.cpp | 10 +++---- lib/source/pl/core/resolver.cpp | 41 ++++++++++++++++++++++++++ lib/source/pl/core/resolvers.cpp | 41 ++------------------------ lib/source/pl/pattern_language.cpp | 11 +++++-- tests/source/main.cpp | 32 ++++---------------- 13 files changed, 131 insertions(+), 122 deletions(-) create mode 100644 lib/include/pl/core/resolvers.hpp create mode 100644 lib/source/pl/core/resolver.cpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 74e10e9c..8a81e70c 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -57,7 +57,7 @@ add_library(libpl ${LIBRARY_TYPE} source/pl/core/preprocessor.cpp source/pl/core/validator.cpp - source/pl/core/resolvers.cpp + source/pl/core/resolver.cpp source/pl/core/error.cpp source/pl/lib/std/pragmas.cpp @@ -70,6 +70,7 @@ add_library(libpl ${LIBRARY_TYPE} source/pl/lib/std/core.cpp source/pl/lib/std/hash.cpp source/pl/lib/std/random.cpp + source/pl/core/resolvers.cpp ) if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") diff --git a/lib/include/pl/api.hpp b/lib/include/pl/api.hpp index be0318ca..ccb826c4 100644 --- a/lib/include/pl/api.hpp +++ b/lib/include/pl/api.hpp @@ -39,8 +39,6 @@ namespace pl::api { static constexpr Source EmptySource = { "", "" }; - using IncludeResolver = std::function(const std::string&)>; - /** * @brief A type representing a custom section */ diff --git a/lib/include/pl/core/parser.hpp b/lib/include/pl/core/parser.hpp index afab0f66..270e2089 100644 --- a/lib/include/pl/core/parser.hpp +++ b/lib/include/pl/core/parser.hpp @@ -30,10 +30,9 @@ namespace pl::core { using TokenIter = std::vector::const_iterator; explicit Parser() = default; - explicit Parser(ParserManager* parserManager) : m_parserManager(parserManager) {} ~Parser() = default; - CompileResult parse(const std::string &sourceCode, const std::vector &tokens); + CompileResult>> parse(const std::string &sourceCode, const std::vector &tokens); const auto &getTypes() { return this->m_types; } @@ -45,6 +44,10 @@ namespace pl::core { this->m_currNamespace.push_back(path); } + void setParserManager(ParserManager* parserManager) { + this->m_parserManager = parserManager; + } + private: std::optional m_error; TokenIter m_curr; diff --git a/lib/include/pl/core/parser_manager.hpp b/lib/include/pl/core/parser_manager.hpp index 0f44192a..b1e01632 100644 --- a/lib/include/pl/core/parser_manager.hpp +++ b/lib/include/pl/core/parser_manager.hpp @@ -3,20 +3,25 @@ #include #include #include +#include -namespace pl::core { +#include - using AST = std::vector>; +namespace pl::core { class ParserManager { + public: + explicit ParserManager() = default; - explicit ParserManager(const api::IncludeResolver& resolver) : m_includeResolver(resolver) {} + CompileResult>> parse(const api::Source* source, const std::string &namespacePrefix = ""); - CompileResult parse(const std::string &code); + void setResolvers(Resolver* resolvers) { + m_resolvers = resolvers; + } private: - std::map m_astCache; - api::IncludeResolver m_includeResolver; + std::map>> m_astCache; + Resolver* m_resolvers = nullptr; }; } \ No newline at end of file diff --git a/lib/include/pl/core/preprocessor.hpp b/lib/include/pl/core/preprocessor.hpp index 085d957e..49f730c3 100644 --- a/lib/include/pl/core/preprocessor.hpp +++ b/lib/include/pl/core/preprocessor.hpp @@ -9,9 +9,9 @@ #include #include #include +#include #include -#include namespace pl::core { @@ -36,8 +36,8 @@ namespace pl::core { return this->m_onlyIncludeOnce; } - void setIncludeResolver(const api::IncludeResolver &resolver) { - this->m_includeResolver = resolver; + void setResolver(Resolver* resolvers) { + m_resolver = resolvers; } private: @@ -73,10 +73,9 @@ namespace pl::core { std::unordered_map> m_defines; std::unordered_map>> m_pragmas; - std::set m_onceIncludedFiles; - - api::IncludeResolver m_includeResolver; + std::set m_onceIncludedFiles; + Resolver *m_resolver = nullptr; PatternLanguage *m_runtime = nullptr; size_t m_offset = 0; diff --git a/lib/include/pl/core/resolver.hpp b/lib/include/pl/core/resolver.hpp index 77adf7df..f548c014 100644 --- a/lib/include/pl/core/resolver.hpp +++ b/lib/include/pl/core/resolver.hpp @@ -6,19 +6,16 @@ namespace pl::core { - using Resolver = std::function(const std::string&)>; + using SourceResolver = std::function(const std::string&)>; - class Resolvers { + class Resolver { public: - Resolvers() = default; + Resolver() = default; hlp::Result resolve(const std::string& path); - inline hlp::Result operator()(const std::string& path) { // forward for include resolver functional interface - return resolve(path); - } - inline void registerProtocol(const std::string& protocol, const Resolver& resolver) { + inline void registerProtocol(const std::string& protocol, const SourceResolver& resolver) { m_protocolResolvers[protocol] = resolver; } @@ -39,33 +36,14 @@ namespace pl::core { return setSource(source, api::Source(code, source)); } - inline void setDefaultResolver(const Resolver& resolver) const { + inline void setDefaultResolver(const SourceResolver& resolver) const { m_defaultResolver = resolver; } private: - mutable std::map m_protocolResolvers; // for git://, http(s):// - mutable Resolver m_defaultResolver; + mutable std::map m_protocolResolvers; // for git://, http(s):// + mutable SourceResolver m_defaultResolver; mutable std::map m_cachedSources; }; - class FileResolver { - public: - - FileResolver() = default; - explicit FileResolver(const std::vector& includePaths) : m_includePaths(includePaths) { } - - hlp::Result resolve(const std::string& path); - inline hlp::Result operator()(const std::string& path) { - return resolve(path); - } - - void setIncludePaths(const std::vector& includePaths) const { - this->m_includePaths = includePaths; - } - - private: - mutable std::vector m_includePaths; - }; - } \ No newline at end of file diff --git a/lib/include/pl/core/resolvers.hpp b/lib/include/pl/core/resolvers.hpp new file mode 100644 index 00000000..5d3e9f21 --- /dev/null +++ b/lib/include/pl/core/resolvers.hpp @@ -0,0 +1,28 @@ +// +// Created by justus on 19.11.23. +// + +#pragma once + +#include + +namespace pl::core { + class FileResolver { + public: + + FileResolver() = default; + explicit FileResolver(const std::vector& includePaths) : m_includePaths(includePaths) { } + + hlp::Result resolve(const std::string& path); + inline hlp::Result operator()(const std::string& path) { + return resolve(path); + } + + void setIncludePaths(const std::vector& includePaths) const { + this->m_includePaths = includePaths; + } + + private: + mutable std::vector m_includePaths; + }; +} \ No newline at end of file diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index fec7eee7..62ffdaea 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -185,7 +186,7 @@ namespace pl { */ void setIncludePaths(const std::vector& paths) const; - void setIncludeResolver(const api::IncludeResolver &resolver) const; + void setResolver(const core::Resolver& resolver); /** * @brief Registers a callback to be called when a dangerous function is being executed @@ -311,6 +312,14 @@ namespace pl { return this->m_internals; } + [[nodiscard]] core::Resolver& getResolver() { + return this->m_resolvers; + } + + [[nodiscard]] const core::Resolver& getResolver() const { + return this->m_resolvers; + } + /** * Adds a new cleanup callback that is called when the runtime is reset * @note This is useful for built-in functions that need to clean up their state @@ -345,7 +354,8 @@ namespace pl { std::vector m_compErrors; std::optional m_currError; - core::Resolvers m_resolvers; + core::Resolver m_resolvers; + core::ParserManager m_parserManager; std::map>> m_patterns; std::map> m_flattenedPatterns; diff --git a/lib/source/pl/core/preprocessor.cpp b/lib/source/pl/core/preprocessor.cpp index 2f022f95..35a2c19c 100644 --- a/lib/source/pl/core/preprocessor.cpp +++ b/lib/source/pl/core/preprocessor.cpp @@ -1,8 +1,6 @@ #include #include -#include - #include namespace pl::core { @@ -27,7 +25,7 @@ namespace pl::core { this->m_defines = other.m_defines; this->m_pragmas = other.m_pragmas; this->m_onceIncludedFiles = other.m_onceIncludedFiles; - this->m_includeResolver = other.m_includeResolver; + this->m_resolver = other.m_resolver; this->m_onlyIncludeOnce = false; this->m_pragmaHandlers = other.m_pragmaHandlers; this->m_directiveHandlers = other.m_directiveHandlers; @@ -204,18 +202,18 @@ namespace pl::core { return; } - const std::fs::path includePath = includeFile->substr(1, includeFile->length() - 2); + const std::string includePath = includeFile->substr(1, includeFile->length() - 2); // determine if we should include this file if (this->m_onceIncludedFiles.contains(includePath)) return; - if(!m_includeResolver) { + if(m_resolver == nullptr) { error_desc("Unable to lookup results", "No include resolver was set."); return; } - auto [resolved, error] = this->m_includeResolver(includePath); + auto [resolved, error] = this->m_resolver->resolve(includePath); if(!resolved.has_value()) { for (const auto &item: error) { diff --git a/lib/source/pl/core/resolver.cpp b/lib/source/pl/core/resolver.cpp new file mode 100644 index 00000000..fc007314 --- /dev/null +++ b/lib/source/pl/core/resolver.cpp @@ -0,0 +1,41 @@ +#include + +using namespace pl::core; +using namespace pl::api; +using namespace pl::hlp; + +Result Resolver::resolve(const std::string &path) { + using result_t = Result; + // look in cache + auto it = m_cachedSources.find(path); + if (it != m_cachedSources.end()) + return result_t::good(&it->second); + + Result result; + + // look for protocol + if(!m_protocolResolvers.empty()){ + auto protocolEnd = path.find("://"); + if (protocolEnd != std::string::npos) { + auto protocol = path.substr(0, protocolEnd); + auto protocolIt = m_protocolResolvers.find(protocol); + if (protocolIt != m_protocolResolvers.end()) { + result = protocolIt->second(path); + } + } + } + + if(!result.is_ok()) { + if (!m_defaultResolver) + return result_t::err("No possible way to resolve path " + path + " and no default resolver set"); + + result = m_defaultResolver(path); + } + + if (result.is_ok()) { + m_cachedSources[path] = result.unwrap(); + return result_t::good(&m_cachedSources[path]); + } + + return result_t::err(result.unwrap_errs()); +} \ No newline at end of file diff --git a/lib/source/pl/core/resolvers.cpp b/lib/source/pl/core/resolvers.cpp index 7b4d0ec5..bad6bcb2 100644 --- a/lib/source/pl/core/resolvers.cpp +++ b/lib/source/pl/core/resolvers.cpp @@ -1,48 +1,11 @@ -#include -#include +#include -#include +#include using namespace pl::core; using namespace pl::api; using namespace pl::hlp; -Result Resolvers::resolve(const std::string &path) { - using result_t = Result; - // look in cache - auto it = m_cachedSources.find(path); - if (it != m_cachedSources.end()) - return result_t::good(&it->second); - - Result result; - - // look for protocol - if(!m_protocolResolvers.empty()){ - auto protocolEnd = path.find("://"); - if (protocolEnd != std::string::npos) { - auto protocol = path.substr(0, protocolEnd); - auto protocolIt = m_protocolResolvers.find(protocol); - if (protocolIt != m_protocolResolvers.end()) { - result = protocolIt->second(path); - } - } - } - - if(!result.is_ok()) { - if (!m_defaultResolver) - return result_t::err("No possible way to resolve path " + path + " and no default resolver set"); - - result = m_defaultResolver(path); - } - - if (result.is_ok()) { - m_cachedSources[path] = result.unwrap(); - return result_t::good(&m_cachedSources[path]); - } - - return result_t::err(result.unwrap_errs()); -} - Result FileResolver::resolve(const std::string &path) { using result_t = Result; diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index d43cf2e6..f61e3fd1 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include @@ -30,6 +32,10 @@ namespace pl { if (addLibStd) lib::libstd::registerFunctions(*this); + + this->m_internals.preprocessor->setResolver(&this->m_resolvers); + + this->m_parserManager.setResolvers(&this->m_resolvers); } PatternLanguage::~PatternLanguage() { @@ -188,11 +194,10 @@ namespace pl { void PatternLanguage::setIncludePaths(const std::vector& paths) const { this->m_resolvers.setDefaultResolver(core::FileResolver { paths }); - setIncludeResolver(m_resolvers); } - void PatternLanguage::setIncludeResolver(const api::IncludeResolver &resolver) const { - this->m_internals.preprocessor->setIncludeResolver(resolver); + void PatternLanguage::setResolver(const core::Resolver& resolver) { + this->m_resolvers = resolver; } void PatternLanguage::addPragma(const std::string &name, const api::PragmaHandler &callback) const { diff --git a/tests/source/main.cpp b/tests/source/main.cpp index 5cfaa5b6..95cd69be 100644 --- a/tests/source/main.cpp +++ b/tests/source/main.cpp @@ -18,22 +18,6 @@ using namespace pl; using namespace pl::test; -struct VirtualIncludeResolver { - std::map files; - - hlp::Result operator()(const std::string &path) { - if (files.contains(path)) - return hlp::Result::good(&files[path]); - else - return hlp::Result::err( - fmt::format("File {} not found", path)); - } - - void addFile(const std::string &name, const std::string &content) { - files[name] = { content, name }; - } -}; - int runTests(int argc, char **argv) { auto &testPatterns = TestPattern::getTests(); @@ -75,28 +59,24 @@ int runTests(int argc, char **argv) { fmt::print("{}\n", message); }); - VirtualIncludeResolver resolver; - - resolver.addFile("A", R"( + runtime.addSource(R"( #include #include fn a() {}; - )"); + )", "A"); - resolver.addFile("B", R"( + runtime.addSource(R"( #include fn b() {}; - )"); + )", "B"); - resolver.addFile("C", R"( + runtime.addSource(R"( #pragma once fn c() {}; - )"); - - runtime.setIncludeResolver(resolver); + )", "C"); auto &test = testPatterns[testName];