From 51a6d74c41cebe226f21bdf158e7874e167ad3a1 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Fri, 11 Jul 2025 07:58:27 +1000 Subject: [PATCH 01/16] Add code from dev branch --- lib/include/pl/core/lexer.hpp | 42 ++- lib/include/pl/pattern_language.hpp | 119 +++--- lib/source/pl/core/lexer.cpp | 552 +++++++++++++++++----------- lib/source/pl/pattern_language.cpp | 349 ++++++++++-------- 4 files changed, 632 insertions(+), 430 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index 5d482698..e0f5c77f 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -13,19 +13,20 @@ #include -namespace pl::core { +namespace pl::core +{ - class Lexer : err::ErrorCollector { + class Lexer : err::ErrorCollector + { public: Lexer() = default; hlp::CompileResult> lex(const api::Source *source); size_t getLongestLineLength() const { return m_longestLineLength; } - private: [[nodiscard]] char peek(size_t p = 1) const; - bool processToken(auto parserFunction, const std::string_view& identifier); + bool processToken(auto parserFunction, const std::string_view &identifier); Location location() override; std::optional parseCharacter(); @@ -48,25 +49,44 @@ namespace pl::core { std::optional parseFloatingPoint(std::string_view literal, char suffix); std::optional parseInteger(std::string_view literal); - Token makeToken(const Token& token, size_t length = 1); - static Token makeTokenAt(const Token& token, Location& location, size_t length = 1); - void addToken(const Token& token); - bool hasTheLineEnded(const char &ch) { - if(ch == '\n') { + Token makeToken(const Token &token, size_t length = 1); + static Token makeTokenAt(const Token &token, Location &location, size_t length = 1); + void addToken(const Token &token); + + bool skipLineEnding() + { + char ch = m_sourceCode[m_cursor]; + if (ch == '\n') { + m_tabCompensation = 0; m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); m_line++; + m_lineBegin = ++m_cursor; + return true; + } + else if (ch == '\r') { + m_tabCompensation = 0; + m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); + m_line++; + ch = m_sourceCode[++m_cursor]; + if (ch == '\n') + ++m_cursor; m_lineBegin = m_cursor; return true; } + return false; } + + static constexpr int tabsize = 4; + std::string m_sourceCode; - const api::Source* m_source = nullptr; + const api::Source *m_source = nullptr; std::vector m_tokens; size_t m_cursor = 0; u32 m_line = 0; + u32 m_tabCompensation = 0; u32 m_lineBegin = 0; size_t m_longestLineLength = 0; - u32 m_errorLength = 0; + u32 m_errorLength; }; } \ No newline at end of file diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 44b256ad..42903e54 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -24,19 +24,25 @@ #include #include -namespace pl { +namespace pl +{ - namespace core { + namespace core + { class Preprocessor; class Lexer; class Parser; class Validator; class Evaluator; - namespace ast { class ASTNode; } + namespace ast + { + class ASTNode; + } } - namespace ptrn { + namespace ptrn + { class Pattern; class IIterable; } @@ -46,9 +52,9 @@ namespace pl { * @note The runtime can be reused for multiple executions, but if you want to execute multiple files at once, you should create a new runtime for each file * @note Things like the abort function and getter functions to check if the runtime is currently executing code are thread safe. However, the runtime is not thread safe in general */ - class PatternLanguage { + class PatternLanguage + { public: - /** * @brief Construct a new Pattern Language object * @param addLibStd Whether to add the standard library functions to the language @@ -56,26 +62,26 @@ namespace pl { explicit PatternLanguage(bool addLibStd = true); ~PatternLanguage(); - PatternLanguage(const PatternLanguage&) = delete; + PatternLanguage(const PatternLanguage &) = delete; PatternLanguage(PatternLanguage &&other) noexcept; - struct Internals { + struct Internals + { std::unique_ptr preprocessor; - std::unique_ptr lexer; - std::unique_ptr parser; - std::unique_ptr validator; - std::unique_ptr evaluator; + std::unique_ptr lexer; + std::unique_ptr parser; + std::unique_ptr validator; + std::unique_ptr evaluator; }; /** - * @brief Lexes and preprocesses a pattern language code string and returns a token stream - * @param code Code to preprocess - * @param source Source of the code - * @return token stream - */ + * @brief Lexes and preprocesses a pattern language code string and returns a token stream + * @param code Code to preprocess + * @param source Source of the code + * @return token stream + */ [[nodiscard]] std::optional> preprocessString(const std::string &code, const std::string &source); - /** * @brief Parses a pattern language code string and returns the generated AST * To get parsing errors, check PatternLanguage#getCompileErrors() after calling this method @@ -93,7 +99,7 @@ namespace pl { * @param checkResult Whether to check the result of the execution * @return True if the execution was successful, false otherwise. Call PatternLanguage#getCompileErrors() AND PatternLanguage#getEvalError() to get the compilation or runtime errors if false is returned */ - [[nodiscard]] bool executeString(std::string code, const std::string& source = api::Source::DefaultSource, const std::map &envVars = {}, const std::map &inVariables = {}, bool checkResult = true); + [[nodiscard]] bool executeString(const std::string &code, const std::string &source = api::Source::DefaultSource, const std::map &envVars = {}, const std::map &inVariables = {}, bool checkResult = true); /** * @brief Executes a pattern language file @@ -118,11 +124,11 @@ namespace pl { * @param source the source of the code * @return the source that was added or that already existed */ - [[nodiscard]] api::Source* addVirtualSource(const std::string& code, const std::string& source, bool mainSource = false) const; + [[nodiscard]] api::Source *addVirtualSource(const std::string &code, const std::string &source, bool mainSource = false) const; /** * @brief Aborts the currently running execution asynchronously - */ + */ void abort(); /** @@ -132,7 +138,7 @@ namespace pl { * @param readFunction Function to read data from the data source * @param writerFunction Optional function to write data to the data source */ - void setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writerFunction = std::nullopt); + void setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writerFunction = std::nullopt); /** * @brief Sets the base address of the data source @@ -159,7 +165,6 @@ namespace pl { void setStartAddress(u64 address); u64 getStartAddress() const; - /** * @brief Adds a new pragma preprocessor instruction * @param name Name of the pragma @@ -190,13 +195,13 @@ namespace pl { * @brief Sets the include paths for where to look for include files * @param paths List of paths to look in */ - void setIncludePaths(const std::vector& paths); + void setIncludePaths(const std::vector &paths); /** * @brief Sets the source resolver of the pattern language * @param resolver Resolver to use */ - void setResolver(const core::Resolver& resolver); + void setResolver(const core::Resolver &resolver); /** * @brief Registers a callback to be called when a dangerous function is being executed @@ -223,7 +228,7 @@ namespace pl { * @brief Gets the errors that occurred during the last compilation (e.g. parseString()) * @return A vector of errors (can be empty if no errors occurred) */ - [[nodiscard]] const std::vector& getCompileErrors() const; + [[nodiscard]] const std::vector &getCompileErrors() const; /** * @brief Gets a map of all out variables and their values that have been defined in the last execution @@ -248,13 +253,13 @@ namespace pl { * @param id ID of the section * @return Memory of the section */ - [[nodiscard]] const std::vector& getSection(u64 id) const; + [[nodiscard]] const std::vector &getSection(u64 id) const; /** * @brief Gets all custom sections that were created * @return Custom sections */ - [[nodiscard]] const std::map& getSections() const; + [[nodiscard]] const std::map &getSections() const; /** * @brief Gets all patterns that were created in the given section @@ -271,7 +276,6 @@ namespace pl { */ [[nodiscard]] std::vector getPatternsAtAddress(u64 address, u64 section = 0x00) const; - /** * @brief Get the colors of all patterns that overlap with the given address * @param address Address to check @@ -289,7 +293,8 @@ namespace pl { * @brief Checks whether the runtime is currently running * @return True if the runtime is running, false otherwise */ - [[nodiscard]] bool isRunning() const { + [[nodiscard]] bool isRunning() const + { return this->m_running; } @@ -297,7 +302,8 @@ namespace pl { * @brief Gets the time the last execution took * @return Time the last execution took */ - [[nodiscard]] double getLastRunningTime() const { + [[nodiscard]] double getLastRunningTime() const + { return this->m_runningTime; } @@ -333,19 +339,23 @@ namespace pl { * @warning Generally this should only be used by "IDEs" or other tools that need to access the internals of the pattern language * @return Internals */ - [[nodiscard]] const Internals& getInternals() const { + [[nodiscard]] const Internals &getInternals() const + { return this->m_internals; } - [[nodiscard]] const std::map& getDefines() const { + [[nodiscard]] const std::map &getDefines() const + { return this->m_defines; } - [[nodiscard]] const std::vector> getAST() const { + [[nodiscard]] const std::vector> getAST() const + { return this->m_currAST; } - [[nodiscard]] const std::map& getPragmas() const { + [[nodiscard]] const std::map &getPragmas() const + { return this->m_pragmas; } @@ -353,7 +363,8 @@ namespace pl { * @brief Gets the source resolver of the pattern language * @return Mutable reference to the Resolver */ - [[nodiscard]] core::Resolver& getResolver() { + [[nodiscard]] core::Resolver &getResolver() + { return this->m_resolvers; } @@ -361,7 +372,8 @@ namespace pl { * @brief Gets the source resolver of the pattern language * @return Resolver */ - [[nodiscard]] const core::Resolver& getResolver() const { + [[nodiscard]] const core::Resolver &getResolver() const + { return this->m_resolvers; } @@ -370,7 +382,8 @@ namespace pl { * @note This is useful for built-in functions that need to clean up their state * @param callback Callback to call */ - void addCleanupCallback(const std::function &callback) { + void addCleanupCallback(const std::function &callback) + { this->m_cleanupCallbacks.push_back(callback); } @@ -378,7 +391,8 @@ namespace pl { * @brief Checks whether the patterns are valid * @return True if the patterns are valid, false otherwise */ - [[nodiscard]] bool arePatternsValid() const { + [[nodiscard]] bool arePatternsValid() const + { return this->m_patternsValid; } @@ -386,21 +400,23 @@ namespace pl { * @brief Gets the current run id * @return Run id */ - [[nodiscard]] u64 getRunId() const { + [[nodiscard]] u64 getRunId() const + { return this->m_runId; } - [[nodiscard]] const std::atomic& getLastReadAddress() const; - [[nodiscard]] const std::atomic& getLastWriteAddress() const; - [[nodiscard]] const std::atomic& getLastPatternPlaceAddress() const; + [[nodiscard]] const std::atomic &getLastReadAddress() const; + [[nodiscard]] const std::atomic &getLastWriteAddress() const; + [[nodiscard]] const std::atomic &getLastPatternPlaceAddress() const; PatternLanguage cloneRuntime() const; - [[nodiscard]] bool isSubRuntime() const { + [[nodiscard]] bool isSubRuntime() const + { return this->m_subRuntime; } - [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string &attribute) const; + [[nodiscard]] const std::set &getPatternsWithAttribute(const std::string &attribute) const; private: void flattenPatterns(); @@ -419,15 +435,15 @@ namespace pl { std::map>> m_patterns; std::atomic m_flattenedPatternsValid = false; - std::map> m_flattenedPatterns; + std::map> m_flattenedPatterns; std::thread m_flattenThread; - std::vector> m_cleanupCallbacks; + std::vector> m_cleanupCallbacks; std::vector> m_currAST; std::atomic m_running = false; std::atomic m_patternsValid = false; std::atomic m_aborted = false; - std::atomic m_runId = 0; + std::atomic m_runId = 0; std::optional m_startAddress; std::endian m_defaultEndian = std::endian::little; @@ -435,13 +451,14 @@ namespace pl { u64 m_dataBaseAddress; u64 m_dataSize; - std::function m_dataReadFunction; - std::optional> m_dataWriteFunction; + std::function m_dataReadFunction; + std::optional> m_dataWriteFunction; std::function m_dangerousFunctionCallCallback; core::LogConsole::Callback m_logCallback; - struct Function { + struct Function + { api::Namespace nameSpace; std::string name; api::FunctionParameterCount parameterCount; diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 28625ae3..29e07145 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -5,112 +5,133 @@ #include -namespace pl::core { +namespace pl::core +{ using namespace tkn; static constexpr char integerSeparator = '\''; - static bool isIdentifierCharacter(const char c) { + static bool isIdentifierCharacter(const char c) + { return std::isalnum(c) || c == '_'; } - static bool isIntegerCharacter(const char c, const int base) { - switch (base) { - case 16: - return std::isxdigit(c); - case 10: - return std::isdigit(c); - case 8: - return c >= '0' && c <= '7'; - case 2: - return c == '0' || c == '1'; - default: - return false; + static bool isIntegerCharacter(const char c, const int base) + { + switch (base) + { + case 16: + return std::isxdigit(c); + case 10: + return std::isdigit(c); + case 8: + return c >= '0' && c <= '7'; + case 2: + return c == '0' || c == '1'; + default: + return false; } } - static int characterValue(const char c) { - if (c >= '0' && c <= '9') { + static int characterValue(const char c) + { + if (c >= '0' && c <= '9') + { return c - '0'; } - if (c >= 'a' && c <= 'f') { + if (c >= 'a' && c <= 'f') + { return c - 'a' + 10; } - if (c >= 'A' && c <= 'F') { + if (c >= 'A' && c <= 'F') + { return c - 'A' + 10; } return 0; } - static size_t getIntegerLiteralLength(const std::string_view& literal) { + static size_t getIntegerLiteralLength(const std::string_view &literal) + { const auto count = literal.find_first_not_of("0123456789ABCDEFabcdef'xXoOpP.uU+-"); const std::string_view intLiteral = count == std::string_view::npos ? literal : literal.substr(0, count); - if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos-1) != 'e' && literal.at(signPos-1) != 'E') || literal.starts_with("0x"))) + if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos - 1) != 'e' && literal.at(signPos - 1) != 'E') || literal.starts_with("0x"))) return signPos; return intLiteral.size(); } - - std::optional Lexer::parseCharacter() { - const char& c = m_sourceCode[m_cursor++]; - if (c == '\\') { - switch (m_sourceCode[m_cursor++]) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 't': - return '\t'; - case 'r': - return '\r'; - case '0': - return '\0'; - case '\'': - return '\''; - case '"': - return '"'; - case '\\': - return '\\'; - case 'x': { - const char hex[3] = { m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0 }; - m_cursor += 2; - try { - return static_cast(std::stoul(hex, nullptr, 16)); - } catch (const std::invalid_argument&) { - m_errorLength = 2; - error("Invalid hex escape sequence: {}", hex); - return std::nullopt; - } + std::optional Lexer::parseCharacter() + { + const char &c = m_sourceCode[m_cursor++]; + if (c == '\\') + { + switch (m_sourceCode[m_cursor++]) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 't': + return '\t'; + case 'r': + return '\r'; + case '0': + return '\0'; + case '\'': + return '\''; + case '"': + return '"'; + case '\\': + return '\\'; + case 'x': + { + const char hex[3] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0}; + m_cursor += 2; + try + { + return static_cast(std::stoul(hex, nullptr, 16)); } - case 'u': { - const char hex[5] = { m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], - m_sourceCode[m_cursor + 3], 0 }; - m_cursor += 4; - try { - return static_cast(std::stoul(hex, nullptr, 16)); - } catch (const std::invalid_argument&) { - m_errorLength = 4; - error("Invalid unicode escape sequence: {}", hex); - return std::nullopt; - } + catch (const std::invalid_argument &) + { + m_errorLength = 2; + error("Invalid hex escape sequence: {}", hex); + return std::nullopt; + } + } + case 'u': + { + const char hex[5] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], + m_sourceCode[m_cursor + 3], 0}; + m_cursor += 4; + try + { + return static_cast(std::stoul(hex, nullptr, 16)); + } + catch (const std::invalid_argument &) + { + m_errorLength = 4; + error("Invalid unicode escape sequence: {}", hex); + return std::nullopt; } - default: - m_errorLength = 1; - error("Unknown escape sequence: {}", m_sourceCode[m_cursor-1]); + } + default: + m_errorLength = 1; + error("Unknown escape sequence: {}", m_sourceCode[m_cursor - 1]); return std::nullopt; } } return c; } - std::optional Lexer::parseDirectiveName(const std::string_view &identifier) { + std::optional Lexer::parseDirectiveName(const std::string_view &identifier) + { const auto &directives = Token::Directives(); - if (const auto directiveToken = directives.find(identifier); directiveToken != directives.end()) { + if (const auto directiveToken = directives.find(identifier); directiveToken != directives.end()) + { return makeToken(directiveToken->second, identifier.length()); } m_errorLength = identifier.length(); @@ -118,59 +139,67 @@ namespace pl::core { return std::nullopt; } - std::optional Lexer::parseDirectiveValue() { + std::optional Lexer::parseDirectiveValue() + { std::string result; + // TODO: What if there are two spaces? Tabs? BUG! m_cursor++; // Skip space auto location = this->location(); - while (!std::isblank(m_sourceCode[m_cursor]) && !std::isspace(m_sourceCode[m_cursor]) && m_sourceCode[m_cursor] != '\0' ) { + while (!std::isblank(m_sourceCode[m_cursor]) && !std::isspace(m_sourceCode[m_cursor]) && m_sourceCode[m_cursor] != '\0') + { auto character = parseCharacter(); - if (!character.has_value()) { + if (!character.has_value()) + { return std::nullopt; } result += character.value(); } - if (hasTheLineEnded(m_sourceCode[m_cursor])) - m_cursor++; + skipLineEnding(); return makeTokenAt(Literal::makeString(result), location, result.size()); } - std::optional Lexer::parseDirectiveArgument() { + std::optional Lexer::parseDirectiveArgument() + { std::string result; m_cursor++; // Skip space auto location = this->location(); - while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { + while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') + { auto character = parseCharacter(); - if (!character.has_value()) { + if (!character.has_value()) + { return std::nullopt; } result += character.value(); } - if (hasTheLineEnded(m_sourceCode[m_cursor])) - m_cursor++; + skipLineEnding(); return makeTokenAt(Literal::makeString(result), location, result.size()); } - std::optional Lexer::parseStringLiteral() { + std::optional Lexer::parseStringLiteral() + { std::string result; auto location = this->location(); m_cursor++; // Skip opening " - while (m_sourceCode[m_cursor] != '\"') { + while (m_sourceCode[m_cursor] != '\"') + { char c = peek(0); - if (c == '\n') { + if (c == '\n') + { m_errorLength = 1; error("Unexpected newline in string literal"); m_line++; @@ -178,14 +207,16 @@ namespace pl::core { return std::nullopt; } - if (c == '\0') { + if (c == '\0') + { m_errorLength = 1; error("Unexpected end of file in string literal"); return std::nullopt; } auto character = parseCharacter(); - if (!character.has_value()) { + if (!character.has_value()) + { return std::nullopt; } @@ -197,41 +228,49 @@ namespace pl::core { return makeTokenAt(Literal::makeString(result), location, result.size() + 2); } - std::optional Lexer::parseInteger(std::string_view literal) { + std::optional Lexer::parseInteger(std::string_view literal) + { u8 base = 10; u128 value = 0; - if(literal[0] == '0') { - if(literal.size() == 1) { + if (literal[0] == '0') + { + if (literal.size() == 1) + { return 0; } bool hasPrefix = true; - switch (literal[1]) { - case 'x': - case 'X': - base = 16; + switch (literal[1]) + { + case 'x': + case 'X': + base = 16; break; - case 'o': - case 'O': - base = 8; + case 'o': + case 'O': + base = 8; break; - case 'b': - case 'B': - base = 2; + case 'b': + case 'B': + base = 2; break; - default: - hasPrefix = false; + default: + hasPrefix = false; break; } - if (hasPrefix) { + if (hasPrefix) + { literal = literal.substr(2); } } - for (const char c : literal) { - if(c == integerSeparator) continue; + for (const char c : literal) + { + if (c == integerSeparator) + continue; - if (!isIntegerCharacter(c, base)) { + if (!isIntegerCharacter(c, base)) + { m_errorLength = literal.size(); error("Invalid integer literal: {}", literal); return std::nullopt; @@ -242,39 +281,44 @@ namespace pl::core { return value; } - std::optional Lexer::parseFloatingPoint(std::string_view literal, const char suffix) { + std::optional Lexer::parseFloatingPoint(std::string_view literal, const char suffix) + { char *end = nullptr; double val = std::strtod(literal.data(), &end); - if(end != literal.data() + literal.size()) { + if (end != literal.data() + literal.size()) + { m_errorLength = literal.size(); error("Invalid float literal: {}", literal); return std::nullopt; } - switch (suffix) { - case 'f': - case 'F': - return float(val); - case 'd': - case 'D': - default: - return val; + switch (suffix) + { + case 'f': + case 'F': + return float(val); + case 'd': + case 'D': + default: + return val; } } - std::optional Lexer::parseIntegerLiteral(std::string_view literal) { + std::optional Lexer::parseIntegerLiteral(std::string_view literal) + { // parse a c like numeric literal - const bool floatSuffix = hlp::stringEndsWithOneOf(literal, { "f", "F", "d", "D" }); - const bool unsignedSuffix = hlp::stringEndsWithOneOf(literal, { "u", "U" }); - const bool isFloat = literal.find('.') != std::string_view::npos - || (!literal.starts_with("0x") && floatSuffix); + const bool floatSuffix = hlp::stringEndsWithOneOf(literal, {"f", "F", "d", "D"}); + const bool unsignedSuffix = hlp::stringEndsWithOneOf(literal, {"u", "U"}); + const bool isFloat = literal.find('.') != std::string_view::npos || (!literal.starts_with("0x") && floatSuffix); const bool isUnsigned = unsignedSuffix; - if(isFloat) { + if (isFloat) + { char suffix = 0; - if(floatSuffix) { + if (floatSuffix) + { // remove suffix suffix = literal.back(); literal = literal.substr(0, literal.size() - 1); @@ -282,82 +326,91 @@ namespace pl::core { auto floatingPoint = parseFloatingPoint(literal, suffix); - if(!floatingPoint.has_value()) return std::nullopt; + if (!floatingPoint.has_value()) + return std::nullopt; return floatingPoint.value(); - } - if(unsignedSuffix) { + if (unsignedSuffix) + { // remove suffix literal = literal.substr(0, literal.size() - 1); } const auto integer = parseInteger(literal); - if(!integer.has_value()) return std::nullopt; + if (!integer.has_value()) + return std::nullopt; u128 value = integer.value(); - if(isUnsigned) { + if (isUnsigned) + { return value; } return i128(value); } - std::optional Lexer::parseOneLineComment() { + std::optional Lexer::parseOneLineComment() + { auto location = this->location(); const auto begin = m_cursor; m_cursor += 2; std::string result; - while(m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { + while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') + { result += m_sourceCode[m_cursor]; m_cursor++; } auto len = m_cursor - begin; - if (hasTheLineEnded(m_sourceCode[m_cursor])) - m_cursor++; + skipLineEnding(); return makeTokenAt(Literal::makeComment(true, result), location, len); } - std::optional Lexer::parseOneLineDocComment() { + std::optional Lexer::parseOneLineDocComment() + { auto location = this->location(); const auto begin = m_cursor; m_cursor += 3; std::string result; - while(m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { + while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') + { result += m_sourceCode[m_cursor]; m_cursor++; } auto len = m_cursor - begin; - if (hasTheLineEnded(m_sourceCode[m_cursor])) - m_cursor++; + skipLineEnding(); return makeTokenAt(Literal::makeDocComment(false, true, result), location, len); } - std::optional Lexer::parseMultiLineDocComment() { + std::optional Lexer::parseMultiLineDocComment() + { auto location = this->location(); const auto begin = m_cursor; const bool global = peek(2) == '!'; std::string result; m_cursor += 3; - while(true) { - hasTheLineEnded(peek(0)); + while (true) + { + skipLineEnding(); - if(peek(1) == '\x00') { + if (peek(1) == '\x00') + { m_errorLength = 1; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; } - if(peek(0) == '*' && peek(1) == '/') { + if (peek(0) == '*' && peek(1) == '/') + { m_cursor += 2; break; } @@ -368,22 +421,26 @@ namespace pl::core { return makeTokenAt(Literal::makeDocComment(global, false, result), location, m_cursor - begin); } - std::optional Lexer::parseMultiLineComment() { + std::optional Lexer::parseMultiLineComment() + { auto location = this->location(); const auto begin = m_cursor; std::string result; m_cursor += 2; - while(true) { - hasTheLineEnded(peek(0)); + while (true) + { + skipLineEnding(); - if(peek(1) == '\x00') { + if (peek(1) == '\x00') + { m_errorLength = 2; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; } - if(peek(0) == '*' && peek(1) == '/') { + if (peek(0) == '*' && peek(1) == '/') + { m_cursor += 2; break; } @@ -394,15 +451,18 @@ namespace pl::core { return makeTokenAt(Literal::makeComment(false, result), location, m_cursor - begin); } - std::optional Lexer::parseOperator() { + std::optional Lexer::parseOperator() + { auto location = this->location(); const auto begin = m_cursor; const auto operators = Token::Operators(); std::optional lastMatch = std::nullopt; - for (int i = 1; i <= Operator::maxOperatorLength; ++i) { - const auto view = std::string_view { &m_sourceCode[begin], static_cast(i) }; - if (auto operatorToken = operators.find(view); operatorToken != operators.end()) { + for (int i = 1; i <= Operator::maxOperatorLength; ++i) + { + const auto view = std::string_view{&m_sourceCode[begin], static_cast(i)}; + if (auto operatorToken = operators.find(view); operatorToken != operators.end()) + { m_cursor++; lastMatch = operatorToken->second; } @@ -411,106 +471,134 @@ namespace pl::core { return lastMatch ? makeTokenAt(lastMatch.value(), location, m_cursor - begin) : lastMatch; } - std::optional Lexer::parseSeparator() { + std::optional Lexer::parseSeparator() + { auto location = this->location(); const auto begin = m_cursor; if (const auto separatorToken = Token::Separators().find(m_sourceCode[m_cursor]); - separatorToken != Token::Separators().end()) { + separatorToken != Token::Separators().end()) + { m_cursor++; return makeTokenAt(separatorToken->second, location, m_cursor - begin); - } + } return std::nullopt; } - std::optional Lexer::parseKeyword(const std::string_view &identifier) { + std::optional Lexer::parseKeyword(const std::string_view &identifier) + { const auto keywords = Token::Keywords(); - if (const auto keywordToken = keywords.find(identifier); keywordToken != keywords.end()) { + if (const auto keywordToken = keywords.find(identifier); keywordToken != keywords.end()) + { return makeToken(keywordToken->second, identifier.length()); } return std::nullopt; } - std::optional Lexer::parseType(const std::string_view &identifier) { + std::optional Lexer::parseType(const std::string_view &identifier) + { auto types = Token::Types(); - if (const auto typeToken = types.find(identifier); typeToken != types.end()) { + if (const auto typeToken = types.find(identifier); typeToken != types.end()) + { return makeToken(typeToken->second, identifier.length()); } return std::nullopt; } - std::optional Lexer::parseNamedOperator(const std::string_view &identifier) { + std::optional Lexer::parseNamedOperator(const std::string_view &identifier) + { auto operators = Token::Operators(); - if (const auto operatorToken = operators.find(identifier); operatorToken != operators.end()) { + if (const auto operatorToken = operators.find(identifier); operatorToken != operators.end()) + { return makeToken(operatorToken->second, identifier.length()); } return std::nullopt; } - std::optional Lexer::parseConstant(const std::string_view &identifier) { - if (const auto constantToken = constants.find(identifier); constantToken != constants.end()) { + std::optional Lexer::parseConstant(const std::string_view &identifier) + { + if (const auto constantToken = constants.find(identifier); constantToken != constants.end()) + { return makeToken(Literal::makeNumeric(constantToken->second), identifier.length()); } return std::nullopt; } - Token Lexer::makeToken(const Token &token, const size_t length) { + Token Lexer::makeToken(const Token &token, const size_t length) + { auto location = this->location(); location.length = length; - return { token.type, token.value, location }; + return {token.type, token.value, location}; } - Token Lexer::makeTokenAt(const Token &token, Location& location, const size_t length) { + Token Lexer::makeTokenAt(const Token &token, Location &location, const size_t length) + { location.length = length; - return { token.type, token.value, location }; + return {token.type, token.value, location}; } - void Lexer::addToken(const Token &token) { + void Lexer::addToken(const Token &token) + { m_tokens.emplace_back(token); } - hlp::CompileResult> Lexer::lex(const api::Source *source) { + hlp::CompileResult> Lexer::lex(const api::Source *source) + { this->m_sourceCode = source->content; this->m_source = source; this->m_cursor = 0; this->m_line = 1; this->m_lineBegin = 0; this->m_longestLineLength = 0; + this->m_tabCompensation = 0; const size_t end = this->m_sourceCode.size(); m_tokens.clear(); - while (this->m_cursor < end) { - const char& c = this->m_sourceCode[this->m_cursor]; + while (this->m_cursor < end) + { + const char &c = this->m_sourceCode[this->m_cursor]; - if (c == '\x00') { + if (c == '\x00') + { m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); break; // end of string } - if (std::isblank(c) || std::isspace(c)) { - hasTheLineEnded(c); - m_cursor++; + if (std::isblank(c) || std::isspace(c)) + { + if (c == '\t') + { + u32 column = m_tabCompensation + (m_cursor - m_lineBegin + 1); + u32 tabbedColumn = (((column - 1) / tabsize + 1) * tabsize) + 1; + m_tabCompensation += tabbedColumn - column - 1; + ++m_cursor; + } + else if (!skipLineEnding()) + ++m_cursor; continue; } - if(isIdentifierCharacter(c) && !std::isdigit(c)) { + if (isIdentifierCharacter(c) && !std::isdigit(c)) + { size_t length = 0; - while (isIdentifierCharacter(peek(length))) { + while (isIdentifierCharacter(peek(length))) + { length++; } - auto identifier = std::string_view { &m_sourceCode[m_cursor], length }; + auto identifier = std::string_view{&m_sourceCode[m_cursor], length}; // process keywords, named operators and types if (processToken(&Lexer::parseKeyword, identifier) || processToken(&Lexer::parseNamedOperator, identifier) || processToken(&Lexer::parseType, identifier) || - processToken(&Lexer::parseConstant, identifier)) { + processToken(&Lexer::parseConstant, identifier)) + { continue; - } + } // not a predefined token, so it must be an identifier addToken(makeToken(Literal::makeIdentifier(std::string(identifier)), length)); @@ -519,13 +607,15 @@ namespace pl::core { continue; } - if(std::isdigit(c)) { + if (std::isdigit(c)) + { auto literal = &m_sourceCode[m_cursor]; size_t size = getIntegerLiteralLength(literal); - const auto integer = parseIntegerLiteral({ literal, size }); + const auto integer = parseIntegerLiteral({literal, size}); - if(integer.has_value()) { + if (integer.has_value()) + { addToken(makeToken(Literal::makeNumeric(integer.value()), size)); this->m_cursor += size; continue; @@ -536,32 +626,42 @@ namespace pl::core { } // comment cases - if(c == '/') { + if (c == '/') + { const char category = peek(1); char type = peek(2); - if(category == '/') { - if(type == '/') { + if (category == '/') + { + if (type == '/') + { const auto token = parseOneLineDocComment(); - if(token.has_value()) { + if (token.has_value()) + { addToken(token.value()); } - } else { + } + else + { const auto token = parseOneLineComment(); - if(token.has_value()) { + if (token.has_value()) + { addToken(token.value()); } } continue; } - if(category == '*') { - if (type != '!' && (type != '*' || peek(3) == '/' )) { + if (category == '*') + { + if (type != '!' && (type != '*' || peek(3) == '/')) + { const auto token = parseMultiLineComment(); - if(token.has_value()) + if (token.has_value()) addToken(token.value()); continue; } const auto token = parseMultiLineDocComment(); - if(token.has_value()) { + if (token.has_value()) + { addToken(token.value()); } continue; @@ -569,45 +669,47 @@ namespace pl::core { } const auto operatorToken = parseOperator(); - if (operatorToken.has_value()) { + if (operatorToken.has_value()) + { addToken(operatorToken.value()); continue; } const auto separatorToken = parseSeparator(); - if (separatorToken.has_value()) { + if (separatorToken.has_value()) + { addToken(separatorToken.value()); continue; } - if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) { + if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) + { size_t length = 1; u32 line = m_line; while (isIdentifierCharacter(peek(length))) length++; auto directiveName = std::string_view{&m_sourceCode[m_cursor], length}; - if (processToken(&Lexer::parseDirectiveName, directiveName)) { + if (processToken(&Lexer::parseDirectiveName, directiveName)) + { Token::Directive directive = get(m_tokens.back().value); if (m_line != line || directive == Token::Directive::Define || directive == Token::Directive::Undef || - peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || - directive == Token::Directive::EndIf) + peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || + directive == Token::Directive::EndIf) continue; - if (hasTheLineEnded(peek(0))) { - m_cursor++; + if (skipLineEnding()) continue; - } auto directiveValue = parseDirectiveValue(); - if (directiveValue.has_value()) { + if (directiveValue.has_value()) + { addToken(directiveValue.value()); if (m_line != line || peek(0) == 0) continue; - if (hasTheLineEnded(peek(0))) { - m_cursor++; + if (skipLineEnding()) continue; - } directiveValue = parseDirectiveArgument(); - if (directiveValue.has_value()) { + if (directiveValue.has_value()) + { addToken(directiveValue.value()); } } @@ -616,21 +718,27 @@ namespace pl::core { } // literals - if (c == '"') { + if (c == '"') + { const auto string = parseStringLiteral(); - if (string.has_value()) { + if (string.has_value()) + { addToken(string.value()); continue; } - } else if(c == '\'') { + } + else if (c == '\'') + { auto location = this->location(); const auto begin = m_cursor; m_cursor++; // skip opening ' const auto character = parseCharacter(); - if (character.has_value()) { - if(m_sourceCode[m_cursor] != '\'') { + if (character.has_value()) + { + if (m_sourceCode[m_cursor] != '\'') + { m_errorLength = 1; error("Expected closing '"); continue; @@ -641,7 +749,9 @@ namespace pl::core { addToken(makeTokenAt(Literal::makeNumeric(character.value()), location, m_cursor - begin)); continue; } - } else { + } + else + { m_errorLength = 1; error("Unexpected character: {}", c); m_cursor++; @@ -654,16 +764,19 @@ namespace pl::core { m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); addToken(makeToken(Separator::EndOfProgram, 0)); - return { m_tokens, collectErrors() }; + return {m_tokens, collectErrors()}; } - inline char Lexer::peek(const size_t p) const { + inline char Lexer::peek(const size_t p) const + { return m_cursor + p < m_sourceCode.size() ? m_sourceCode[m_cursor + p] : '\0'; } - bool Lexer::processToken(auto parserFunction, const std::string_view& identifier) { + bool Lexer::processToken(auto parserFunction, const std::string_view &identifier) + { const auto token = (this->*parserFunction)(identifier); - if (token.has_value()) { + if (token.has_value()) + { m_tokens.emplace_back(token.value()); m_cursor += identifier.size(); return true; @@ -671,12 +784,9 @@ namespace pl::core { return false; } - Location Lexer::location() { - u32 column = m_cursor - m_lineBegin; - // There is no newline before the first line so add 1 to the column - if(m_line==1) { - column += 1; - } - return Location { m_source, m_line, column, m_errorLength }; + Location Lexer::location() + { + u32 column = m_tabCompensation + m_cursor - m_lineBegin + 1; + return Location{m_source, m_line, column, m_errorLength}; } } \ No newline at end of file diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index 945cf7b1..f06a6e1b 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -18,12 +18,13 @@ #include #include -namespace pl { +namespace pl +{ - static std::string getFunctionName(const api::Namespace &ns, const std::string &name) { + static std::string getFunctionName(const api::Namespace &ns, const std::string &name) + { std::string functionName; - for (auto &scope : ns) functionName += fmt::format("{}::", scope); @@ -32,14 +33,14 @@ namespace pl { return functionName; } - PatternLanguage::PatternLanguage(const bool addLibStd) { + PatternLanguage::PatternLanguage(const bool addLibStd) + { this->m_internals = { - .preprocessor = std::make_unique(), - .lexer = std::make_unique(), - .parser = std::make_unique(), - .validator = std::make_unique(), - .evaluator = std::make_unique() - }; + .preprocessor = std::make_unique(), + .lexer = std::make_unique(), + .parser = std::make_unique(), + .validator = std::make_unique(), + .evaluator = std::make_unique()}; this->m_internals.evaluator->setRuntime(this); @@ -49,7 +50,8 @@ namespace pl { this->reset(); } - PatternLanguage::~PatternLanguage() { + PatternLanguage::~PatternLanguage() + { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); this->m_patterns.clear(); @@ -57,39 +59,39 @@ namespace pl { this->m_flattenedPatternsValid = false; } - PatternLanguage::PatternLanguage(PatternLanguage &&other) noexcept { + PatternLanguage::PatternLanguage(PatternLanguage &&other) noexcept + { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); - this->m_internals = std::move(other.m_internals); - other.m_internals = { }; + this->m_internals = std::move(other.m_internals); + other.m_internals = {}; this->m_internals.evaluator->setRuntime(this); + this->m_compileErrors = std::move(other.m_compileErrors); + this->m_currError = std::move(other.m_currError); - this->m_compileErrors = std::move(other.m_compileErrors); - this->m_currError = std::move(other.m_currError); + this->m_defines = std::move(other.m_defines); + this->m_pragmas = std::move(other.m_pragmas); - this->m_defines = std::move(other.m_defines); - this->m_pragmas = std::move(other.m_pragmas); + this->m_resolvers = std::move(other.m_resolvers); + this->m_fileResolver = std::move(other.m_fileResolver); + this->m_parserManager = std::move(other.m_parserManager); - this->m_resolvers = std::move(other.m_resolvers); - this->m_fileResolver = std::move(other.m_fileResolver); - this->m_parserManager = std::move(other.m_parserManager); + this->m_patterns = std::move(other.m_patterns); + this->m_flattenedPatterns = std::move(other.m_flattenedPatterns); + this->m_cleanupCallbacks = std::move(other.m_cleanupCallbacks); + this->m_currAST = std::move(other.m_currAST); - this->m_patterns = std::move(other.m_patterns); - this->m_flattenedPatterns = std::move(other.m_flattenedPatterns); - this->m_cleanupCallbacks = std::move(other.m_cleanupCallbacks); - this->m_currAST = std::move(other.m_currAST); + this->m_dataBaseAddress = other.m_dataBaseAddress; + this->m_dataSize = other.m_dataSize; + this->m_dataReadFunction = std::move(other.m_dataReadFunction); + this->m_dataWriteFunction = std::move(other.m_dataWriteFunction); - this->m_dataBaseAddress = other.m_dataBaseAddress; - this->m_dataSize = other.m_dataSize; - this->m_dataReadFunction = std::move(other.m_dataReadFunction); - this->m_dataWriteFunction = std::move(other.m_dataWriteFunction); + this->m_logCallback = std::move(other.m_logCallback); + this->m_dangerousFunctionCallCallback = std::move(other.m_dangerousFunctionCallCallback); - this->m_logCallback = std::move(other.m_logCallback); - this->m_dangerousFunctionCallCallback = std::move(other.m_dangerousFunctionCallCallback); - - this->m_functions = std::move(other.m_functions); + this->m_functions = std::move(other.m_functions); this->m_running.exchange(other.m_running.load()); this->m_patternsValid.exchange(other.m_patternsValid.load()); @@ -97,30 +99,31 @@ namespace pl { this->m_runId.exchange(other.m_runId.load()); this->m_subRuntime = other.m_subRuntime; - m_startAddress = std::move(other.m_startAddress); + m_startAddress = std::move(other.m_startAddress); m_defaultEndian = other.m_defaultEndian; - m_runningTime = other.m_runningTime; + m_runningTime = other.m_runningTime; } - PatternLanguage PatternLanguage::cloneRuntime() const { + PatternLanguage PatternLanguage::cloneRuntime() const + { PatternLanguage runtime; - runtime.m_defines = this->m_defines; - runtime.m_pragmas = this->m_pragmas; + runtime.m_defines = this->m_defines; + runtime.m_pragmas = this->m_pragmas; - runtime.m_resolvers = this->m_resolvers; - runtime.m_fileResolver = this->m_fileResolver; + runtime.m_resolvers = this->m_resolvers; + runtime.m_fileResolver = this->m_fileResolver; runtime.m_parserManager = this->m_parserManager; - runtime.m_startAddress = this->m_startAddress; + runtime.m_startAddress = this->m_startAddress; runtime.m_defaultEndian = this->m_defaultEndian; - runtime.m_dataBaseAddress = this->m_dataBaseAddress; - runtime.m_dataSize = this->m_dataSize; - runtime.m_dataReadFunction = this->m_dataReadFunction; - runtime.m_dataWriteFunction = this->m_dataWriteFunction; + runtime.m_dataBaseAddress = this->m_dataBaseAddress; + runtime.m_dataSize = this->m_dataSize; + runtime.m_dataReadFunction = this->m_dataReadFunction; + runtime.m_dataWriteFunction = this->m_dataWriteFunction; - runtime.m_logCallback = this->m_logCallback; - runtime.m_dangerousFunctionCallCallback = this->m_dangerousFunctionCallCallback; + runtime.m_logCallback = this->m_logCallback; + runtime.m_dangerousFunctionCallCallback = this->m_dangerousFunctionCallCallback; runtime.m_functions = this->m_functions; runtime.m_subRuntime = true; @@ -128,7 +131,8 @@ namespace pl { return runtime; } - [[nodiscard]] std::optional> PatternLanguage::preprocessString(const std::string& code, const std::string& source) { + [[nodiscard]] std::optional> PatternLanguage::preprocessString(const std::string &code, const std::string &source) + { this->reset(); auto internalSource = addVirtualSource(code, source, true); // add virtual source to file resolver @@ -143,14 +147,15 @@ namespace pl { this->m_compileErrors.clear(); auto [tokens, preprocessorErrors] = this->m_internals.preprocessor->preprocess(this, internalSource, true); - if (!preprocessorErrors.empty()) + if (!preprocessorErrors.empty()) this->m_compileErrors = std::move(preprocessorErrors); if (!tokens.has_value() || tokens->empty()) return std::nullopt; return tokens; } - std::optional>> PatternLanguage::parseString(const std::string &code, const std::string &source) { + std::optional>> PatternLanguage::parseString(const std::string &code, const std::string &source) + { auto tokens = this->preprocessString(code, source); if (!tokens.has_value() || tokens->empty()) return std::nullopt; @@ -158,7 +163,8 @@ namespace pl { this->m_parserManager.setPreprocessorOnceIncluded(this->m_internals.preprocessor->getOnceIncludedFiles()); this->m_internals.parser->setParserManager(&this->m_parserManager); auto [ast, parserErrors] = this->m_internals.parser->parse(tokens.value()); - if (!parserErrors.empty()) { + if (!parserErrors.empty()) + { this->m_compileErrors.insert(m_compileErrors.end(), parserErrors.begin(), parserErrors.end()); parserErrors.clear(); } @@ -170,15 +176,14 @@ namespace pl { if (ast->empty()) return ast; - auto [validated, validatorErrors] = this->m_internals.validator->validate(ast.value()); wolv::util::unused(validated); - if (!validatorErrors.empty()) { + if (!validatorErrors.empty()) + { this->m_compileErrors.insert(m_compileErrors.end(), validatorErrors.begin(), validatorErrors.end()); validatorErrors.clear(); } - this->m_internals.preprocessor->setStoredErrors(this->m_compileErrors); if (ast->empty() || !ast.has_value()) @@ -187,16 +192,15 @@ namespace pl { return m_currAST; } - bool PatternLanguage::executeString(std::string code, const std::string& source, const std::map &envVars, const std::map &inVariables, bool checkResult) { - const auto startTime = std::chrono::high_resolution_clock::now(); - ON_SCOPE_EXIT { + bool PatternLanguage::executeString(const std::string &code, const std::string &source, const std::map &envVars, const std::map &inVariables, bool checkResult) + { + const auto startTime = std::chrono::high_resolution_clock::now(); + ON_SCOPE_EXIT + { const auto endTime = std::chrono::high_resolution_clock::now(); this->m_runningTime = std::chrono::duration_cast>(endTime - startTime).count(); }; - code = wolv::util::replaceStrings(code, "\r\n", "\n"); - code = wolv::util::replaceStrings(code, "\t", " "); - const auto &evaluator = this->m_internals.evaluator; evaluator->getConsole().setLogCallback(this->m_logCallback); @@ -206,12 +210,15 @@ namespace pl { this->m_runId += 1; ON_SCOPE_EXIT { this->m_running = false; }; - ON_SCOPE_EXIT { - for (const auto &error: this->m_compileErrors) { + ON_SCOPE_EXIT + { + for (const auto &error : this->m_compileErrors) + { evaluator->getConsole().log(core::LogConsole::Level::Error, error.format()); } - if (this->m_currError.has_value()) { + if (this->m_currError.has_value()) + { const auto &error = this->m_currError.value(); evaluator->getConsole().log(core::LogConsole::Level::Error, error.message); @@ -235,30 +242,30 @@ namespace pl { this->m_currAST = std::move(*ast); - for (const auto &[ns, name, parameterCount, callback, dangerous] : this->m_functions) { - this->m_internals.evaluator->addBuiltinFunction(getFunctionName(ns, name), parameterCount, { }, callback, dangerous); + for (const auto &[ns, name, parameterCount, callback, dangerous] : this->m_functions) + { + this->m_internals.evaluator->addBuiltinFunction(getFunctionName(ns, name), parameterCount, {}, callback, dangerous); } - std::optional> writeFunction; - if (m_dataWriteFunction.has_value()) { - writeFunction = [this](u64 address, const u8 *buffer, size_t size) { + std::optional> writeFunction; + if (m_dataWriteFunction.has_value()) + { + writeFunction = [this](u64 address, const u8 *buffer, size_t size) + { return (*this->m_dataWriteFunction)(address + this->getStartAddress(), buffer, size); }; } - evaluator->setDataSource(this->m_dataBaseAddress, this->m_dataSize, - [this](u64 address, u8 *buffer, size_t size) { - return this->m_dataReadFunction(address + this->getStartAddress(), buffer, size); - }, - writeFunction - ); + evaluator->setDataSource(this->m_dataBaseAddress, this->m_dataSize, [this](u64 address, u8 *buffer, size_t size) + { return this->m_dataReadFunction(address + this->getStartAddress(), buffer, size); }, writeFunction); evaluator->setStartAddress(this->getStartAddress()); evaluator->setReadOffset(evaluator->getDataBaseAddress()); evaluator->setDangerousFunctionCallHandler(this->m_dangerousFunctionCallCallback); bool evaluationResult = evaluator->evaluate(this->m_currAST); - if (!evaluationResult) { + if (!evaluationResult) + { auto &console = evaluator->getConsole(); this->m_currError = console.getLastHardError(); @@ -267,7 +274,8 @@ namespace pl { const auto &callStack = evaluator->getCallStack(); u32 lastLine = 0; - for (const auto &entry : callStack | std::views::reverse) { + for (const auto &entry : callStack | std::views::reverse) + { const auto &[node, address] = entry; if (node == nullptr) continue; @@ -285,14 +293,18 @@ namespace pl { console.log(core::LogConsole::Level::Error, fmt::format("Error happened with cursor at address 0x{:04X}", *cursor + m_startAddress.value_or(0x00))); console.log(core::LogConsole::Level::Error, "\n"); - } else { + } + else + { auto returnCode = evaluator->getMainResult().value_or(i128(0)).toSigned(); - if (!isSubRuntime()) { + if (!isSubRuntime()) + { evaluator->getConsole().log(core::LogConsole::Level::Info, fmt::format("Pattern exited with code: {}", i64(returnCode))); } - if (checkResult && returnCode != 0) { + if (checkResult && returnCode != 0) + { this->m_currError = core::err::PatternLanguageError(core::err::E0009.format(fmt::format("Pattern exited with non-zero result: {}", i64(returnCode))), 0, 1); evaluationResult = false; @@ -302,16 +314,20 @@ namespace pl { for (const auto &pattern : evaluator->getPatterns()) this->m_patterns[pattern->getSection()].push_back(pattern); - for (const auto &pattern : this->m_patterns[ptrn::Pattern::HeapSectionId]) { - if (pattern->hasAttribute("export")) { + for (const auto &pattern : this->m_patterns[ptrn::Pattern::HeapSectionId]) + { + if (pattern->hasAttribute("export")) + { this->m_patterns[ptrn::Pattern::MainSectionId].emplace_back(pattern); } } - - if (this->m_aborted) { + if (this->m_aborted) + { this->reset(); - } else { + } + else + { this->flattenPatterns(); this->m_patternsValid = true; } @@ -319,7 +335,8 @@ namespace pl { return evaluationResult; } - bool PatternLanguage::executeFile(const std::fs::path &path, const std::map &envVars, const std::map &inVariables, bool checkResult) { + bool PatternLanguage::executeFile(const std::fs::path &path, const std::map &envVars, const std::map &inVariables, bool checkResult) + { wolv::io::File file(path, wolv::io::File::Mode::Read); if (!file.isValid()) return false; @@ -327,120 +344,143 @@ namespace pl { return this->executeString(file.readString(), path.string(), envVars, inVariables, checkResult); } - std::pair> PatternLanguage::executeFunction(const std::string &code) { + std::pair> PatternLanguage::executeFunction(const std::string &code) + { const auto functionContent = fmt::format("fn main() {{ {0} }};", code); auto success = this->executeString(functionContent, api::Source::DefaultSource, {}, {}, false); - auto result = this->m_internals.evaluator->getMainResult(); + auto result = this->m_internals.evaluator->getMainResult(); - return { success, std::move(result) }; + return {success, std::move(result)}; } - api::Source* PatternLanguage::addVirtualSource(const std::string &code, const std::string &source, bool mainSource) const { + api::Source *PatternLanguage::addVirtualSource(const std::string &code, const std::string &source, bool mainSource) const + { return this->m_fileResolver.addVirtualFile(code, source, mainSource); } - void PatternLanguage::abort() { + void PatternLanguage::abort() + { this->m_internals.evaluator->abort(); this->m_aborted = true; } - void PatternLanguage::setIncludePaths(const std::vector& paths) { + void PatternLanguage::setIncludePaths(const std::vector &paths) + { this->m_fileResolver.setIncludePaths(paths); } - void PatternLanguage::setResolver(const core::Resolver& resolver) { + void PatternLanguage::setResolver(const core::Resolver &resolver) + { this->m_resolvers = resolver; } - void PatternLanguage::addPragma(const std::string &name, const api::PragmaHandler &callback) { + void PatternLanguage::addPragma(const std::string &name, const api::PragmaHandler &callback) + { this->m_pragmas[name] = callback; } - void PatternLanguage::removePragma(const std::string &name) { + void PatternLanguage::removePragma(const std::string &name) + { this->m_pragmas.erase(name); } - void PatternLanguage::addDefine(const std::string &name, const std::string &value) { + void PatternLanguage::addDefine(const std::string &name, const std::string &value) + { this->m_defines[name] = value; } - void PatternLanguage::removeDefine(const std::string &name) { + void PatternLanguage::removeDefine(const std::string &name) + { this->m_defines.erase(name); } - void PatternLanguage::setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writeFunction) { + void PatternLanguage::setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writeFunction) + { this->m_dataBaseAddress = baseAddress; this->m_dataSize = size; this->m_dataReadFunction = std::move(readFunction); this->m_dataWriteFunction = std::move(writeFunction); } - const std::atomic& PatternLanguage::getLastReadAddress() const { + const std::atomic &PatternLanguage::getLastReadAddress() const + { return this->m_internals.evaluator->getLastReadAddress(); } - const std::atomic& PatternLanguage::getLastWriteAddress() const { + const std::atomic &PatternLanguage::getLastWriteAddress() const + { return this->m_internals.evaluator->getLastWriteAddress(); } - const std::atomic& PatternLanguage::getLastPatternPlaceAddress() const { + const std::atomic &PatternLanguage::getLastPatternPlaceAddress() const + { return this->m_internals.evaluator->getLastPatternPlaceAddress(); } - void PatternLanguage::setDataBaseAddress(u64 baseAddress) { + void PatternLanguage::setDataBaseAddress(u64 baseAddress) + { this->m_dataBaseAddress = baseAddress; } - void PatternLanguage::setDataSize(u64 size) { + void PatternLanguage::setDataSize(u64 size) + { this->m_dataSize = size; } - void PatternLanguage::setDefaultEndian(std::endian endian) { + void PatternLanguage::setDefaultEndian(std::endian endian) + { this->m_defaultEndian = endian; } - void PatternLanguage::setStartAddress(u64 address) { + void PatternLanguage::setStartAddress(u64 address) + { this->m_startAddress = address; } - u64 PatternLanguage::getStartAddress() const { + u64 PatternLanguage::getStartAddress() const + { return this->m_startAddress.value_or(0x00); } - - void PatternLanguage::setDangerousFunctionCallHandler(std::function callback) { + void PatternLanguage::setDangerousFunctionCallHandler(std::function callback) + { this->m_dangerousFunctionCallCallback = std::move(callback); } - [[nodiscard]] std::map PatternLanguage::getOutVariables() const { + [[nodiscard]] std::map PatternLanguage::getOutVariables() const + { return this->m_internals.evaluator->getOutVariables(); } - - void PatternLanguage::setLogCallback(const core::LogConsole::Callback &callback) { + void PatternLanguage::setLogCallback(const core::LogConsole::Callback &callback) + { this->m_logCallback = callback; } - const std::optional &PatternLanguage::getEvalError() const { + const std::optional &PatternLanguage::getEvalError() const + { return this->m_currError; } - const std::vector& PatternLanguage::getCompileErrors() const { + const std::vector &PatternLanguage::getCompileErrors() const + { return this->m_compileErrors; } - - u64 PatternLanguage::getCreatedPatternCount() const { + u64 PatternLanguage::getCreatedPatternCount() const + { return this->m_internals.evaluator->getPatternCount(); } - u64 PatternLanguage::getMaximumPatternCount() const { + u64 PatternLanguage::getMaximumPatternCount() const + { return this->m_internals.evaluator->getPatternLimit(); } - const std::vector& PatternLanguage::getSection(u64 id) const { + const std::vector &PatternLanguage::getSection(u64 id) const + { static std::vector empty; if (id > this->m_internals.evaluator->getSectionCount() || id == ptrn::Pattern::MainSectionId || id == ptrn::Pattern::HeapSectionId) return empty; @@ -448,11 +488,13 @@ namespace pl { return this->m_internals.evaluator->getSection(id); } - [[nodiscard]] const std::map& PatternLanguage::getSections() const { + [[nodiscard]] const std::map &PatternLanguage::getSections() const + { return this->m_internals.evaluator->getSections(); } - [[nodiscard]] const std::vector> &PatternLanguage::getPatterns(u64 section) const { + [[nodiscard]] const std::vector> &PatternLanguage::getPatterns(u64 section) const + { static const std::vector> empty; if (this->m_patterns.contains(section)) return this->m_patterns.at(section); @@ -460,8 +502,8 @@ namespace pl { return empty; } - - void PatternLanguage::reset() { + void PatternLanguage::reset() + { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); this->m_patterns.clear(); @@ -483,11 +525,11 @@ namespace pl { this->m_internals.parser->setParserManager(&m_parserManager); this->m_patternsValid = false; - this->m_resolvers.setDefaultResolver([this](const std::string& path) { - return this->m_fileResolver.resolve(path); - }); + this->m_resolvers.setDefaultResolver([this](const std::string &path) + { return this->m_fileResolver.resolve(path); }); - auto resolver = [this](const std::string& path) { + auto resolver = [this](const std::string &path) + { return this->m_resolvers.resolve(path); }; @@ -496,59 +538,70 @@ namespace pl { this->m_parserManager.setPatternLanguage(this); } - void PatternLanguage::addFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) { + void PatternLanguage::addFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) + { this->m_functions.emplace_back(ns, name, parameterCount, func, false); } - void PatternLanguage::addDangerousFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) { + void PatternLanguage::addDangerousFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) + { this->m_functions.emplace_back(ns, name, parameterCount, func, true); } - void PatternLanguage::addType(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::TypeCallback &func) { + void PatternLanguage::addType(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::TypeCallback &func) + { this->m_parserManager.addBuiltinType(getFunctionName(ns, name), parameterCount, func); } - void PatternLanguage::flattenPatterns() { - for (const auto &[section, patterns] : this->m_patterns) { + void PatternLanguage::flattenPatterns() + { + for (const auto &[section, patterns] : this->m_patterns) + { if (this->m_aborted) return; auto §ionTree = this->m_flattenedPatterns[section]; - for (const auto &pattern : patterns) { + for (const auto &pattern : patterns) + { if (this->m_aborted) return; - if (auto staticArray = dynamic_cast(pattern.get()); staticArray != nullptr) { - if (staticArray->getEntryCount() > 0 && staticArray->getEntry(0)->getChildren().empty()) { + if (auto staticArray = dynamic_cast(pattern.get()); staticArray != nullptr) + { + if (staticArray->getEntryCount() > 0 && staticArray->getEntry(0)->getChildren().empty()) + { const auto address = staticArray->getOffset(); const auto size = staticArray->getSize(); - sectionTree.insert({ address, address + size - 1 }, staticArray); + sectionTree.insert({address, address + size - 1}, staticArray); continue; } } auto children = pattern->getChildren(); - for (const auto &[address, child] : children) { + for (const auto &[address, child] : children) + { if (this->m_aborted) return; if (child->getSize() == 0) continue; - sectionTree.insert({ address, address + child->getSize() - 1 }, child); + sectionTree.insert({address, address + child->getSize() - 1}, child); } } } } - std::vector PatternLanguage::getPatternsAtAddress(u64 address, u64 section) const { + std::vector PatternLanguage::getPatternsAtAddress(u64 address, u64 section) const + { if (this->m_flattenedPatterns.empty() || !this->m_flattenedPatterns.contains(section)) - return { }; + return {}; - auto intervals = this->m_flattenedPatterns.at(section).overlapping({ address, address }); + auto intervals = this->m_flattenedPatterns.at(section).overlapping({address, address}); - std::vector results; - std::transform(intervals.begin(), intervals.end(), std::back_inserter(results), [](const auto &interval) { + std::vector results; + std::transform(intervals.begin(), intervals.end(), std::back_inserter(results), [](const auto &interval) + { ptrn::Pattern* value = interval.value; auto parent = value->getParent(); @@ -563,20 +616,21 @@ namespace pl { value->clearFormatCache(); } - return value; - }); + return value; }); return results; } - std::vector PatternLanguage::getColorsAtAddress(u64 address, u64 section) const { + std::vector PatternLanguage::getColorsAtAddress(u64 address, u64 section) const + { if (this->m_flattenedPatterns.empty() || !this->m_flattenedPatterns.contains(section)) - return { }; + return {}; - auto intervals = this->m_flattenedPatterns.at(section).overlapping({ address, address }); + auto intervals = this->m_flattenedPatterns.at(section).overlapping({address, address}); std::vector results; - for (auto &[interval, pattern] : intervals) { + for (auto &[interval, pattern] : intervals) + { auto visibility = pattern->getVisibility(); if (visibility == pl::ptrn::Visibility::Hidden || visibility == pl::ptrn::Visibility::HighlightHidden) continue; @@ -587,7 +641,8 @@ namespace pl { return results; } - const std::set& PatternLanguage::getPatternsWithAttribute(const std::string &attribute) const { + const std::set &PatternLanguage::getPatternsWithAttribute(const std::string &attribute) const + { return m_internals.evaluator->getPatternsWithAttribute(attribute); } From f9e93042817454a97e9e6e146d3d50d4ad91c7d3 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 00:53:31 +1000 Subject: [PATCH 02/16] Fix auto code-formatter disaster --- lib/include/pl/core/lexer.hpp | 17 +- lib/include/pl/pattern_language.hpp | 107 ++++------ lib/source/pl/core/lexer.cpp | 314 ++++++++++------------------ lib/source/pl/pattern_language.cpp | 210 +++++++------------ 4 files changed, 227 insertions(+), 421 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index e0f5c77f..3fd29d95 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -13,11 +13,9 @@ #include -namespace pl::core -{ +namespace pl::core { - class Lexer : err::ErrorCollector - { + class Lexer : err::ErrorCollector { public: Lexer() = default; @@ -26,7 +24,7 @@ namespace pl::core private: [[nodiscard]] char peek(size_t p = 1) const; - bool processToken(auto parserFunction, const std::string_view &identifier); + bool processToken(auto parserFunction, const std::string_view& identifier); Location location() override; std::optional parseCharacter(); @@ -49,12 +47,11 @@ namespace pl::core std::optional parseFloatingPoint(std::string_view literal, char suffix); std::optional parseInteger(std::string_view literal); - Token makeToken(const Token &token, size_t length = 1); - static Token makeTokenAt(const Token &token, Location &location, size_t length = 1); - void addToken(const Token &token); + Token makeToken(const Token& token, size_t length = 1); + static Token makeTokenAt(const Token& token, Location &location, size_t length = 1); + void addToken(const Token& token); - bool skipLineEnding() - { + bool skipLineEnding() { char ch = m_sourceCode[m_cursor]; if (ch == '\n') { m_tabCompensation = 0; diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 42903e54..adec70c7 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -27,22 +27,17 @@ namespace pl { - namespace core - { + namespace core { class Preprocessor; class Lexer; class Parser; class Validator; class Evaluator; - namespace ast - { - class ASTNode; - } + namespace ast { class ASTNode; } } - namespace ptrn - { + namespace ptrn { class Pattern; class IIterable; } @@ -52,9 +47,9 @@ namespace pl * @note The runtime can be reused for multiple executions, but if you want to execute multiple files at once, you should create a new runtime for each file * @note Things like the abort function and getter functions to check if the runtime is currently executing code are thread safe. However, the runtime is not thread safe in general */ - class PatternLanguage - { + class PatternLanguage { public: + /** * @brief Construct a new Pattern Language object * @param addLibStd Whether to add the standard library functions to the language @@ -62,24 +57,23 @@ namespace pl explicit PatternLanguage(bool addLibStd = true); ~PatternLanguage(); - PatternLanguage(const PatternLanguage &) = delete; + PatternLanguage(const PatternLanguage&) = delete; PatternLanguage(PatternLanguage &&other) noexcept; - struct Internals - { + struct Internals { std::unique_ptr preprocessor; - std::unique_ptr lexer; - std::unique_ptr parser; - std::unique_ptr validator; - std::unique_ptr evaluator; + std::unique_ptr lexer; + std::unique_ptr parser; + std::unique_ptr validator; + std::unique_ptr evaluator; }; /** - * @brief Lexes and preprocesses a pattern language code string and returns a token stream - * @param code Code to preprocess - * @param source Source of the code - * @return token stream - */ + * @brief Lexes and preprocesses a pattern language code string and returns a token stream + * @param code Code to preprocess + * @param source Source of the code + * @return token stream + */ [[nodiscard]] std::optional> preprocessString(const std::string &code, const std::string &source); /** @@ -124,7 +118,7 @@ namespace pl * @param source the source of the code * @return the source that was added or that already existed */ - [[nodiscard]] api::Source *addVirtualSource(const std::string &code, const std::string &source, bool mainSource = false) const; + [[nodiscard]] api::Source* addVirtualSource(const std::string& code, const std::string& source, bool mainSource = false) const; /** * @brief Aborts the currently running execution asynchronously @@ -138,7 +132,7 @@ namespace pl * @param readFunction Function to read data from the data source * @param writerFunction Optional function to write data to the data source */ - void setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writerFunction = std::nullopt); + void setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writerFunction = std::nullopt); /** * @brief Sets the base address of the data source @@ -195,13 +189,13 @@ namespace pl * @brief Sets the include paths for where to look for include files * @param paths List of paths to look in */ - void setIncludePaths(const std::vector &paths); + void setIncludePaths(const std::vector& paths); /** * @brief Sets the source resolver of the pattern language * @param resolver Resolver to use */ - void setResolver(const core::Resolver &resolver); + void setResolver(const core::Resolver& resolver); /** * @brief Registers a callback to be called when a dangerous function is being executed @@ -228,7 +222,7 @@ namespace pl * @brief Gets the errors that occurred during the last compilation (e.g. parseString()) * @return A vector of errors (can be empty if no errors occurred) */ - [[nodiscard]] const std::vector &getCompileErrors() const; + [[nodiscard]] const std::vector& getCompileErrors() const; /** * @brief Gets a map of all out variables and their values that have been defined in the last execution @@ -253,13 +247,13 @@ namespace pl * @param id ID of the section * @return Memory of the section */ - [[nodiscard]] const std::vector &getSection(u64 id) const; + [[nodiscard]] const std::vector& getSection(u64 id) const; /** * @brief Gets all custom sections that were created * @return Custom sections */ - [[nodiscard]] const std::map &getSections() const; + [[nodiscard]] const std::map& getSections() const; /** * @brief Gets all patterns that were created in the given section @@ -293,8 +287,7 @@ namespace pl * @brief Checks whether the runtime is currently running * @return True if the runtime is running, false otherwise */ - [[nodiscard]] bool isRunning() const - { + [[nodiscard]] bool isRunning() const { return this->m_running; } @@ -302,8 +295,7 @@ namespace pl * @brief Gets the time the last execution took * @return Time the last execution took */ - [[nodiscard]] double getLastRunningTime() const - { + [[nodiscard]] double getLastRunningTime() const { return this->m_runningTime; } @@ -339,23 +331,21 @@ namespace pl * @warning Generally this should only be used by "IDEs" or other tools that need to access the internals of the pattern language * @return Internals */ - [[nodiscard]] const Internals &getInternals() const + [[nodiscard]] const Internals& getInternals() const { return this->m_internals; } - [[nodiscard]] const std::map &getDefines() const + [[nodiscard]] const std::map& getDefines() const { return this->m_defines; } - [[nodiscard]] const std::vector> getAST() const - { + [[nodiscard]] const std::vector> getAST() const { return this->m_currAST; } - [[nodiscard]] const std::map &getPragmas() const - { + [[nodiscard]] const std::map &getPragmas() const { return this->m_pragmas; } @@ -363,8 +353,7 @@ namespace pl * @brief Gets the source resolver of the pattern language * @return Mutable reference to the Resolver */ - [[nodiscard]] core::Resolver &getResolver() - { + [[nodiscard]] core::Resolver& getResolver() { return this->m_resolvers; } @@ -372,8 +361,7 @@ namespace pl * @brief Gets the source resolver of the pattern language * @return Resolver */ - [[nodiscard]] const core::Resolver &getResolver() const - { + [[nodiscard]] const core::Resolver& getResolver() const { return this->m_resolvers; } @@ -382,8 +370,7 @@ namespace pl * @note This is useful for built-in functions that need to clean up their state * @param callback Callback to call */ - void addCleanupCallback(const std::function &callback) - { + void addCleanupCallback(const std::function &callback) { this->m_cleanupCallbacks.push_back(callback); } @@ -391,8 +378,7 @@ namespace pl * @brief Checks whether the patterns are valid * @return True if the patterns are valid, false otherwise */ - [[nodiscard]] bool arePatternsValid() const - { + [[nodiscard]] bool arePatternsValid() const { return this->m_patternsValid; } @@ -400,23 +386,21 @@ namespace pl * @brief Gets the current run id * @return Run id */ - [[nodiscard]] u64 getRunId() const - { + [[nodiscard]] u64 getRunId() const { return this->m_runId; } - [[nodiscard]] const std::atomic &getLastReadAddress() const; - [[nodiscard]] const std::atomic &getLastWriteAddress() const; - [[nodiscard]] const std::atomic &getLastPatternPlaceAddress() const; + [[nodiscard]] const std::atomic& getLastReadAddress() const; + [[nodiscard]] const std::atomic& getLastWriteAddress() const; + [[nodiscard]] const std::atomic& getLastPatternPlaceAddress() const; PatternLanguage cloneRuntime() const; - [[nodiscard]] bool isSubRuntime() const - { + [[nodiscard]] bool isSubRuntime() const { return this->m_subRuntime; } - [[nodiscard]] const std::set &getPatternsWithAttribute(const std::string &attribute) const; + [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string &attribute) const; private: void flattenPatterns(); @@ -435,15 +419,15 @@ namespace pl std::map>> m_patterns; std::atomic m_flattenedPatternsValid = false; - std::map> m_flattenedPatterns; + std::map> m_flattenedPatterns; std::thread m_flattenThread; - std::vector> m_cleanupCallbacks; + std::vector> m_cleanupCallbacks; std::vector> m_currAST; std::atomic m_running = false; std::atomic m_patternsValid = false; std::atomic m_aborted = false; - std::atomic m_runId = 0; + std::atomic m_runId = 0; std::optional m_startAddress; std::endian m_defaultEndian = std::endian::little; @@ -451,14 +435,13 @@ namespace pl u64 m_dataBaseAddress; u64 m_dataSize; - std::function m_dataReadFunction; - std::optional> m_dataWriteFunction; + std::function m_dataReadFunction; + std::optional> m_dataWriteFunction; std::function m_dangerousFunctionCallCallback; core::LogConsole::Callback m_logCallback; - struct Function - { + struct Function { api::Namespace nameSpace; std::string name; api::FunctionParameterCount parameterCount; diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 29e07145..7ab392c6 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -11,13 +11,11 @@ namespace pl::core static constexpr char integerSeparator = '\''; - static bool isIdentifierCharacter(const char c) - { + static bool isIdentifierCharacter(const char c) { return std::isalnum(c) || c == '_'; } - static bool isIntegerCharacter(const char c, const int base) - { + static bool isIntegerCharacter(const char c, const int base) { switch (base) { case 16: @@ -33,40 +31,32 @@ namespace pl::core } } - static int characterValue(const char c) - { - if (c >= '0' && c <= '9') - { + static int characterValue(const char c) { + if (c >= '0' && c <= '9') { return c - '0'; } - if (c >= 'a' && c <= 'f') - { + if (c >= 'a' && c <= 'f') { return c - 'a' + 10; } - if (c >= 'A' && c <= 'F') - { + if (c >= 'A' && c <= 'F') { return c - 'A' + 10; } return 0; } - static size_t getIntegerLiteralLength(const std::string_view &literal) - { + static size_t getIntegerLiteralLength(const std::string_view &literal) { const auto count = literal.find_first_not_of("0123456789ABCDEFabcdef'xXoOpP.uU+-"); const std::string_view intLiteral = count == std::string_view::npos ? literal : literal.substr(0, count); - if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos - 1) != 'e' && literal.at(signPos - 1) != 'E') || literal.starts_with("0x"))) + if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos-1) != 'e' && literal.at(signPos-1) != 'E') || literal.starts_with("0x"))) return signPos; return intLiteral.size(); } - std::optional Lexer::parseCharacter() - { + std::optional Lexer::parseCharacter() { const char &c = m_sourceCode[m_cursor++]; - if (c == '\\') - { - switch (m_sourceCode[m_cursor++]) - { + if (c == '\\') { + switch (m_sourceCode[m_cursor++]) { case 'a': return '\a'; case 'b': @@ -87,32 +77,26 @@ namespace pl::core return '"'; case '\\': return '\\'; - case 'x': - { + case 'x': { const char hex[3] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0}; m_cursor += 2; - try - { + try { return static_cast(std::stoul(hex, nullptr, 16)); } - catch (const std::invalid_argument &) - { + catch (const std::invalid_argument&) { m_errorLength = 2; error("Invalid hex escape sequence: {}", hex); return std::nullopt; } } - case 'u': - { + case 'u': { const char hex[5] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], m_sourceCode[m_cursor + 3], 0}; m_cursor += 4; - try - { + try { return static_cast(std::stoul(hex, nullptr, 16)); } - catch (const std::invalid_argument &) - { + catch (const std::invalid_argument &) { m_errorLength = 4; error("Invalid unicode escape sequence: {}", hex); return std::nullopt; @@ -127,11 +111,9 @@ namespace pl::core return c; } - std::optional Lexer::parseDirectiveName(const std::string_view &identifier) - { + std::optional Lexer::parseDirectiveName(const std::string_view &identifier) { const auto &directives = Token::Directives(); - if (const auto directiveToken = directives.find(identifier); directiveToken != directives.end()) - { + if (const auto directiveToken = directives.find(identifier); directiveToken != directives.end()) { return makeToken(directiveToken->second, identifier.length()); } m_errorLength = identifier.length(); @@ -139,20 +121,17 @@ namespace pl::core return std::nullopt; } - std::optional Lexer::parseDirectiveValue() - { + std::optional Lexer::parseDirectiveValue() { std::string result; // TODO: What if there are two spaces? Tabs? BUG! m_cursor++; // Skip space auto location = this->location(); - while (!std::isblank(m_sourceCode[m_cursor]) && !std::isspace(m_sourceCode[m_cursor]) && m_sourceCode[m_cursor] != '\0') - { + while (!std::isblank(m_sourceCode[m_cursor]) && !std::isspace(m_sourceCode[m_cursor]) && m_sourceCode[m_cursor] != '\0') { auto character = parseCharacter(); - if (!character.has_value()) - { + if (!character.has_value()) { return std::nullopt; } @@ -164,19 +143,16 @@ namespace pl::core return makeTokenAt(Literal::makeString(result), location, result.size()); } - std::optional Lexer::parseDirectiveArgument() - { + std::optional Lexer::parseDirectiveArgument() { std::string result; m_cursor++; // Skip space auto location = this->location(); - while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') - { + while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { auto character = parseCharacter(); - if (!character.has_value()) - { + if (!character.has_value()) { return std::nullopt; } @@ -188,18 +164,15 @@ namespace pl::core return makeTokenAt(Literal::makeString(result), location, result.size()); } - std::optional Lexer::parseStringLiteral() - { + std::optional Lexer::parseStringLiteral() { std::string result; auto location = this->location(); m_cursor++; // Skip opening " - while (m_sourceCode[m_cursor] != '\"') - { + while (m_sourceCode[m_cursor] != '\"') { char c = peek(0); - if (c == '\n') - { + if (c == '\n') { m_errorLength = 1; error("Unexpected newline in string literal"); m_line++; @@ -207,16 +180,14 @@ namespace pl::core return std::nullopt; } - if (c == '\0') - { + if (c == '\0') { m_errorLength = 1; error("Unexpected end of file in string literal"); return std::nullopt; } auto character = parseCharacter(); - if (!character.has_value()) - { + if (!character.has_value()) { return std::nullopt; } @@ -228,20 +199,16 @@ namespace pl::core return makeTokenAt(Literal::makeString(result), location, result.size() + 2); } - std::optional Lexer::parseInteger(std::string_view literal) - { + std::optional Lexer::parseInteger(std::string_view literal) { u8 base = 10; u128 value = 0; - if (literal[0] == '0') - { - if (literal.size() == 1) - { + if (literal[0] == '0') { + if (literal.size() == 1) { return 0; } bool hasPrefix = true; - switch (literal[1]) - { + switch (literal[1]) { case 'x': case 'X': base = 16; @@ -258,19 +225,16 @@ namespace pl::core hasPrefix = false; break; } - if (hasPrefix) - { + if (hasPrefix) { literal = literal.substr(2); } } - for (const char c : literal) - { + for (const char c : literal) { if (c == integerSeparator) continue; - if (!isIntegerCharacter(c, base)) - { + if (!isIntegerCharacter(c, base)) { m_errorLength = literal.size(); error("Invalid integer literal: {}", literal); return std::nullopt; @@ -281,13 +245,11 @@ namespace pl::core return value; } - std::optional Lexer::parseFloatingPoint(std::string_view literal, const char suffix) - { + std::optional Lexer::parseFloatingPoint(std::string_view literal, const char suffix) { char *end = nullptr; double val = std::strtod(literal.data(), &end); - if (end != literal.data() + literal.size()) - { + if (end != literal.data() + literal.size()) { m_errorLength = literal.size(); error("Invalid float literal: {}", literal); return std::nullopt; @@ -305,20 +267,17 @@ namespace pl::core } } - std::optional Lexer::parseIntegerLiteral(std::string_view literal) - { + std::optional Lexer::parseIntegerLiteral(std::string_view literal) { // parse a c like numeric literal const bool floatSuffix = hlp::stringEndsWithOneOf(literal, {"f", "F", "d", "D"}); const bool unsignedSuffix = hlp::stringEndsWithOneOf(literal, {"u", "U"}); const bool isFloat = literal.find('.') != std::string_view::npos || (!literal.starts_with("0x") && floatSuffix); const bool isUnsigned = unsignedSuffix; - if (isFloat) - { + if (isFloat) { char suffix = 0; - if (floatSuffix) - { + if (floatSuffix) { // remove suffix suffix = literal.back(); literal = literal.substr(0, literal.size() - 1); @@ -332,8 +291,7 @@ namespace pl::core return floatingPoint.value(); } - if (unsignedSuffix) - { + if (unsignedSuffix) { // remove suffix literal = literal.substr(0, literal.size() - 1); } @@ -344,23 +302,20 @@ namespace pl::core return std::nullopt; u128 value = integer.value(); - if (isUnsigned) - { + if (isUnsigned) { return value; } return i128(value); } - std::optional Lexer::parseOneLineComment() - { + std::optional Lexer::parseOneLineComment() { auto location = this->location(); const auto begin = m_cursor; m_cursor += 2; std::string result; - while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') - { + while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { result += m_sourceCode[m_cursor]; m_cursor++; } @@ -371,15 +326,13 @@ namespace pl::core return makeTokenAt(Literal::makeComment(true, result), location, len); } - std::optional Lexer::parseOneLineDocComment() - { + std::optional Lexer::parseOneLineDocComment() { auto location = this->location(); const auto begin = m_cursor; m_cursor += 3; std::string result; - while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') - { + while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { result += m_sourceCode[m_cursor]; m_cursor++; } @@ -390,27 +343,23 @@ namespace pl::core return makeTokenAt(Literal::makeDocComment(false, true, result), location, len); } - std::optional Lexer::parseMultiLineDocComment() - { + std::optional Lexer::parseMultiLineDocComment() { auto location = this->location(); const auto begin = m_cursor; const bool global = peek(2) == '!'; std::string result; m_cursor += 3; - while (true) - { + while (true) { skipLineEnding(); - if (peek(1) == '\x00') - { + if (peek(1) == '\x00') { m_errorLength = 1; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; } - if (peek(0) == '*' && peek(1) == '/') - { + if (peek(0) == '*' && peek(1) == '/') { m_cursor += 2; break; } @@ -421,26 +370,22 @@ namespace pl::core return makeTokenAt(Literal::makeDocComment(global, false, result), location, m_cursor - begin); } - std::optional Lexer::parseMultiLineComment() - { + std::optional Lexer::parseMultiLineComment() { auto location = this->location(); const auto begin = m_cursor; std::string result; m_cursor += 2; - while (true) - { + while (true) { skipLineEnding(); - if (peek(1) == '\x00') - { + if (peek(1) == '\x00') { m_errorLength = 2; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; } - if (peek(0) == '*' && peek(1) == '/') - { + if (peek(0) == '*' && peek(1) == '/') { m_cursor += 2; break; } @@ -451,18 +396,15 @@ namespace pl::core return makeTokenAt(Literal::makeComment(false, result), location, m_cursor - begin); } - std::optional Lexer::parseOperator() - { + std::optional Lexer::parseOperator() { auto location = this->location(); const auto begin = m_cursor; const auto operators = Token::Operators(); std::optional lastMatch = std::nullopt; - for (int i = 1; i <= Operator::maxOperatorLength; ++i) - { + for (int i = 1; i <= Operator::maxOperatorLength; ++i) { const auto view = std::string_view{&m_sourceCode[begin], static_cast(i)}; - if (auto operatorToken = operators.find(view); operatorToken != operators.end()) - { + if (auto operatorToken = operators.find(view); operatorToken != operators.end()) { m_cursor++; lastMatch = operatorToken->second; } @@ -471,14 +413,12 @@ namespace pl::core return lastMatch ? makeTokenAt(lastMatch.value(), location, m_cursor - begin) : lastMatch; } - std::optional Lexer::parseSeparator() - { + std::optional Lexer::parseSeparator() { auto location = this->location(); const auto begin = m_cursor; if (const auto separatorToken = Token::Separators().find(m_sourceCode[m_cursor]); - separatorToken != Token::Separators().end()) - { + separatorToken != Token::Separators().end()) { m_cursor++; return makeTokenAt(separatorToken->second, location, m_cursor - begin); } @@ -486,65 +426,53 @@ namespace pl::core return std::nullopt; } - std::optional Lexer::parseKeyword(const std::string_view &identifier) - { + std::optional Lexer::parseKeyword(const std::string_view &identifier) { const auto keywords = Token::Keywords(); - if (const auto keywordToken = keywords.find(identifier); keywordToken != keywords.end()) - { + if (const auto keywordToken = keywords.find(identifier); keywordToken != keywords.end()) { return makeToken(keywordToken->second, identifier.length()); } return std::nullopt; } - std::optional Lexer::parseType(const std::string_view &identifier) - { + std::optional Lexer::parseType(const std::string_view &identifier) { auto types = Token::Types(); - if (const auto typeToken = types.find(identifier); typeToken != types.end()) - { + if (const auto typeToken = types.find(identifier); typeToken != types.end()) { return makeToken(typeToken->second, identifier.length()); } return std::nullopt; } - std::optional Lexer::parseNamedOperator(const std::string_view &identifier) - { + std::optional Lexer::parseNamedOperator(const std::string_view &identifier) { auto operators = Token::Operators(); - if (const auto operatorToken = operators.find(identifier); operatorToken != operators.end()) - { + if (const auto operatorToken = operators.find(identifier); operatorToken != operators.end()) { return makeToken(operatorToken->second, identifier.length()); } return std::nullopt; } - std::optional Lexer::parseConstant(const std::string_view &identifier) - { - if (const auto constantToken = constants.find(identifier); constantToken != constants.end()) - { + std::optional Lexer::parseConstant(const std::string_view &identifier) { + if (const auto constantToken = constants.find(identifier); constantToken != constants.end()) { return makeToken(Literal::makeNumeric(constantToken->second), identifier.length()); } return std::nullopt; } - Token Lexer::makeToken(const Token &token, const size_t length) - { + Token Lexer::makeToken(const Token &token, const size_t length) { auto location = this->location(); location.length = length; return {token.type, token.value, location}; } - Token Lexer::makeTokenAt(const Token &token, Location &location, const size_t length) - { + Token Lexer::makeTokenAt(const Token &token, Location &location, const size_t length) { location.length = length; return {token.type, token.value, location}; } - void Lexer::addToken(const Token &token) - { + void Lexer::addToken(const Token &token) { m_tokens.emplace_back(token); } - hlp::CompileResult> Lexer::lex(const api::Source *source) - { + hlp::CompileResult> Lexer::lex(const api::Source *source) { this->m_sourceCode = source->content; this->m_source = source; this->m_cursor = 0; @@ -557,20 +485,16 @@ namespace pl::core m_tokens.clear(); - while (this->m_cursor < end) - { + while (this->m_cursor < end) { const char &c = this->m_sourceCode[this->m_cursor]; - if (c == '\x00') - { + if (c == '\x00') { m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); break; // end of string } - if (std::isblank(c) || std::isspace(c)) - { - if (c == '\t') - { + if (std::isblank(c) || std::isspace(c)) { + if (c == '\t') { u32 column = m_tabCompensation + (m_cursor - m_lineBegin + 1); u32 tabbedColumn = (((column - 1) / tabsize + 1) * tabsize) + 1; m_tabCompensation += tabbedColumn - column - 1; @@ -581,11 +505,9 @@ namespace pl::core continue; } - if (isIdentifierCharacter(c) && !std::isdigit(c)) - { + if (isIdentifierCharacter(c) && !std::isdigit(c)) { size_t length = 0; - while (isIdentifierCharacter(peek(length))) - { + while (isIdentifierCharacter(peek(length))) { length++; } @@ -607,15 +529,13 @@ namespace pl::core continue; } - if (std::isdigit(c)) - { + if (std::isdigit(c)) { auto literal = &m_sourceCode[m_cursor]; size_t size = getIntegerLiteralLength(literal); const auto integer = parseIntegerLiteral({literal, size}); - if (integer.has_value()) - { + if (integer.has_value()) { addToken(makeToken(Literal::makeNumeric(integer.value()), size)); this->m_cursor += size; continue; @@ -626,42 +546,33 @@ namespace pl::core } // comment cases - if (c == '/') - { + if (c == '/') { const char category = peek(1); char type = peek(2); - if (category == '/') - { - if (type == '/') - { + if (category == '/') { + if (type == '/') { const auto token = parseOneLineDocComment(); - if (token.has_value()) - { + if (token.has_value()) { addToken(token.value()); } } - else - { + else { const auto token = parseOneLineComment(); - if (token.has_value()) - { + if (token.has_value()) { addToken(token.value()); } } continue; } - if (category == '*') - { - if (type != '!' && (type != '*' || peek(3) == '/')) - { + if (category == '*') { + if (type != '!' && (type != '*' || peek(3) == '/')) { const auto token = parseMultiLineComment(); if (token.has_value()) addToken(token.value()); continue; } const auto token = parseMultiLineDocComment(); - if (token.has_value()) - { + if (token.has_value()) { addToken(token.value()); } continue; @@ -669,29 +580,25 @@ namespace pl::core } const auto operatorToken = parseOperator(); - if (operatorToken.has_value()) - { + if (operatorToken.has_value()) { addToken(operatorToken.value()); continue; } const auto separatorToken = parseSeparator(); - if (separatorToken.has_value()) - { + if (separatorToken.has_value()) { addToken(separatorToken.value()); continue; } - if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) - { + if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) { size_t length = 1; u32 line = m_line; while (isIdentifierCharacter(peek(length))) length++; auto directiveName = std::string_view{&m_sourceCode[m_cursor], length}; - if (processToken(&Lexer::parseDirectiveName, directiveName)) - { + if (processToken(&Lexer::parseDirectiveName, directiveName)) { Token::Directive directive = get(m_tokens.back().value); if (m_line != line || directive == Token::Directive::Define || directive == Token::Directive::Undef || peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || @@ -700,16 +607,14 @@ namespace pl::core if (skipLineEnding()) continue; auto directiveValue = parseDirectiveValue(); - if (directiveValue.has_value()) - { + if (directiveValue.has_value()) { addToken(directiveValue.value()); if (m_line != line || peek(0) == 0) continue; if (skipLineEnding()) continue; directiveValue = parseDirectiveArgument(); - if (directiveValue.has_value()) - { + if (directiveValue.has_value()) { addToken(directiveValue.value()); } } @@ -718,27 +623,22 @@ namespace pl::core } // literals - if (c == '"') - { + if (c == '"') { const auto string = parseStringLiteral(); - if (string.has_value()) - { + if (string.has_value()) { addToken(string.value()); continue; } } - else if (c == '\'') - { + else if (c == '\'') { auto location = this->location(); const auto begin = m_cursor; m_cursor++; // skip opening ' const auto character = parseCharacter(); - if (character.has_value()) - { - if (m_sourceCode[m_cursor] != '\'') - { + if (character.has_value()) { + if (m_sourceCode[m_cursor] != '\'') { m_errorLength = 1; error("Expected closing '"); continue; @@ -750,8 +650,7 @@ namespace pl::core continue; } } - else - { + else { m_errorLength = 1; error("Unexpected character: {}", c); m_cursor++; @@ -767,16 +666,13 @@ namespace pl::core return {m_tokens, collectErrors()}; } - inline char Lexer::peek(const size_t p) const - { + inline char Lexer::peek(const size_t p) const { return m_cursor + p < m_sourceCode.size() ? m_sourceCode[m_cursor + p] : '\0'; } - bool Lexer::processToken(auto parserFunction, const std::string_view &identifier) - { + bool Lexer::processToken(auto parserFunction, const std::string_view &identifier) { const auto token = (this->*parserFunction)(identifier); - if (token.has_value()) - { + if (token.has_value()) { m_tokens.emplace_back(token.value()); m_cursor += identifier.size(); return true; diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index f06a6e1b..8ffacf3a 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -18,11 +18,9 @@ #include #include -namespace pl -{ +namespace pl { - static std::string getFunctionName(const api::Namespace &ns, const std::string &name) - { + static std::string getFunctionName(const api::Namespace &ns, const std::string &name) { std::string functionName; for (auto &scope : ns) @@ -33,8 +31,7 @@ namespace pl return functionName; } - PatternLanguage::PatternLanguage(const bool addLibStd) - { + PatternLanguage::PatternLanguage(const bool addLibStd) { this->m_internals = { .preprocessor = std::make_unique(), .lexer = std::make_unique(), @@ -50,8 +47,7 @@ namespace pl this->reset(); } - PatternLanguage::~PatternLanguage() - { + PatternLanguage::~PatternLanguage() { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); this->m_patterns.clear(); @@ -59,8 +55,7 @@ namespace pl this->m_flattenedPatternsValid = false; } - PatternLanguage::PatternLanguage(PatternLanguage &&other) noexcept - { + PatternLanguage::PatternLanguage(PatternLanguage &&other) noexcept { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); @@ -104,8 +99,7 @@ namespace pl m_runningTime = other.m_runningTime; } - PatternLanguage PatternLanguage::cloneRuntime() const - { + PatternLanguage PatternLanguage::cloneRuntime() const { PatternLanguage runtime; runtime.m_defines = this->m_defines; runtime.m_pragmas = this->m_pragmas; @@ -131,8 +125,7 @@ namespace pl return runtime; } - [[nodiscard]] std::optional> PatternLanguage::preprocessString(const std::string &code, const std::string &source) - { + [[nodiscard]] std::optional> PatternLanguage::preprocessString(const std::string &code, const std::string &source) { this->reset(); auto internalSource = addVirtualSource(code, source, true); // add virtual source to file resolver @@ -154,8 +147,7 @@ namespace pl return tokens; } - std::optional>> PatternLanguage::parseString(const std::string &code, const std::string &source) - { + std::optional>> PatternLanguage::parseString(const std::string &code, const std::string &source) { auto tokens = this->preprocessString(code, source); if (!tokens.has_value() || tokens->empty()) return std::nullopt; @@ -163,8 +155,7 @@ namespace pl this->m_parserManager.setPreprocessorOnceIncluded(this->m_internals.preprocessor->getOnceIncludedFiles()); this->m_internals.parser->setParserManager(&this->m_parserManager); auto [ast, parserErrors] = this->m_internals.parser->parse(tokens.value()); - if (!parserErrors.empty()) - { + if (!parserErrors.empty()) { this->m_compileErrors.insert(m_compileErrors.end(), parserErrors.begin(), parserErrors.end()); parserErrors.clear(); } @@ -178,8 +169,7 @@ namespace pl auto [validated, validatorErrors] = this->m_internals.validator->validate(ast.value()); wolv::util::unused(validated); - if (!validatorErrors.empty()) - { + if (!validatorErrors.empty()) { this->m_compileErrors.insert(m_compileErrors.end(), validatorErrors.begin(), validatorErrors.end()); validatorErrors.clear(); } @@ -192,11 +182,9 @@ namespace pl return m_currAST; } - bool PatternLanguage::executeString(const std::string &code, const std::string &source, const std::map &envVars, const std::map &inVariables, bool checkResult) - { + bool PatternLanguage::executeString(const std::string &code, const std::string &source, const std::map &envVars, const std::map &inVariables, bool checkResult) { const auto startTime = std::chrono::high_resolution_clock::now(); - ON_SCOPE_EXIT - { + ON_SCOPE_EXIT { const auto endTime = std::chrono::high_resolution_clock::now(); this->m_runningTime = std::chrono::duration_cast>(endTime - startTime).count(); }; @@ -210,15 +198,12 @@ namespace pl this->m_runId += 1; ON_SCOPE_EXIT { this->m_running = false; }; - ON_SCOPE_EXIT - { - for (const auto &error : this->m_compileErrors) - { + ON_SCOPE_EXIT { + for (const auto &error : this->m_compileErrors) { evaluator->getConsole().log(core::LogConsole::Level::Error, error.format()); } - if (this->m_currError.has_value()) - { + if (this->m_currError.has_value()) { const auto &error = this->m_currError.value(); evaluator->getConsole().log(core::LogConsole::Level::Error, error.message); @@ -242,16 +227,13 @@ namespace pl this->m_currAST = std::move(*ast); - for (const auto &[ns, name, parameterCount, callback, dangerous] : this->m_functions) - { + for (const auto &[ns, name, parameterCount, callback, dangerous] : this->m_functions) { this->m_internals.evaluator->addBuiltinFunction(getFunctionName(ns, name), parameterCount, {}, callback, dangerous); } std::optional> writeFunction; - if (m_dataWriteFunction.has_value()) - { - writeFunction = [this](u64 address, const u8 *buffer, size_t size) - { + if (m_dataWriteFunction.has_value()) { + writeFunction = [this](u64 address, const u8 *buffer, size_t size) { return (*this->m_dataWriteFunction)(address + this->getStartAddress(), buffer, size); }; } @@ -264,8 +246,7 @@ namespace pl evaluator->setDangerousFunctionCallHandler(this->m_dangerousFunctionCallCallback); bool evaluationResult = evaluator->evaluate(this->m_currAST); - if (!evaluationResult) - { + if (!evaluationResult) { auto &console = evaluator->getConsole(); this->m_currError = console.getLastHardError(); @@ -274,8 +255,7 @@ namespace pl const auto &callStack = evaluator->getCallStack(); u32 lastLine = 0; - for (const auto &entry : callStack | std::views::reverse) - { + for (const auto &entry : callStack | std::views::reverse) { const auto &[node, address] = entry; if (node == nullptr) continue; @@ -294,17 +274,14 @@ namespace pl console.log(core::LogConsole::Level::Error, "\n"); } - else - { + else { auto returnCode = evaluator->getMainResult().value_or(i128(0)).toSigned(); - if (!isSubRuntime()) - { + if (!isSubRuntime()) { evaluator->getConsole().log(core::LogConsole::Level::Info, fmt::format("Pattern exited with code: {}", i64(returnCode))); } - if (checkResult && returnCode != 0) - { + if (checkResult && returnCode != 0) { this->m_currError = core::err::PatternLanguageError(core::err::E0009.format(fmt::format("Pattern exited with non-zero result: {}", i64(returnCode))), 0, 1); evaluationResult = false; @@ -314,20 +291,16 @@ namespace pl for (const auto &pattern : evaluator->getPatterns()) this->m_patterns[pattern->getSection()].push_back(pattern); - for (const auto &pattern : this->m_patterns[ptrn::Pattern::HeapSectionId]) - { - if (pattern->hasAttribute("export")) - { + for (const auto &pattern : this->m_patterns[ptrn::Pattern::HeapSectionId]) { + if (pattern->hasAttribute("export")) { this->m_patterns[ptrn::Pattern::MainSectionId].emplace_back(pattern); } } - if (this->m_aborted) - { + if (this->m_aborted) { this->reset(); } - else - { + else { this->flattenPatterns(); this->m_patternsValid = true; } @@ -335,8 +308,7 @@ namespace pl return evaluationResult; } - bool PatternLanguage::executeFile(const std::fs::path &path, const std::map &envVars, const std::map &inVariables, bool checkResult) - { + bool PatternLanguage::executeFile(const std::fs::path &path, const std::map &envVars, const std::map &inVariables, bool checkResult) { wolv::io::File file(path, wolv::io::File::Mode::Read); if (!file.isValid()) return false; @@ -344,8 +316,7 @@ namespace pl return this->executeString(file.readString(), path.string(), envVars, inVariables, checkResult); } - std::pair> PatternLanguage::executeFunction(const std::string &code) - { + std::pair> PatternLanguage::executeFunction(const std::string &code) { const auto functionContent = fmt::format("fn main() {{ {0} }};", code); @@ -355,132 +326,107 @@ namespace pl return {success, std::move(result)}; } - api::Source *PatternLanguage::addVirtualSource(const std::string &code, const std::string &source, bool mainSource) const - { + api::Source *PatternLanguage::addVirtualSource(const std::string &code, const std::string &source, bool mainSource) const { return this->m_fileResolver.addVirtualFile(code, source, mainSource); } - void PatternLanguage::abort() - { + void PatternLanguage::abort() { this->m_internals.evaluator->abort(); this->m_aborted = true; } - void PatternLanguage::setIncludePaths(const std::vector &paths) - { + void PatternLanguage::setIncludePaths(const std::vector &paths) { this->m_fileResolver.setIncludePaths(paths); } - void PatternLanguage::setResolver(const core::Resolver &resolver) - { + void PatternLanguage::setResolver(const core::Resolver &resolver) { this->m_resolvers = resolver; } - void PatternLanguage::addPragma(const std::string &name, const api::PragmaHandler &callback) - { + void PatternLanguage::addPragma(const std::string &name, const api::PragmaHandler &callback) { this->m_pragmas[name] = callback; } - void PatternLanguage::removePragma(const std::string &name) - { + void PatternLanguage::removePragma(const std::string &name) { this->m_pragmas.erase(name); } - void PatternLanguage::addDefine(const std::string &name, const std::string &value) - { + void PatternLanguage::addDefine(const std::string &name, const std::string &value) { this->m_defines[name] = value; } - void PatternLanguage::removeDefine(const std::string &name) - { + void PatternLanguage::removeDefine(const std::string &name) { this->m_defines.erase(name); } - void PatternLanguage::setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writeFunction) - { + void PatternLanguage::setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writeFunction) { this->m_dataBaseAddress = baseAddress; this->m_dataSize = size; this->m_dataReadFunction = std::move(readFunction); this->m_dataWriteFunction = std::move(writeFunction); } - const std::atomic &PatternLanguage::getLastReadAddress() const - { + const std::atomic &PatternLanguage::getLastReadAddress() const { return this->m_internals.evaluator->getLastReadAddress(); } - const std::atomic &PatternLanguage::getLastWriteAddress() const - { + const std::atomic &PatternLanguage::getLastWriteAddress() const { return this->m_internals.evaluator->getLastWriteAddress(); } - const std::atomic &PatternLanguage::getLastPatternPlaceAddress() const - { + const std::atomic &PatternLanguage::getLastPatternPlaceAddress() const { return this->m_internals.evaluator->getLastPatternPlaceAddress(); } - void PatternLanguage::setDataBaseAddress(u64 baseAddress) - { + void PatternLanguage::setDataBaseAddress(u64 baseAddress) { this->m_dataBaseAddress = baseAddress; } - void PatternLanguage::setDataSize(u64 size) - { + void PatternLanguage::setDataSize(u64 size) { this->m_dataSize = size; } - void PatternLanguage::setDefaultEndian(std::endian endian) - { + void PatternLanguage::setDefaultEndian(std::endian endian) { this->m_defaultEndian = endian; } - void PatternLanguage::setStartAddress(u64 address) - { + void PatternLanguage::setStartAddress(u64 address) { this->m_startAddress = address; } - u64 PatternLanguage::getStartAddress() const - { + u64 PatternLanguage::getStartAddress() const { return this->m_startAddress.value_or(0x00); } - void PatternLanguage::setDangerousFunctionCallHandler(std::function callback) - { + void PatternLanguage::setDangerousFunctionCallHandler(std::function callback) { this->m_dangerousFunctionCallCallback = std::move(callback); } - [[nodiscard]] std::map PatternLanguage::getOutVariables() const - { + [[nodiscard]] std::map PatternLanguage::getOutVariables() const { return this->m_internals.evaluator->getOutVariables(); } - void PatternLanguage::setLogCallback(const core::LogConsole::Callback &callback) - { + void PatternLanguage::setLogCallback(const core::LogConsole::Callback &callback) { this->m_logCallback = callback; } - const std::optional &PatternLanguage::getEvalError() const - { + const std::optional &PatternLanguage::getEvalError() const { return this->m_currError; } - const std::vector &PatternLanguage::getCompileErrors() const - { + const std::vector &PatternLanguage::getCompileErrors() const { return this->m_compileErrors; } - u64 PatternLanguage::getCreatedPatternCount() const - { + u64 PatternLanguage::getCreatedPatternCount() const { return this->m_internals.evaluator->getPatternCount(); } - u64 PatternLanguage::getMaximumPatternCount() const - { + u64 PatternLanguage::getMaximumPatternCount() const { return this->m_internals.evaluator->getPatternLimit(); } - const std::vector &PatternLanguage::getSection(u64 id) const - { + const std::vector &PatternLanguage::getSection(u64 id) const { static std::vector empty; if (id > this->m_internals.evaluator->getSectionCount() || id == ptrn::Pattern::MainSectionId || id == ptrn::Pattern::HeapSectionId) return empty; @@ -488,13 +434,11 @@ namespace pl return this->m_internals.evaluator->getSection(id); } - [[nodiscard]] const std::map &PatternLanguage::getSections() const - { + [[nodiscard]] const std::map &PatternLanguage::getSections() const { return this->m_internals.evaluator->getSections(); } - [[nodiscard]] const std::vector> &PatternLanguage::getPatterns(u64 section) const - { + [[nodiscard]] const std::vector> &PatternLanguage::getPatterns(u64 section) const { static const std::vector> empty; if (this->m_patterns.contains(section)) return this->m_patterns.at(section); @@ -528,8 +472,7 @@ namespace pl this->m_resolvers.setDefaultResolver([this](const std::string &path) { return this->m_fileResolver.resolve(path); }); - auto resolver = [this](const std::string &path) - { + auto resolver = [this](const std::string &path) { return this->m_resolvers.resolve(path); }; @@ -538,38 +481,30 @@ namespace pl this->m_parserManager.setPatternLanguage(this); } - void PatternLanguage::addFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) - { + void PatternLanguage::addFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) { this->m_functions.emplace_back(ns, name, parameterCount, func, false); } - void PatternLanguage::addDangerousFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) - { + void PatternLanguage::addDangerousFunction(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::FunctionCallback &func) { this->m_functions.emplace_back(ns, name, parameterCount, func, true); } - void PatternLanguage::addType(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::TypeCallback &func) - { + void PatternLanguage::addType(const api::Namespace &ns, const std::string &name, api::FunctionParameterCount parameterCount, const api::TypeCallback &func) { this->m_parserManager.addBuiltinType(getFunctionName(ns, name), parameterCount, func); } - void PatternLanguage::flattenPatterns() - { - for (const auto &[section, patterns] : this->m_patterns) - { + void PatternLanguage::flattenPatterns() { + for (const auto &[section, patterns] : this->m_patterns) { if (this->m_aborted) return; auto §ionTree = this->m_flattenedPatterns[section]; - for (const auto &pattern : patterns) - { + for (const auto &pattern : patterns) { if (this->m_aborted) return; - if (auto staticArray = dynamic_cast(pattern.get()); staticArray != nullptr) - { - if (staticArray->getEntryCount() > 0 && staticArray->getEntry(0)->getChildren().empty()) - { + if (auto staticArray = dynamic_cast(pattern.get()); staticArray != nullptr) { + if (staticArray->getEntryCount() > 0 && staticArray->getEntry(0)->getChildren().empty()) { const auto address = staticArray->getOffset(); const auto size = staticArray->getSize(); sectionTree.insert({address, address + size - 1}, staticArray); @@ -578,8 +513,7 @@ namespace pl } auto children = pattern->getChildren(); - for (const auto &[address, child] : children) - { + for (const auto &[address, child] : children) { if (this->m_aborted) return; @@ -592,8 +526,7 @@ namespace pl } } - std::vector PatternLanguage::getPatternsAtAddress(u64 address, u64 section) const - { + std::vector PatternLanguage::getPatternsAtAddress(u64 address, u64 section) const { if (this->m_flattenedPatterns.empty() || !this->m_flattenedPatterns.contains(section)) return {}; @@ -621,16 +554,14 @@ namespace pl return results; } - std::vector PatternLanguage::getColorsAtAddress(u64 address, u64 section) const - { + std::vector PatternLanguage::getColorsAtAddress(u64 address, u64 section) const { if (this->m_flattenedPatterns.empty() || !this->m_flattenedPatterns.contains(section)) return {}; auto intervals = this->m_flattenedPatterns.at(section).overlapping({address, address}); std::vector results; - for (auto &[interval, pattern] : intervals) - { + for (auto &[interval, pattern] : intervals) { auto visibility = pattern->getVisibility(); if (visibility == pl::ptrn::Visibility::Hidden || visibility == pl::ptrn::Visibility::HighlightHidden) continue; @@ -641,8 +572,7 @@ namespace pl return results; } - const std::set &PatternLanguage::getPatternsWithAttribute(const std::string &attribute) const - { + const std::set &PatternLanguage::getPatternsWithAttribute(const std::string &attribute) const { return m_internals.evaluator->getPatternsWithAttribute(attribute); } From 95e0ccf98632938c8ca966df708d8a60a6b38e5b Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 01:29:53 +1000 Subject: [PATCH 03/16] Fix auto code-formatter disaster --- lib/include/pl/core/lexer.hpp | 4 +- lib/include/pl/pattern_language.hpp | 13 +- lib/source/pl/core/lexer.cpp | 224 ++++++++++++++-------------- lib/source/pl/pattern_language.cpp | 89 ++++++----- 4 files changed, 160 insertions(+), 170 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index 3fd29d95..cf6315f9 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -48,7 +48,7 @@ namespace pl::core { std::optional parseInteger(std::string_view literal); Token makeToken(const Token& token, size_t length = 1); - static Token makeTokenAt(const Token& token, Location &location, size_t length = 1); + static Token makeTokenAt(const Token& token, Location& location, size_t length = 1); void addToken(const Token& token); bool skipLineEnding() { @@ -77,7 +77,7 @@ namespace pl::core { static constexpr int tabsize = 4; std::string m_sourceCode; - const api::Source *m_source = nullptr; + const api::Source* m_source = nullptr; std::vector m_tokens; size_t m_cursor = 0; u32 m_line = 0; diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index adec70c7..114ccf5d 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -24,8 +24,7 @@ #include #include -namespace pl -{ +namespace pl { namespace core { class Preprocessor; @@ -331,13 +330,11 @@ namespace pl * @warning Generally this should only be used by "IDEs" or other tools that need to access the internals of the pattern language * @return Internals */ - [[nodiscard]] const Internals& getInternals() const - { + [[nodiscard]] const Internals& getInternals() const { return this->m_internals; } - [[nodiscard]] const std::map& getDefines() const - { + [[nodiscard]] const std::map& getDefines() const { return this->m_defines; } @@ -345,7 +342,7 @@ namespace pl return this->m_currAST; } - [[nodiscard]] const std::map &getPragmas() const { + [[nodiscard]] const std::map& getPragmas() const { return this->m_pragmas; } @@ -400,7 +397,7 @@ namespace pl return this->m_subRuntime; } - [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string &attribute) const; + [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string& attribute) const; private: void flattenPatterns(); diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 7ab392c6..09f32c0a 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -5,8 +5,7 @@ #include -namespace pl::core -{ +namespace pl::core { using namespace tkn; static constexpr char integerSeparator = '\''; @@ -16,8 +15,7 @@ namespace pl::core } static bool isIntegerCharacter(const char c, const int base) { - switch (base) - { + switch (base) { case 16: return std::isxdigit(c); case 10: @@ -45,7 +43,7 @@ namespace pl::core return 0; } - static size_t getIntegerLiteralLength(const std::string_view &literal) { + static size_t getIntegerLiteralLength(const std::string_view& literal) { const auto count = literal.find_first_not_of("0123456789ABCDEFabcdef'xXoOpP.uU+-"); const std::string_view intLiteral = count == std::string_view::npos ? literal : literal.substr(0, count); if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos-1) != 'e' && literal.at(signPos-1) != 'E') || literal.starts_with("0x"))) @@ -54,59 +52,59 @@ namespace pl::core } std::optional Lexer::parseCharacter() { - const char &c = m_sourceCode[m_cursor++]; + const char& c = m_sourceCode[m_cursor++]; if (c == '\\') { switch (m_sourceCode[m_cursor++]) { - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 't': - return '\t'; - case 'r': - return '\r'; - case '0': - return '\0'; - case '\'': - return '\''; - case '"': - return '"'; - case '\\': - return '\\'; - case 'x': { - const char hex[3] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0}; - m_cursor += 2; - try { - return static_cast(std::stoul(hex, nullptr, 16)); - } - catch (const std::invalid_argument&) { - m_errorLength = 2; - error("Invalid hex escape sequence: {}", hex); - return std::nullopt; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 't': + return '\t'; + case 'r': + return '\r'; + case '0': + return '\0'; + case '\'': + return '\''; + case '"': + return '"'; + case '\\': + return '\\'; + case 'x': { + const char hex[3] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0}; + m_cursor += 2; + try { + return static_cast(std::stoul(hex, nullptr, 16)); + } + catch (const std::invalid_argument&) { + m_errorLength = 2; + error("Invalid hex escape sequence: {}", hex); + return std::nullopt; + } } - } - case 'u': { - const char hex[5] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], - m_sourceCode[m_cursor + 3], 0}; - m_cursor += 4; - try { - return static_cast(std::stoul(hex, nullptr, 16)); + case 'u': { + const char hex[5] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], + m_sourceCode[m_cursor + 3], 0}; + m_cursor += 4; + try { + return static_cast(std::stoul(hex, nullptr, 16)); + } + catch (const std::invalid_argument &) { + m_errorLength = 4; + error("Invalid unicode escape sequence: {}", hex); + return std::nullopt; + } } - catch (const std::invalid_argument &) { - m_errorLength = 4; - error("Invalid unicode escape sequence: {}", hex); + default: + m_errorLength = 1; + error("Unknown escape sequence: {}", m_sourceCode[m_cursor - 1]); return std::nullopt; } - } - default: - m_errorLength = 1; - error("Unknown escape sequence: {}", m_sourceCode[m_cursor - 1]); - return std::nullopt; - } } return c; } @@ -209,21 +207,21 @@ namespace pl::core } bool hasPrefix = true; switch (literal[1]) { - case 'x': - case 'X': - base = 16; - break; - case 'o': - case 'O': - base = 8; - break; - case 'b': - case 'B': - base = 2; - break; - default: - hasPrefix = false; - break; + case 'x': + case 'X': + base = 16; + break; + case 'o': + case 'O': + base = 8; + break; + case 'b': + case 'B': + base = 2; + break; + default: + hasPrefix = false; + break; } if (hasPrefix) { literal = literal.substr(2); @@ -231,8 +229,7 @@ namespace pl::core } for (const char c : literal) { - if (c == integerSeparator) - continue; + if (c == integerSeparator) continue; if (!isIntegerCharacter(c, base)) { m_errorLength = literal.size(); @@ -249,7 +246,7 @@ namespace pl::core char *end = nullptr; double val = std::strtod(literal.data(), &end); - if (end != literal.data() + literal.size()) { + if(end != literal.data() + literal.size()) { m_errorLength = literal.size(); error("Invalid float literal: {}", literal); return std::nullopt; @@ -257,27 +254,27 @@ namespace pl::core switch (suffix) { - case 'f': - case 'F': - return float(val); - case 'd': - case 'D': - default: - return val; + case 'f': + case 'F': + return float(val); + case 'd': + case 'D': + default: + return val; } } std::optional Lexer::parseIntegerLiteral(std::string_view literal) { // parse a c like numeric literal - const bool floatSuffix = hlp::stringEndsWithOneOf(literal, {"f", "F", "d", "D"}); - const bool unsignedSuffix = hlp::stringEndsWithOneOf(literal, {"u", "U"}); + const bool floatSuffix = hlp::stringEndsWithOneOf(literal, { "f", "F", "d", "D" }); + const bool unsignedSuffix = hlp::stringEndsWithOneOf(literal, { "u", "U" }); const bool isFloat = literal.find('.') != std::string_view::npos || (!literal.starts_with("0x") && floatSuffix); const bool isUnsigned = unsignedSuffix; - if (isFloat) { + if(isFloat) { char suffix = 0; - if (floatSuffix) { + if(floatSuffix) { // remove suffix suffix = literal.back(); literal = literal.substr(0, literal.size() - 1); @@ -285,24 +282,24 @@ namespace pl::core auto floatingPoint = parseFloatingPoint(literal, suffix); - if (!floatingPoint.has_value()) + if(!floatingPoint.has_value()) return std::nullopt; return floatingPoint.value(); } - if (unsignedSuffix) { + if(unsignedSuffix) { // remove suffix literal = literal.substr(0, literal.size() - 1); } const auto integer = parseInteger(literal); - if (!integer.has_value()) + if(!integer.has_value()) return std::nullopt; u128 value = integer.value(); - if (isUnsigned) { + if(isUnsigned) { return value; } @@ -315,7 +312,7 @@ namespace pl::core m_cursor += 2; std::string result; - while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { + while(m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { result += m_sourceCode[m_cursor]; m_cursor++; } @@ -332,7 +329,7 @@ namespace pl::core m_cursor += 3; std::string result; - while (m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { + while(m_sourceCode[m_cursor] != '\n' && m_sourceCode[m_cursor] != '\0') { result += m_sourceCode[m_cursor]; m_cursor++; } @@ -353,13 +350,13 @@ namespace pl::core while (true) { skipLineEnding(); - if (peek(1) == '\x00') { + if(peek(1) == '\x00') { m_errorLength = 1; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; } - if (peek(0) == '*' && peek(1) == '/') { + if(peek(0) == '*' && peek(1) == '/') { m_cursor += 2; break; } @@ -376,7 +373,7 @@ namespace pl::core std::string result; m_cursor += 2; - while (true) { + while(true) { skipLineEnding(); if (peek(1) == '\x00') { @@ -403,7 +400,7 @@ namespace pl::core std::optional lastMatch = std::nullopt; for (int i = 1; i <= Operator::maxOperatorLength; ++i) { - const auto view = std::string_view{&m_sourceCode[begin], static_cast(i)}; + const auto view = std::string_view { &m_sourceCode[begin], static_cast(i) }; if (auto operatorToken = operators.find(view); operatorToken != operators.end()) { m_cursor++; lastMatch = operatorToken->second; @@ -463,9 +460,9 @@ namespace pl::core return {token.type, token.value, location}; } - Token Lexer::makeTokenAt(const Token &token, Location &location, const size_t length) { + Token Lexer::makeTokenAt(const Token &token, Location& location, const size_t length) { location.length = length; - return {token.type, token.value, location}; + return { token.type, token.value, location }; } void Lexer::addToken(const Token &token) { @@ -486,7 +483,7 @@ namespace pl::core m_tokens.clear(); while (this->m_cursor < end) { - const char &c = this->m_sourceCode[this->m_cursor]; + const char& c = this->m_sourceCode[this->m_cursor]; if (c == '\x00') { m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); @@ -505,13 +502,13 @@ namespace pl::core continue; } - if (isIdentifierCharacter(c) && !std::isdigit(c)) { + if(isIdentifierCharacter(c) && !std::isdigit(c)) { size_t length = 0; while (isIdentifierCharacter(peek(length))) { length++; } - auto identifier = std::string_view{&m_sourceCode[m_cursor], length}; + auto identifier = std::string_view { &m_sourceCode[m_cursor], length }; // process keywords, named operators and types if (processToken(&Lexer::parseKeyword, identifier) || @@ -529,11 +526,11 @@ namespace pl::core continue; } - if (std::isdigit(c)) { + if(std::isdigit(c)) { auto literal = &m_sourceCode[m_cursor]; size_t size = getIntegerLiteralLength(literal); - const auto integer = parseIntegerLiteral({literal, size}); + const auto integer = parseIntegerLiteral({ literal, size }); if (integer.has_value()) { addToken(makeToken(Literal::makeNumeric(integer.value()), size)); @@ -546,33 +543,32 @@ namespace pl::core } // comment cases - if (c == '/') { + if(c == '/') { const char category = peek(1); char type = peek(2); - if (category == '/') { - if (type == '/') { + if(category == '/') { + if(type == '/') { const auto token = parseOneLineDocComment(); if (token.has_value()) { addToken(token.value()); } - } - else { + } else { const auto token = parseOneLineComment(); - if (token.has_value()) { + if(token.has_value()) { addToken(token.value()); } } continue; } - if (category == '*') { - if (type != '!' && (type != '*' || peek(3) == '/')) { + if(category == '*') { + if(type != '!' && (type != '*' || peek(3) == '/')) { const auto token = parseMultiLineComment(); - if (token.has_value()) + if(token.has_value()) addToken(token.value()); continue; } const auto token = parseMultiLineDocComment(); - if (token.has_value()) { + if(token.has_value()) { addToken(token.value()); } continue; @@ -630,15 +626,14 @@ namespace pl::core addToken(string.value()); continue; } - } - else if (c == '\'') { + } else if (c == '\'') { auto location = this->location(); const auto begin = m_cursor; m_cursor++; // skip opening ' const auto character = parseCharacter(); if (character.has_value()) { - if (m_sourceCode[m_cursor] != '\'') { + if(m_sourceCode[m_cursor] != '\'') { m_errorLength = 1; error("Expected closing '"); continue; @@ -649,8 +644,7 @@ namespace pl::core addToken(makeTokenAt(Literal::makeNumeric(character.value()), location, m_cursor - begin)); continue; } - } - else { + } else { m_errorLength = 1; error("Unexpected character: {}", c); m_cursor++; @@ -663,14 +657,14 @@ namespace pl::core m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); addToken(makeToken(Separator::EndOfProgram, 0)); - return {m_tokens, collectErrors()}; + return { m_tokens, collectErrors() }; } inline char Lexer::peek(const size_t p) const { return m_cursor + p < m_sourceCode.size() ? m_sourceCode[m_cursor + p] : '\0'; } - bool Lexer::processToken(auto parserFunction, const std::string_view &identifier) { + bool Lexer::processToken(auto parserFunction, const std::string_view& identifier) { const auto token = (this->*parserFunction)(identifier); if (token.has_value()) { m_tokens.emplace_back(token.value()); diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index 8ffacf3a..7a288e8d 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -31,13 +31,14 @@ namespace pl { return functionName; } - PatternLanguage::PatternLanguage(const bool addLibStd) { + PatternLanguage::PatternLanguage(const bool addLibStd) { this->m_internals = { - .preprocessor = std::make_unique(), - .lexer = std::make_unique(), - .parser = std::make_unique(), - .validator = std::make_unique(), - .evaluator = std::make_unique()}; + .preprocessor = std::make_unique(), + .lexer = std::make_unique(), + .parser = std::make_unique(), + .validator = std::make_unique(), + .evaluator = std::make_unique() + }; this->m_internals.evaluator->setRuntime(this); @@ -56,37 +57,35 @@ namespace pl { } PatternLanguage::PatternLanguage(PatternLanguage &&other) noexcept { - if (this->m_flattenThread.joinable()) - this->m_flattenThread.join(); - - this->m_internals = std::move(other.m_internals); - other.m_internals = {}; + this->m_internals = std::move(other.m_internals); + other.m_internals = { }; this->m_internals.evaluator->setRuntime(this); - this->m_compileErrors = std::move(other.m_compileErrors); - this->m_currError = std::move(other.m_currError); - this->m_defines = std::move(other.m_defines); - this->m_pragmas = std::move(other.m_pragmas); + this->m_compileErrors = std::move(other.m_compileErrors); + this->m_currError = std::move(other.m_currError); + + this->m_defines = std::move(other.m_defines); + this->m_pragmas = std::move(other.m_pragmas); - this->m_resolvers = std::move(other.m_resolvers); - this->m_fileResolver = std::move(other.m_fileResolver); - this->m_parserManager = std::move(other.m_parserManager); + this->m_resolvers = std::move(other.m_resolvers); + this->m_fileResolver = std::move(other.m_fileResolver); + this->m_parserManager = std::move(other.m_parserManager); - this->m_patterns = std::move(other.m_patterns); - this->m_flattenedPatterns = std::move(other.m_flattenedPatterns); - this->m_cleanupCallbacks = std::move(other.m_cleanupCallbacks); - this->m_currAST = std::move(other.m_currAST); + this->m_patterns = std::move(other.m_patterns); + this->m_flattenedPatterns = std::move(other.m_flattenedPatterns); + this->m_cleanupCallbacks = std::move(other.m_cleanupCallbacks); + this->m_currAST = std::move(other.m_currAST); - this->m_dataBaseAddress = other.m_dataBaseAddress; - this->m_dataSize = other.m_dataSize; - this->m_dataReadFunction = std::move(other.m_dataReadFunction); - this->m_dataWriteFunction = std::move(other.m_dataWriteFunction); + this->m_dataBaseAddress = other.m_dataBaseAddress; + this->m_dataSize = other.m_dataSize; + this->m_dataReadFunction = std::move(other.m_dataReadFunction); + this->m_dataWriteFunction = std::move(other.m_dataWriteFunction); - this->m_logCallback = std::move(other.m_logCallback); - this->m_dangerousFunctionCallCallback = std::move(other.m_dangerousFunctionCallCallback); + this->m_logCallback = std::move(other.m_logCallback); + this->m_dangerousFunctionCallCallback = std::move(other.m_dangerousFunctionCallCallback); - this->m_functions = std::move(other.m_functions); + this->m_functions = std::move(other.m_functions); this->m_running.exchange(other.m_running.load()); this->m_patternsValid.exchange(other.m_patternsValid.load()); @@ -94,30 +93,30 @@ namespace pl { this->m_runId.exchange(other.m_runId.load()); this->m_subRuntime = other.m_subRuntime; - m_startAddress = std::move(other.m_startAddress); + m_startAddress = std::move(other.m_startAddress); m_defaultEndian = other.m_defaultEndian; - m_runningTime = other.m_runningTime; + m_runningTime = other.m_runningTime; } PatternLanguage PatternLanguage::cloneRuntime() const { PatternLanguage runtime; - runtime.m_defines = this->m_defines; - runtime.m_pragmas = this->m_pragmas; + runtime.m_defines = this->m_defines; + runtime.m_pragmas = this->m_pragmas; - runtime.m_resolvers = this->m_resolvers; - runtime.m_fileResolver = this->m_fileResolver; + runtime.m_resolvers = this->m_resolvers; + runtime.m_fileResolver = this->m_fileResolver; runtime.m_parserManager = this->m_parserManager; - runtime.m_startAddress = this->m_startAddress; + runtime.m_startAddress = this->m_startAddress; runtime.m_defaultEndian = this->m_defaultEndian; - runtime.m_dataBaseAddress = this->m_dataBaseAddress; - runtime.m_dataSize = this->m_dataSize; - runtime.m_dataReadFunction = this->m_dataReadFunction; - runtime.m_dataWriteFunction = this->m_dataWriteFunction; + runtime.m_dataBaseAddress = this->m_dataBaseAddress; + runtime.m_dataSize = this->m_dataSize; + runtime.m_dataReadFunction = this->m_dataReadFunction; + runtime.m_dataWriteFunction = this->m_dataWriteFunction; - runtime.m_logCallback = this->m_logCallback; - runtime.m_dangerousFunctionCallCallback = this->m_dangerousFunctionCallCallback; + runtime.m_logCallback = this->m_logCallback; + runtime.m_dangerousFunctionCallCallback = this->m_dangerousFunctionCallCallback; runtime.m_functions = this->m_functions; runtime.m_subRuntime = true; @@ -125,7 +124,7 @@ namespace pl { return runtime; } - [[nodiscard]] std::optional> PatternLanguage::preprocessString(const std::string &code, const std::string &source) { + [[nodiscard]] std::optional> PatternLanguage::preprocessString(const std::string& code, const std::string& source) { this->reset(); auto internalSource = addVirtualSource(code, source, true); // add virtual source to file resolver @@ -140,7 +139,7 @@ namespace pl { this->m_compileErrors.clear(); auto [tokens, preprocessorErrors] = this->m_internals.preprocessor->preprocess(this, internalSource, true); - if (!preprocessorErrors.empty()) + if (!preprocessorErrors.empty()) this->m_compileErrors = std::move(preprocessorErrors); if (!tokens.has_value() || tokens->empty()) return std::nullopt; @@ -199,7 +198,7 @@ namespace pl { ON_SCOPE_EXIT { this->m_running = false; }; ON_SCOPE_EXIT { - for (const auto &error : this->m_compileErrors) { + for (const auto &error: this->m_compileErrors) { evaluator->getConsole().log(core::LogConsole::Level::Error, error.format()); } From f52b404cb3894454782fb480d9aac26c92564732 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 01:41:14 +1000 Subject: [PATCH 04/16] Fix auto code-formatter disaster --- lib/include/pl/core/lexer.hpp | 2 +- lib/include/pl/pattern_language.hpp | 2 +- lib/source/pl/core/lexer.cpp | 60 ++++++++++++++--------------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index cf6315f9..fe036b96 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -84,6 +84,6 @@ namespace pl::core { u32 m_tabCompensation = 0; u32 m_lineBegin = 0; size_t m_longestLineLength = 0; - u32 m_errorLength; + u32 m_errorLength = 0 }; } \ No newline at end of file diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 114ccf5d..098ede51 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -397,7 +397,7 @@ namespace pl { return this->m_subRuntime; } - [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string& attribute) const; + [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string & attribute) const; private: void flattenPatterns(); diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 09f32c0a..e92b465d 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -16,16 +16,16 @@ namespace pl::core { static bool isIntegerCharacter(const char c, const int base) { switch (base) { - case 16: - return std::isxdigit(c); - case 10: - return std::isdigit(c); - case 8: - return c >= '0' && c <= '7'; - case 2: - return c == '0' || c == '1'; - default: - return false; + case 16: + return std::isxdigit(c); + case 10: + return std::isdigit(c); + case 8: + return c >= '0' && c <= '7'; + case 2: + return c == '0' || c == '1'; + default: + return false; } } @@ -46,7 +46,7 @@ namespace pl::core { static size_t getIntegerLiteralLength(const std::string_view& literal) { const auto count = literal.find_first_not_of("0123456789ABCDEFabcdef'xXoOpP.uU+-"); const std::string_view intLiteral = count == std::string_view::npos ? literal : literal.substr(0, count); - if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos-1) != 'e' && literal.at(signPos-1) != 'E') || literal.starts_with("0x"))) + if (const auto signPos = intLiteral.find_first_of("+-"); signPos != std::string_view::npos && ((literal.at(signPos-1) != 'e' && literal.at(signPos-1) != 'E') || literal.starts_with("0x"))) return signPos; return intLiteral.size(); } @@ -76,25 +76,23 @@ namespace pl::core { case '\\': return '\\'; case 'x': { - const char hex[3] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0}; + const char hex[3] = { m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], 0 }; m_cursor += 2; try { return static_cast(std::stoul(hex, nullptr, 16)); - } - catch (const std::invalid_argument&) { + } catch (const std::invalid_argument&) { m_errorLength = 2; error("Invalid hex escape sequence: {}", hex); return std::nullopt; } } case 'u': { - const char hex[5] = {m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], - m_sourceCode[m_cursor + 3], 0}; + const char hex[5] = { m_sourceCode[m_cursor], m_sourceCode[m_cursor + 1], m_sourceCode[m_cursor + 2], + m_sourceCode[m_cursor + 3], 0 }; m_cursor += 4; try { return static_cast(std::stoul(hex, nullptr, 16)); - } - catch (const std::invalid_argument &) { + } catch (const std::invalid_argument&) { m_errorLength = 4; error("Invalid unicode escape sequence: {}", hex); return std::nullopt; @@ -102,9 +100,9 @@ namespace pl::core { } default: m_errorLength = 1; - error("Unknown escape sequence: {}", m_sourceCode[m_cursor - 1]); - return std::nullopt; - } + error("Unknown escape sequence: {}", m_sourceCode[m_cursor-1]); + return std::nullopt; + } } return c; } @@ -122,11 +120,10 @@ namespace pl::core { std::optional Lexer::parseDirectiveValue() { std::string result; - // TODO: What if there are two spaces? Tabs? BUG! m_cursor++; // Skip space auto location = this->location(); - while (!std::isblank(m_sourceCode[m_cursor]) && !std::isspace(m_sourceCode[m_cursor]) && m_sourceCode[m_cursor] != '\0') { + while (!std::isblank(m_sourceCode[m_cursor]) && !std::isspace(m_sourceCode[m_cursor]) && m_sourceCode[m_cursor] != '\0' ) { auto character = parseCharacter(); if (!character.has_value()) { @@ -136,7 +133,8 @@ namespace pl::core { result += character.value(); } - skipLineEnding(); + if (hasTheLineEnded(m_sourceCode[m_cursor])) + m_cursor++; return makeTokenAt(Literal::makeString(result), location, result.size()); } @@ -201,8 +199,8 @@ namespace pl::core { u8 base = 10; u128 value = 0; - if (literal[0] == '0') { - if (literal.size() == 1) { + if(literal[0] == '0') { + if(literal.size() == 1) { return 0; } bool hasPrefix = true; @@ -210,18 +208,18 @@ namespace pl::core { case 'x': case 'X': base = 16; - break; + break; case 'o': case 'O': base = 8; - break; + break; case 'b': case 'B': base = 2; - break; + break; default: hasPrefix = false; - break; + break; } if (hasPrefix) { literal = literal.substr(2); @@ -229,7 +227,7 @@ namespace pl::core { } for (const char c : literal) { - if (c == integerSeparator) continue; + if(c == integerSeparator) continue; if (!isIntegerCharacter(c, base)) { m_errorLength = literal.size(); From 4ecaf94ce942aeaa656fa0c28e7b862c83a22090 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 01:56:36 +1000 Subject: [PATCH 05/16] Fix auto code-formatter disaster --- lib/include/pl/pattern_language.hpp | 2 +- lib/source/pl/core/lexer.cpp | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 098ede51..444bece5 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -397,7 +397,7 @@ namespace pl { return this->m_subRuntime; } - [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string & attribute) const; + [[nodiscard]] const std::set& getPatternsWithAttribute(const std::string &attribute) const; private: void flattenPatterns(); diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index e92b465d..7628f148 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -250,8 +250,7 @@ namespace pl::core { return std::nullopt; } - switch (suffix) - { + switch (suffix) { case 'f': case 'F': return float(val); @@ -266,7 +265,8 @@ namespace pl::core { // parse a c like numeric literal const bool floatSuffix = hlp::stringEndsWithOneOf(literal, { "f", "F", "d", "D" }); const bool unsignedSuffix = hlp::stringEndsWithOneOf(literal, { "u", "U" }); - const bool isFloat = literal.find('.') != std::string_view::npos || (!literal.starts_with("0x") && floatSuffix); + const bool isFloat = literal.find('.') != std::string_view::npos + || (!literal.starts_with("0x") && floatSuffix); const bool isUnsigned = unsignedSuffix; if(isFloat) { @@ -280,10 +280,10 @@ namespace pl::core { auto floatingPoint = parseFloatingPoint(literal, suffix); - if(!floatingPoint.has_value()) - return std::nullopt; + if(!floatingPoint.has_value()) return std::nullopt; return floatingPoint.value(); + } if(unsignedSuffix) { @@ -293,8 +293,7 @@ namespace pl::core { const auto integer = parseInteger(literal); - if(!integer.has_value()) - return std::nullopt; + if(!integer.has_value()) return std::nullopt; u128 value = integer.value(); if(isUnsigned) { @@ -374,13 +373,13 @@ namespace pl::core { while(true) { skipLineEnding(); - if (peek(1) == '\x00') { + if(peek(1) == '\x00') { m_errorLength = 2; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; } - if (peek(0) == '*' && peek(1) == '/') { + if(peek(0) == '*' && peek(1) == '/') { m_cursor += 2; break; } @@ -455,7 +454,7 @@ namespace pl::core { Token Lexer::makeToken(const Token &token, const size_t length) { auto location = this->location(); location.length = length; - return {token.type, token.value, location}; + return { token.type, token.value, location }; } Token Lexer::makeTokenAt(const Token &token, Location& location, const size_t length) { @@ -512,10 +511,9 @@ namespace pl::core { if (processToken(&Lexer::parseKeyword, identifier) || processToken(&Lexer::parseNamedOperator, identifier) || processToken(&Lexer::parseType, identifier) || - processToken(&Lexer::parseConstant, identifier)) - { + processToken(&Lexer::parseConstant, identifier)) { continue; - } + } // not a predefined token, so it must be an identifier addToken(makeToken(Literal::makeIdentifier(std::string(identifier)), length)); @@ -530,7 +528,7 @@ namespace pl::core { const auto integer = parseIntegerLiteral({ literal, size }); - if (integer.has_value()) { + if(integer.has_value()) { addToken(makeToken(Literal::makeNumeric(integer.value()), size)); this->m_cursor += size; continue; @@ -547,7 +545,7 @@ namespace pl::core { if(category == '/') { if(type == '/') { const auto token = parseOneLineDocComment(); - if (token.has_value()) { + if(token.has_value()) { addToken(token.value()); } } else { From 09bdf7ab16d5136e50bfa3b82f7bf82ac71fbe9f Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 02:06:32 +1000 Subject: [PATCH 06/16] Fix auto code-formatter disaster --- lib/source/pl/pattern_language.cpp | 91 +++++++++++++++++------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index 7a288e8d..2f4d154b 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -23,6 +23,7 @@ namespace pl { static std::string getFunctionName(const api::Namespace &ns, const std::string &name) { std::string functionName; + for (auto &scope : ns) functionName += fmt::format("{}::", scope); @@ -57,6 +58,9 @@ namespace pl { } PatternLanguage::PatternLanguage(PatternLanguage &&other) noexcept { + if (this->m_flattenThread.joinable()) + this->m_flattenThread.join(); + this->m_internals = std::move(other.m_internals); other.m_internals = { }; this->m_internals.evaluator->setRuntime(this); @@ -166,6 +170,7 @@ namespace pl { if (ast->empty()) return ast; + auto [validated, validatorErrors] = this->m_internals.validator->validate(ast.value()); wolv::util::unused(validated); if (!validatorErrors.empty()) { @@ -173,6 +178,7 @@ namespace pl { validatorErrors.clear(); } + this->m_internals.preprocessor->setStoredErrors(this->m_compileErrors); if (ast->empty() || !ast.has_value()) @@ -181,8 +187,8 @@ namespace pl { return m_currAST; } - bool PatternLanguage::executeString(const std::string &code, const std::string &source, const std::map &envVars, const std::map &inVariables, bool checkResult) { - const auto startTime = std::chrono::high_resolution_clock::now(); + bool PatternLanguage::executeString(const std::string &code, const std::string& source, const std::map &envVars, const std::map &inVariables, bool checkResult) { + const auto startTime = std::chrono::high_resolution_clock::now(); ON_SCOPE_EXIT { const auto endTime = std::chrono::high_resolution_clock::now(); this->m_runningTime = std::chrono::duration_cast>(endTime - startTime).count(); @@ -227,18 +233,22 @@ namespace pl { this->m_currAST = std::move(*ast); for (const auto &[ns, name, parameterCount, callback, dangerous] : this->m_functions) { - this->m_internals.evaluator->addBuiltinFunction(getFunctionName(ns, name), parameterCount, {}, callback, dangerous); + this->m_internals.evaluator->addBuiltinFunction(getFunctionName(ns, name), parameterCount, { }, callback, dangerous); } - std::optional> writeFunction; + std::optional> writeFunction; if (m_dataWriteFunction.has_value()) { writeFunction = [this](u64 address, const u8 *buffer, size_t size) { return (*this->m_dataWriteFunction)(address + this->getStartAddress(), buffer, size); }; } - evaluator->setDataSource(this->m_dataBaseAddress, this->m_dataSize, [this](u64 address, u8 *buffer, size_t size) - { return this->m_dataReadFunction(address + this->getStartAddress(), buffer, size); }, writeFunction); + evaluator->setDataSource(this->m_dataBaseAddress, this->m_dataSize, + [this](u64 address, u8 *buffer, size_t size) { + return this->m_dataReadFunction(address + this->getStartAddress(), buffer, size); + }, + writeFunction + ); evaluator->setStartAddress(this->getStartAddress()); evaluator->setReadOffset(evaluator->getDataBaseAddress()); @@ -272,8 +282,7 @@ namespace pl { console.log(core::LogConsole::Level::Error, fmt::format("Error happened with cursor at address 0x{:04X}", *cursor + m_startAddress.value_or(0x00))); console.log(core::LogConsole::Level::Error, "\n"); - } - else { + } else { auto returnCode = evaluator->getMainResult().value_or(i128(0)).toSigned(); if (!isSubRuntime()) { @@ -296,10 +305,10 @@ namespace pl { } } + if (this->m_aborted) { this->reset(); - } - else { + } else { this->flattenPatterns(); this->m_patternsValid = true; } @@ -320,12 +329,12 @@ namespace pl { const auto functionContent = fmt::format("fn main() {{ {0} }};", code); auto success = this->executeString(functionContent, api::Source::DefaultSource, {}, {}, false); - auto result = this->m_internals.evaluator->getMainResult(); + auto result = this->m_internals.evaluator->getMainResult(); - return {success, std::move(result)}; + return { success, std::move(result) }; } - api::Source *PatternLanguage::addVirtualSource(const std::string &code, const std::string &source, bool mainSource) const { + api::Source* PatternLanguage::addVirtualSource(const std::string &code, const std::string &source, bool mainSource) const { return this->m_fileResolver.addVirtualFile(code, source, mainSource); } @@ -334,11 +343,11 @@ namespace pl { this->m_aborted = true; } - void PatternLanguage::setIncludePaths(const std::vector &paths) { + void PatternLanguage::setIncludePaths(const std::vector& paths) { this->m_fileResolver.setIncludePaths(paths); } - void PatternLanguage::setResolver(const core::Resolver &resolver) { + void PatternLanguage::setResolver(const core::Resolver& resolver) { this->m_resolvers = resolver; } @@ -358,22 +367,22 @@ namespace pl { this->m_defines.erase(name); } - void PatternLanguage::setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writeFunction) { + void PatternLanguage::setDataSource(u64 baseAddress, u64 size, std::function readFunction, std::optional> writeFunction) { this->m_dataBaseAddress = baseAddress; this->m_dataSize = size; this->m_dataReadFunction = std::move(readFunction); this->m_dataWriteFunction = std::move(writeFunction); } - const std::atomic &PatternLanguage::getLastReadAddress() const { + const std::atomic& PatternLanguage::getLastReadAddress() const { return this->m_internals.evaluator->getLastReadAddress(); } - const std::atomic &PatternLanguage::getLastWriteAddress() const { + const std::atomic& PatternLanguage::getLastWriteAddress() const { return this->m_internals.evaluator->getLastWriteAddress(); } - const std::atomic &PatternLanguage::getLastPatternPlaceAddress() const { + const std::atomic& PatternLanguage::getLastPatternPlaceAddress() const { return this->m_internals.evaluator->getLastPatternPlaceAddress(); } @@ -397,6 +406,7 @@ namespace pl { return this->m_startAddress.value_or(0x00); } + void PatternLanguage::setDangerousFunctionCallHandler(std::function callback) { this->m_dangerousFunctionCallCallback = std::move(callback); } @@ -405,6 +415,7 @@ namespace pl { return this->m_internals.evaluator->getOutVariables(); } + void PatternLanguage::setLogCallback(const core::LogConsole::Callback &callback) { this->m_logCallback = callback; } @@ -413,10 +424,11 @@ namespace pl { return this->m_currError; } - const std::vector &PatternLanguage::getCompileErrors() const { + const std::vector& PatternLanguage::getCompileErrors() const { return this->m_compileErrors; } + u64 PatternLanguage::getCreatedPatternCount() const { return this->m_internals.evaluator->getPatternCount(); } @@ -425,7 +437,7 @@ namespace pl { return this->m_internals.evaluator->getPatternLimit(); } - const std::vector &PatternLanguage::getSection(u64 id) const { + const std::vector& PatternLanguage::getSection(u64 id) const { static std::vector empty; if (id > this->m_internals.evaluator->getSectionCount() || id == ptrn::Pattern::MainSectionId || id == ptrn::Pattern::HeapSectionId) return empty; @@ -433,7 +445,7 @@ namespace pl { return this->m_internals.evaluator->getSection(id); } - [[nodiscard]] const std::map &PatternLanguage::getSections() const { + [[nodiscard]] const std::map& PatternLanguage::getSections() const { return this->m_internals.evaluator->getSections(); } @@ -445,8 +457,8 @@ namespace pl { return empty; } - void PatternLanguage::reset() - { + + void PatternLanguage::reset() { if (this->m_flattenThread.joinable()) this->m_flattenThread.join(); this->m_patterns.clear(); @@ -468,10 +480,11 @@ namespace pl { this->m_internals.parser->setParserManager(&m_parserManager); this->m_patternsValid = false; - this->m_resolvers.setDefaultResolver([this](const std::string &path) - { return this->m_fileResolver.resolve(path); }); + this->m_resolvers.setDefaultResolver([this](const std::string& path) { + return this->m_fileResolver.resolve(path); + }); - auto resolver = [this](const std::string &path) { + auto resolver = [this](const std::string& path) { return this->m_resolvers.resolve(path); }; @@ -502,11 +515,11 @@ namespace pl { if (this->m_aborted) return; - if (auto staticArray = dynamic_cast(pattern.get()); staticArray != nullptr) { + if (auto staticArray = dynamic_cast(pattern.get()); staticArray != nullptr) { if (staticArray->getEntryCount() > 0 && staticArray->getEntry(0)->getChildren().empty()) { const auto address = staticArray->getOffset(); const auto size = staticArray->getSize(); - sectionTree.insert({address, address + size - 1}, staticArray); + sectionTree.insert({ address, address + size - 1 }, staticArray); continue; } } @@ -519,7 +532,7 @@ namespace pl { if (child->getSize() == 0) continue; - sectionTree.insert({address, address + child->getSize() - 1}, child); + sectionTree.insert({ address, address + child->getSize() - 1 }, child); } } } @@ -527,13 +540,12 @@ namespace pl { std::vector PatternLanguage::getPatternsAtAddress(u64 address, u64 section) const { if (this->m_flattenedPatterns.empty() || !this->m_flattenedPatterns.contains(section)) - return {}; + return { }; - auto intervals = this->m_flattenedPatterns.at(section).overlapping({address, address}); + auto intervals = this->m_flattenedPatterns.at(section).overlapping({ address, address }); - std::vector results; - std::transform(intervals.begin(), intervals.end(), std::back_inserter(results), [](const auto &interval) - { + std::vector results; + std::transform(intervals.begin(), intervals.end(), std::back_inserter(results), [](const auto &interval) { ptrn::Pattern* value = interval.value; auto parent = value->getParent(); @@ -548,16 +560,17 @@ namespace pl { value->clearFormatCache(); } - return value; }); + return value; + }); return results; } std::vector PatternLanguage::getColorsAtAddress(u64 address, u64 section) const { if (this->m_flattenedPatterns.empty() || !this->m_flattenedPatterns.contains(section)) - return {}; + return { }; - auto intervals = this->m_flattenedPatterns.at(section).overlapping({address, address}); + auto intervals = this->m_flattenedPatterns.at(section).overlapping({ address, address }); std::vector results; for (auto &[interval, pattern] : intervals) { @@ -571,7 +584,7 @@ namespace pl { return results; } - const std::set &PatternLanguage::getPatternsWithAttribute(const std::string &attribute) const { + const std::set& PatternLanguage::getPatternsWithAttribute(const std::string &attribute) const { return m_internals.evaluator->getPatternsWithAttribute(attribute); } From 35a70d9e99a1fc7c232fcae2f89f45d488ce157a Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 02:20:04 +1000 Subject: [PATCH 07/16] Fix build error. Code formatting mess resolved --- lib/include/pl/core/lexer.hpp | 2 +- lib/source/pl/core/lexer.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index fe036b96..1216db6e 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -84,6 +84,6 @@ namespace pl::core { u32 m_tabCompensation = 0; u32 m_lineBegin = 0; size_t m_longestLineLength = 0; - u32 m_errorLength = 0 + u32 m_errorLength = 0; }; } \ No newline at end of file diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 7628f148..4b302d67 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -133,8 +133,7 @@ namespace pl::core { result += character.value(); } - if (hasTheLineEnded(m_sourceCode[m_cursor])) - m_cursor++; + skipLineEnding(); return makeTokenAt(Literal::makeString(result), location, result.size()); } From 8c37d1d077698622bc68a5548b3910e84e989210 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 04:07:29 +1000 Subject: [PATCH 08/16] Make whole longest line visible --- lib/include/pl/core/lexer.hpp | 11 ++++++++--- lib/source/pl/core/lexer.cpp | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index 1216db6e..f713d01a 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -20,7 +20,12 @@ namespace pl::core { Lexer() = default; hlp::CompileResult> lex(const api::Source *source); - size_t getLongestLineLength() const { return m_longestLineLength; } + size_t getLongestLineLength() const { + // 'getLongestLineLength' is used my the pattern editor to control + // the x-scrolling range. Adding two makes the whole longest line visible. + // Not sure why we have to do this. + return m_longestLineLength+2; + } private: [[nodiscard]] char peek(size_t p = 1) const; @@ -54,15 +59,15 @@ namespace pl::core { bool skipLineEnding() { char ch = m_sourceCode[m_cursor]; if (ch == '\n') { + m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); m_tabCompensation = 0; - m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); m_line++; m_lineBegin = ++m_cursor; return true; } else if (ch == '\r') { + m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); m_tabCompensation = 0; - m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); m_line++; ch = m_sourceCode[++m_cursor]; if (ch == '\n') diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 4b302d67..42ca77d4 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -482,7 +482,7 @@ namespace pl::core { const char& c = this->m_sourceCode[this->m_cursor]; if (c == '\x00') { - m_longestLineLength = std::max(m_longestLineLength, m_cursor - m_lineBegin); + m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); break; // end of string } From dd10d4934063f2ece7f46de245274780ca70f8c2 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 05:46:03 +1000 Subject: [PATCH 09/16] Fix grammar in comment --- lib/include/pl/core/lexer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index f713d01a..cb92b8b2 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -21,7 +21,7 @@ namespace pl::core { hlp::CompileResult> lex(const api::Source *source); size_t getLongestLineLength() const { - // 'getLongestLineLength' is used my the pattern editor to control + // 'getLongestLineLength' is used by the pattern editor to control // the x-scrolling range. Adding two makes the whole longest line visible. // Not sure why we have to do this. return m_longestLineLength+2; From c02181895e9ae108a4244314e477af447e123ed0 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 18:19:08 +1000 Subject: [PATCH 10/16] Remove unwanted formatting changes --- lib/include/pl/pattern_language.hpp | 5 ++++- lib/source/pl/core/lexer.cpp | 13 +++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 444bece5..4c60ce9a 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -74,6 +74,7 @@ namespace pl { * @return token stream */ [[nodiscard]] std::optional> preprocessString(const std::string &code, const std::string &source); + /** * @brief Parses a pattern language code string and returns the generated AST @@ -121,7 +122,7 @@ namespace pl { /** * @brief Aborts the currently running execution asynchronously - */ + */ void abort(); /** @@ -158,6 +159,7 @@ namespace pl { void setStartAddress(u64 address); u64 getStartAddress() const; + /** * @brief Adds a new pragma preprocessor instruction * @param name Name of the pragma @@ -269,6 +271,7 @@ namespace pl { */ [[nodiscard]] std::vector getPatternsAtAddress(u64 address, u64 section = 0x00) const; + /** * @brief Get the colors of all patterns that overlap with the given address * @param address Address to check diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 42ca77d4..cd91bb44 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -51,6 +51,7 @@ namespace pl::core { return intLiteral.size(); } + std::optional Lexer::parseCharacter() { const char& c = m_sourceCode[m_cursor++]; if (c == '\\') { @@ -414,7 +415,7 @@ namespace pl::core { separatorToken != Token::Separators().end()) { m_cursor++; return makeTokenAt(separatorToken->second, location, m_cursor - begin); - } + } return std::nullopt; } @@ -556,7 +557,7 @@ namespace pl::core { continue; } if(category == '*') { - if(type != '!' && (type != '*' || peek(3) == '/')) { + if (type != '!' && (type != '*' || peek(3) == '/' )) { const auto token = parseMultiLineComment(); if(token.has_value()) addToken(token.value()); @@ -582,7 +583,7 @@ namespace pl::core { continue; } - if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) { + if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) { size_t length = 1; u32 line = m_line; while (isIdentifierCharacter(peek(length))) @@ -592,8 +593,8 @@ namespace pl::core { if (processToken(&Lexer::parseDirectiveName, directiveName)) { Token::Directive directive = get(m_tokens.back().value); if (m_line != line || directive == Token::Directive::Define || directive == Token::Directive::Undef || - peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || - directive == Token::Directive::EndIf) + peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || + directive == Token::Directive::EndIf) continue; if (skipLineEnding()) continue; @@ -621,7 +622,7 @@ namespace pl::core { addToken(string.value()); continue; } - } else if (c == '\'') { + } else if(c == '\'') { auto location = this->location(); const auto begin = m_cursor; m_cursor++; // skip opening ' From 155dcbeac35a0480372e47952b33b341e5b7414a Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 18:19:08 +1000 Subject: [PATCH 11/16] Remove unwanted formatting changes --- lib/include/pl/pattern_language.hpp | 5 ++++- lib/source/pl/core/lexer.cpp | 13 +++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 444bece5..97a816bf 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -75,6 +75,7 @@ namespace pl { */ [[nodiscard]] std::optional> preprocessString(const std::string &code, const std::string &source); + /** * @brief Parses a pattern language code string and returns the generated AST * To get parsing errors, check PatternLanguage#getCompileErrors() after calling this method @@ -121,7 +122,7 @@ namespace pl { /** * @brief Aborts the currently running execution asynchronously - */ + */ void abort(); /** @@ -158,6 +159,7 @@ namespace pl { void setStartAddress(u64 address); u64 getStartAddress() const; + /** * @brief Adds a new pragma preprocessor instruction * @param name Name of the pragma @@ -269,6 +271,7 @@ namespace pl { */ [[nodiscard]] std::vector getPatternsAtAddress(u64 address, u64 section = 0x00) const; + /** * @brief Get the colors of all patterns that overlap with the given address * @param address Address to check diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 42ca77d4..cd91bb44 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -51,6 +51,7 @@ namespace pl::core { return intLiteral.size(); } + std::optional Lexer::parseCharacter() { const char& c = m_sourceCode[m_cursor++]; if (c == '\\') { @@ -414,7 +415,7 @@ namespace pl::core { separatorToken != Token::Separators().end()) { m_cursor++; return makeTokenAt(separatorToken->second, location, m_cursor - begin); - } + } return std::nullopt; } @@ -556,7 +557,7 @@ namespace pl::core { continue; } if(category == '*') { - if(type != '!' && (type != '*' || peek(3) == '/')) { + if (type != '!' && (type != '*' || peek(3) == '/' )) { const auto token = parseMultiLineComment(); if(token.has_value()) addToken(token.value()); @@ -582,7 +583,7 @@ namespace pl::core { continue; } - if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) { + if (c == '#' && (m_tokens.empty() || m_tokens.back().location.line < m_line)) { size_t length = 1; u32 line = m_line; while (isIdentifierCharacter(peek(length))) @@ -592,8 +593,8 @@ namespace pl::core { if (processToken(&Lexer::parseDirectiveName, directiveName)) { Token::Directive directive = get(m_tokens.back().value); if (m_line != line || directive == Token::Directive::Define || directive == Token::Directive::Undef || - peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || - directive == Token::Directive::EndIf) + peek(0) == 0 || directive == Token::Directive::IfDef || directive == Token::Directive::IfNDef || + directive == Token::Directive::EndIf) continue; if (skipLineEnding()) continue; @@ -621,7 +622,7 @@ namespace pl::core { addToken(string.value()); continue; } - } else if (c == '\'') { + } else if(c == '\'') { auto location = this->location(); const auto begin = m_cursor; m_cursor++; // skip opening ' From b1872f689111b9c4d93bf90a447a74bfeedb8473 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 18:28:23 +1000 Subject: [PATCH 12/16] Remove unwanted formatting changes --- lib/include/pl/pattern_language.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 84e73bb4..97a816bf 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -74,7 +74,6 @@ namespace pl { * @return token stream */ [[nodiscard]] std::optional> preprocessString(const std::string &code, const std::string &source); - /** From b4fab847b06527542e6489c331495d0d0b3b3be7 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 18:30:23 +1000 Subject: [PATCH 13/16] Remove unwanted formatting changes --- lib/source/pl/core/lexer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index cd91bb44..0f72c203 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -51,7 +51,7 @@ namespace pl::core { return intLiteral.size(); } - + std::optional Lexer::parseCharacter() { const char& c = m_sourceCode[m_cursor++]; if (c == '\\') { From 6dc69fa13202594ea58a85e79c548786d31f95ac Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 18:59:06 +1000 Subject: [PATCH 14/16] Fixed potential buffer overrun --- lib/include/pl/core/lexer.hpp | 23 +---------------------- lib/source/pl/core/lexer.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index cb92b8b2..d661c786 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -56,28 +56,7 @@ namespace pl::core { static Token makeTokenAt(const Token& token, Location& location, size_t length = 1); void addToken(const Token& token); - bool skipLineEnding() { - char ch = m_sourceCode[m_cursor]; - if (ch == '\n') { - m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); - m_tabCompensation = 0; - m_line++; - m_lineBegin = ++m_cursor; - return true; - } - else if (ch == '\r') { - m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); - m_tabCompensation = 0; - m_line++; - ch = m_sourceCode[++m_cursor]; - if (ch == '\n') - ++m_cursor; - m_lineBegin = m_cursor; - return true; - } - - return false; - } + bool skipLineEnding(); static constexpr int tabsize = 4; diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 0f72c203..400691e9 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -51,6 +51,30 @@ namespace pl::core { return intLiteral.size(); } + inline bool Lexer::skipLineEnding() { + char ch = m_sourceCode[m_cursor]; + if (ch == '\n') { + m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); + m_tabCompensation = 0; + m_line++; + m_lineBegin = ++m_cursor; + return true; + } + else if (ch == '\r') { + m_longestLineLength = std::max(m_longestLineLength, m_cursor-m_lineBegin+m_tabCompensation); + m_tabCompensation = 0; + m_line++; + if (++m_cursor Lexer::parseCharacter() { const char& c = m_sourceCode[m_cursor++]; From fefa424edb32a3ba47f321c94b009e3b406f3525 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sat, 12 Jul 2025 21:48:14 +1000 Subject: [PATCH 15/16] Fixed bug while investigating feedback from @paxcut --- lib/source/pl/core/lexer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/source/pl/core/lexer.cpp b/lib/source/pl/core/lexer.cpp index 400691e9..8670aec5 100644 --- a/lib/source/pl/core/lexer.cpp +++ b/lib/source/pl/core/lexer.cpp @@ -371,7 +371,7 @@ namespace pl::core { while (true) { skipLineEnding(); - if(peek(1) == '\x00') { + if(m_cursor>=m_sourceCode.size() || peek(0)=='\x00') { m_errorLength = 1; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; @@ -397,7 +397,7 @@ namespace pl::core { while(true) { skipLineEnding(); - if(peek(1) == '\x00') { + if(m_cursor>=m_sourceCode.size() || peek(0)=='\x00') { m_errorLength = 2; error("Unexpected end of file while parsing multi line doc comment"); return std::nullopt; From c4373e72286abce4dbd1ab48bfd4ccb04ca67241 Mon Sep 17 00:00:00 2001 From: "shewitt.au" Date: Sun, 13 Jul 2025 23:22:18 +1000 Subject: [PATCH 16/16] Longest line length --- lib/include/pl/core/lexer.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/include/pl/core/lexer.hpp b/lib/include/pl/core/lexer.hpp index d661c786..04775c10 100644 --- a/lib/include/pl/core/lexer.hpp +++ b/lib/include/pl/core/lexer.hpp @@ -21,10 +21,7 @@ namespace pl::core { hlp::CompileResult> lex(const api::Source *source); size_t getLongestLineLength() const { - // 'getLongestLineLength' is used by the pattern editor to control - // the x-scrolling range. Adding two makes the whole longest line visible. - // Not sure why we have to do this. - return m_longestLineLength+2; + return m_longestLineLength; // Does not include line endings } private: