From 8911702c0d2799eb42073d9710f84af7dc6db67d Mon Sep 17 00:00:00 2001 From: erick-alcachofa Date: Thu, 25 Dec 2025 11:41:08 -0600 Subject: [PATCH] refactor(parser): overhaul parsing logic and enhance error reporting Signed-off-by: erick-alcachofa Major refactoring of the Parser and Tokenizer components to improve code maintainability, strengthen error messaging, and streamline AST generation. This version intentionally focuses on top-level declarations, with statement parsing stubbed for the next development phase. - **Path Sanitization**: Added `sanitizePath` to extract filenames from input paths, ensuring consistent `unitName` identification regardless of directory depth. - **Improved Output**: Wrapped AST string output in Markdown code blocks and added a commented-out entry for the new DOT graph visualization. - **Unified Consumption**: Replaced manual token checks with a more robust `consume()` method that leverages `peekExpect()` for centralized error handling. - **New Predicates**: Introduced `match()` and `matchAndConsume()` helpers to handle optional tokens and branching logic without redundant peek/consume calls. - **Exception Handling**: Standardized the use of `langException` across all parsing functions, providing more descriptive "Expected X, found Y" messages. - **Declarations**: Refactored `parseTopLevelDeclaration` and sub-parsers (Module, Struct, Enum, Fn) to use the new matching patterns. - **Looping Logic**: Replaced recursive-style parsing loops with `while(keepParsing)` iterative blocks to prevent stack depth issues and clarify termination conditions (e.g., finding a closing brace or failing to find a comma). - **Namespaced Identifiers**: Rewrote `parseNamespacedIdentifier` to correctly handle multi-part paths (`A::B::C`) and edge cases. - **Generic Support**: Improved handling of generic parameter and argument lists, ensuring strict enforcement of delimiters like `<` and `>`. - **Contextual Errors**: Updated `peekExpect` to accept a custom `message` string, allowing the parser to describe *what* it was looking for (e.g., "Expected ';'"). - **Token Lookahead**: Enhanced `peek` and `peekExpect` reliability with better bounds checking and buffer management. - **Removed `lib/src/Parser/AST/AST.cpp`**: Deleted the monolithic AST stringification file in favor of the previously introduced modular implementations. - **Build System**: Updated `.gitignore` to ignore `cpm-package-lock.cmake`. --- .gitignore | 2 + frontend/src/main.cpp | 16 +- lib/include/artichoke/Parser/Parser.hpp | 23 +- lib/include/artichoke/Tokenizer/Tokenizer.hpp | 6 +- lib/src/Parser/AST/AST.cpp | 1742 ----------------- lib/src/Parser/Declarations.cpp | 1021 ++++------ lib/src/Parser/Parser.cpp | 20 +- lib/src/Parser/Statements.cpp | 14 +- lib/src/Parser/Types.cpp | 283 +-- lib/src/Tokenizer/Tokenizer.cpp | 19 +- 10 files changed, 581 insertions(+), 2565 deletions(-) delete mode 100644 lib/src/Parser/AST/AST.cpp diff --git a/.gitignore b/.gitignore index 5a3697e..b368a8f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ build/** install/** +cpm-package-lock.cmake + TODO.md diff --git a/frontend/src/main.cpp b/frontend/src/main.cpp index 73cea02..1f689a0 100644 --- a/frontend/src/main.cpp +++ b/frontend/src/main.cpp @@ -1,8 +1,15 @@ #include #include +#include #include +std::string sanitizePath(std::string_view path) { + namespace fs = std::filesystem; + fs::path p{ path }; + return p.filename().string(); +} + int main(int argc, char **argv) { using namespace arti::lang; @@ -12,7 +19,7 @@ int main(int argc, char **argv) { } std::ifstream file; - file.open(argv[1]); + file.open(sanitizePath(argv[1])); if (! file.is_open()) { std::println("Failed to open file {}", argv[1]); @@ -22,7 +29,7 @@ int main(int argc, char **argv) { std::string buffer{ std::istreambuf_iterator(file), std::istreambuf_iterator() }; - auto parser = Parser{ buffer }; + auto parser = Parser{ sanitizePath(argv[1]), buffer }; auto res = parser.parse(); @@ -40,5 +47,10 @@ int main(int argc, char **argv) { auto ast = std::move(res).value(); + std::println("# AST"); + std::println("```markdown"); std::println("{}", ast::toString(ast)); + std::println("```"); + + // std::println("{}", ast::toDot(ast)); } diff --git a/lib/include/artichoke/Parser/Parser.hpp b/lib/include/artichoke/Parser/Parser.hpp index 14015ec..34a970a 100644 --- a/lib/include/artichoke/Parser/Parser.hpp +++ b/lib/include/artichoke/Parser/Parser.hpp @@ -126,22 +126,13 @@ namespace arti::lang { Expected parseInfLoopStatement(); - Expected consume(TokenV type, std::string_view expected_name) { - auto peeked = tokenizer.peek(); + Expected consume(TokenV type, std::string_view message) { + auto peeked = tokenizer.peekExpect(type, message); if (! peeked) { return Unexpected<>{ std::move(peeked).error() }; } - if (peeked->value != type) { - return langException( - peeked->line, - peeked->column, - toString(*peeked), - expected_name - ); - } - std::ignore = tokenizer.consume(); return peeked; @@ -163,6 +154,16 @@ namespace arti::lang { return true; } + Expected match(TokenV type, std::size_t offset = 0) { + auto peeked = tokenizer.peek(offset); + + if (! peeked) { + return Unexpected<>{ std::move(peeked).error() }; + } + + return (peeked->value == type); + } + private: std::string unitName; std::string sourceCode; diff --git a/lib/include/artichoke/Tokenizer/Tokenizer.hpp b/lib/include/artichoke/Tokenizer/Tokenizer.hpp index 33c5485..73b474c 100644 --- a/lib/include/artichoke/Tokenizer/Tokenizer.hpp +++ b/lib/include/artichoke/Tokenizer/Tokenizer.hpp @@ -25,7 +25,11 @@ namespace arti::lang { Expected consume(std::size_t n = 1) noexcept; Expected peek(std::size_t n = 0) noexcept; - Expected peekExpect(std::size_t n, TokenV tokenType) noexcept; + Expected peekExpect( + TokenV tokenType, + std::string_view message = "", + std::size_t n = 0 + ) noexcept; bool finished() const noexcept; diff --git a/lib/src/Parser/AST/AST.cpp b/lib/src/Parser/AST/AST.cpp deleted file mode 100644 index c7e156c..0000000 --- a/lib/src/Parser/AST/AST.cpp +++ /dev/null @@ -1,1742 +0,0 @@ -#include - -#include -#include -#include - -#include - -namespace arti::lang::ast { - std::string createPadding(std::size_t padding) { - return std::views::repeat(' ') - | std::views::take(padding) - | std::ranges::to(); - } - - std::string toString(const ModuleDeclNode &, std::size_t); - std::string toString(const StructDeclNode &, std::size_t); - std::string toString(const EnumDeclNode &, std::size_t); - std::string toString(const FunctionDeclNode &, std::size_t); - std::string toString(const ImportDeclNode &, std::size_t); - std::string toString(const AliasDeclNode &, std::size_t); - std::string toString(const EnumMemberNode &, std::size_t); - std::string toString(const StructMemberNode &, std::size_t); - std::string toString(const GenericParamNode &, std::size_t); - std::string toString(const FunctionParamNode &, std::size_t); - std::string toString(const TopLevelDeclNode &, std::size_t); - std::string toString(const ModuleInnerDeclNode &, std::size_t); - std::string toString(const TypeNode &, std::size_t); - std::string toString(const GenericTypeNode &, std::size_t); - std::string toString(const IdentifierTypeNode &, std::size_t); - std::string toString(const NamespacedTypeNode &, std::size_t); - std::string toString(const NamespacedIdentifierNode &, std::size_t); - std::string toString(const TypeExpressionNode &, std::size_t); - std::string toString(const CharLtrlNode &, std::size_t); - std::string toString(const NullLtrlNode &, std::size_t); - std::string toString(const StringLtrlNode &, std::size_t); - std::string toString(const FloatLtrlNode &, std::size_t); - std::string toString(const IntegerLtrlNode &, std::size_t); - std::string toString(const BooleanLtrlNode &, std::size_t); - std::string toString(const StructLtrlNode &, std::size_t); - std::string toString(const SliceLtrlNode &, std::size_t); - std::string toString(const StructLtrlNamedFieldInitNode &, std::size_t); - std::string toString(const StructLtrlPositionalInitNode &, std::size_t); - std::string toString(const StructLtrlNamedInitializerNode &, std::size_t); - std::string toString(const StructLtrlPositionalInitializerNode &,std::size_t); - std::string toString(const StructLtrlInitializerNode &, std::size_t); - std::string toString(const IdentifierExprNode &, std::size_t); - std::string toString(const UnaryExprNode &, std::size_t); - std::string toString(const BinaryExprNode &, std::size_t); - std::string toString(const AssignExprNode &, std::size_t); - std::string toString(const CompoundAssignExprNode &, std::size_t); - std::string toString(const FunctionCallExprNode &, std::size_t); - std::string toString(const SliceAccessExprNode &, std::size_t); - std::string toString(const SliceRangeExprNode &, std::size_t); - std::string toString(const MemberAccessExprNode &, std::size_t); - std::string toString(const PointerAccessExprNode &, std::size_t); - std::string toString(const ScopeAccessExprNode &, std::size_t); - std::string toString(const ReflectionExprNode &, std::size_t); - std::string toString(const SliceCreationExprNode &, std::size_t); - std::string toString(const SliceLengthExprNode &, std::size_t); - std::string toString(const SlicePtrExprNode &, std::size_t); - std::string toString(const ExpressionNode &, std::size_t); - std::string toString(const CodeBlockStmtNode &, std::size_t); - std::string toString(const VariableStmtNode &, std::size_t); - std::string toString(const IfStmtNode &, std::size_t); - std::string toString(const ElseStmtNode &, std::size_t); - std::string toString(const DeferStmtNode &, std::size_t); - std::string toString(const ErrDeferStmtNode &, std::size_t); - std::string toString(const ReturnStmtNode &, std::size_t); - std::string toString(const BreakStmtNode &, std::size_t); - std::string toString(const ContinueStmtNode &, std::size_t); - std::string toString(const MatchStmtNode &, std::size_t); - std::string toString(const SwitchStmtNode &, std::size_t); - std::string toString(const CForStmtNode &, std::size_t); - std::string toString(const RangeForStmtNode &, std::size_t); - std::string toString(const WhileStmtNode &, std::size_t); - std::string toString(const DoWhileStmtNode &, std::size_t); - std::string toString(const InfLoopStmtNode &, std::size_t); - std::string toString(const ExpressionStmtNode &, std::size_t); - std::string toString(const MatchCaseNode &, std::size_t); - std::string toString(const SwitchCaseNode &, std::size_t); - std::string toString(const StatementNode &, std::size_t); - std::string toString(const ElseBranchNode &, std::size_t); - std::string toString(const DeferableNode &, std::size_t); - std::string toString(const PreLoopStmtNode &, std::size_t); - std::string toString(UnaryOperator op); - std::string toString(BinaryOperator op); - std::string toString(CompoundAssignOperator op); - - std::string toString(const AST &tree, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - std::vector childs; - - ss << std::format("- CompilationUnit {}", tree->unitName); - - for (const auto &d : tree->declarations) { - ss << std::format("\n{} - {}", paddingStr, toString(d, padding + 2)); - } - - return ss.str(); - } - - std::string toString(const TopLevelDeclNode &tlDecl, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const ModuleDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const StructDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const EnumDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const FunctionDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ImportDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const AliasDeclNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, tlDecl); - } - - std::string toString(const ModuleDeclNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "Module {} {}", - toString(node->name, padding), - node->isExported ? "[exported]" : "" - ); - - if (! node->aliasDeclarations.empty()) { - ss << std::format("\n{} - AliasedTypes", paddingStr); - - for (const auto &al : node->aliasDeclarations) { - ss - << std::format("\n{} - {}", paddingStr, toString(al, padding + 4)); - } - } - - if (! node->innerDeclarations.empty()) { - ss << std::format("\n{} - InnerDeclarations", paddingStr); - - for (const auto &id : node->innerDeclarations) { - ss - << std::format("\n{} - {}", paddingStr, toString(id, padding + 4)); - } - } - - if (! node->childModules.empty()) { - ss << std::format("\n{} - ChildModules", paddingStr); - - for (const auto &cm : node->childModules) { - ss - << std::format("\n{} - {}", paddingStr, toString(cm, padding + 4)); - } - } - - return ss.str(); - } - - std::string toString(const StructDeclNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "Struct {} {}", - node->name, - node->isExported ? "[exported]" : "" - ); - - if (! node->genericParams.empty()) { - ss << std::format("\n{} - GenericParams", paddingStr); - - for (const auto &gp : node->genericParams) { - ss - << std::format("\n{} - {}", paddingStr, toString(gp, padding + 4)); - } - } - - if (! node->structMembers.empty()) { - ss << std::format("\n{} - FieldMembers", paddingStr); - - for (const auto &sm : node->structMembers) { - ss - << std::format("\n{} - {}", paddingStr, toString(sm, padding + 4)); - } - } - - return ss.str(); - } - - std::string toString(const EnumDeclNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "Enum {} {}", - node->name, - node->isExported ? "[exported]" : "" - ); - - if (! node->genericParams.empty()) { - ss << std::format("\n{} - GenericParams", paddingStr); - - for (const auto &gp : node->genericParams) { - ss - << std::format("\n{} - {}", paddingStr, toString(gp, padding + 4)); - } - } - - ss << std::format("\n{} - EnumValues", paddingStr); - - for (const auto &em : node->enumMembers) { - ss << std::format("\n{} - {}", paddingStr, toString(em, padding + 4)); - } - - return ss.str(); - } - - std::string toString(const FunctionDeclNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "Function {} {}", - node->name, - node->isExported ? "[exported]" : "" - ); - - if (node->returnType) { - ss << std::format("\n{} - ReturnType", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->returnType, padding + 4) - ); - } - - if (! node->genericParams.empty()) { - ss << std::format("\n{} - GenericParams", paddingStr); - - for (const auto &gp : node->genericParams) { - ss - << std::format("\n{} - {}", paddingStr, toString(gp, padding + 4)); - } - } - - if (! node->functionParams.empty()) { - ss << std::format("\n{} - FunctionParams", paddingStr); - - for (const auto &gp : node->functionParams) { - ss - << std::format("\n{} - {}", paddingStr, toString(gp, padding + 4)); - } - } - - ss << std::format("\n{} - FunctionBody", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->functionBody, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const ImportDeclNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "Import {}{}", - toString(node->importTarget, padding), - node->importAll ? "::*" : "" - ); - - return ss.str(); - } - - std::string toString(const AliasDeclNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "Alias {}", - node->alias - ); - - ss << std::format("\n{} - AliasedType", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->target, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const EnumMemberNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "EnumMember {}", - node->name - ); - - if (node->type) { - ss << std::format("\n{} - StorageType", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->type, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const StructMemberNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << std::format( - "StructMember {}", - node->name - ); - - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->type, padding + 2) - ); - - return ss.str(); - } - - std::string toString(const GenericParamNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("typename {}", node->name); - } - - std::string toString(const FunctionParamNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - if (node->isThis) { - ss << std::format( - "This", - paddingStr - ); - } - else { - ss << std::format( - "Param {}", - node->name - ); - } - - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->type, padding + 2) - ); - - return ss.str(); - } - - std::string toString(const ModuleInnerDeclNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const StructDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const EnumDeclNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const FunctionDeclNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const TypeNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "Type"; - - if (!node->qualifiers.empty()) { - ss << std::format("\n{} - Qualifiers", paddingStr); - - for (const auto &q : node->qualifiers) { - switch(q) { - case TypeQualifier::Pointer: - ss << std::format("\n{} - Pointer (*)", paddingStr); - break; - case TypeQualifier::Slice: - ss << std::format("\n{} - Slice ([])", paddingStr); - break; - case TypeQualifier::Mutable: - ss << std::format("\n{} - Mutable ($)", paddingStr); - break; - case TypeQualifier::Optional: - ss << std::format("\n{} - Optional (?)", paddingStr); - break; - default: - break; - } - } - } - - ss << std::format("\n{} - BaseType", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->baseType, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const GenericTypeNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "GenericType"; - ss << std::format("\n{} - BaseType", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->baseType, padding + 4) - ); - - if (!node->genericArgs.empty()) { - ss << std::format("\n{} - GenericArgs", paddingStr); - for (const auto &ga : node->genericArgs) { - ss - << std::format("\n{} - {}", paddingStr, toString(ga, padding + 4)); - } - } - - return ss.str(); - } - - std::string toString(const IdentifierTypeNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "IdentifierType"; - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->typeName, padding + 2) - ); - - return ss.str(); - } - - std::string toString(const NamespacedTypeNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "NamespacedType"; - - ss << std::format("\n{} - BaseType", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->baseType, padding + 4) - ); - - ss << std::format("\n{} - TypeName", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - node->typeName - ); - - return ss.str(); - } - - std::string - toString(const NamespacedIdentifierNode &node, std::size_t padding) { - std::ignore = padding; - return node->identParts - | std::views::join_with(std::string_view{"::"}) - | std::ranges::to(); - } - - std::string toString(const TypeExpressionNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const GenericTypeNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const IdentifierTypeNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const NamespacedTypeNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const CharLtrlNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("CharLiteral '{}'", node->value); - } - - std::string toString(const NullLtrlNode &node, std::size_t padding) { - std::ignore = node; - std::ignore = padding; - return std::format("NullLiteral 'null'"); - } - - std::string toString(const StringLtrlNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("StringLiteral \"{}\"", node->value); - } - - std::string toString(const FloatLtrlNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("FloatLiteral {}", node->value); - } - - std::string toString(const IntegerLtrlNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("IntegerLiteral {}", node->value); - } - - std::string toString(const BooleanLtrlNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("BooleanLiteral {}", node->value ? "true" : "false"); - } - - std::string toString(const StructLtrlNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "StructLiteral"; - - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->type, padding + 2) - ); - - if (node->initializer) { - ss << std::format("\n{} - Elements", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->initializer, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const SliceLtrlNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SliceLiteral"; - - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->type, padding + 4) - ); - - if (node->initializer) { - ss << std::format("\n{} - Elements", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->initializer, padding + 4) - ); - } - - return ss.str(); - } - - std::string - toString(const StructLtrlNamedFieldInitNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "FieldInitializer"; - - ss << std::format("\n{} - Field '{}'", paddingStr, node->fieldName); - ss << std::format("\n{} - Value", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->fieldValue, padding + 4) - ); - - return ss.str(); - } - - std::string - toString(const StructLtrlPositionalInitNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "PositionalInitializer"; - - ss << std::format("\n{} - Value", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->fieldValue, padding + 4) - ); - - return ss.str(); - } - - std::string - toString(const StructLtrlNamedInitializerNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "InitializerList"; - ss << std::format("\n{} - Elements", paddingStr); - - for (const auto &ele : node->fields) { - ss << std::format( - "\n{} - {}", - paddingStr, - toString(ele, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString( - const StructLtrlPositionalInitializerNode &node, - std::size_t padding - ) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "InitializerList"; - ss << std::format("\n{} - Elements", paddingStr); - - for (const auto &[idx, ele] : std::views::enumerate(node->fields)) { - ss << std::format( - "\n{} - [{}] {}", - paddingStr, - idx, - toString(ele, padding + 4) - ); - } - - return ss.str(); - } - - std::string - toString(const StructLtrlInitializerNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const StructLtrlNamedInitializerNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const StructLtrlPositionalInitializerNode &node) - -> std::string { return toString(node, padding); }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const IdentifierExprNode &node, std::size_t padding) { - std::ignore = padding; - return std::format("Identifier {}", node->identifierName); - } - - std::string toString(const UnaryExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "UnaryExpression"; - ss << std::format("\n{} - Operator {}", paddingStr, toString(node->op)); - - ss << std::format("\n{} - Operand", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->right, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const BinaryExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "BinaryExpression"; - ss << std::format("\n{} - Operator {}", paddingStr, toString(node->op)); - - ss << std::format("\n{} - Left", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->left, padding + 4) - ); - - ss << std::format("\n{} - Right", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->right, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const AssignExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "AssignExpression"; - ss << std::format("\n{} - Left", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->left, padding + 4) - ); - - ss << std::format("\n{} - Right", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->right, padding + 4) - ); - - return ss.str(); - } - - std::string - toString(const CompoundAssignExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "CompoundAssignExpression"; - ss << std::format("\n{} - Operator {}", paddingStr, toString(node->op)); - - ss << std::format("\n{} - Left", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->left, padding + 4) - ); - - ss << std::format("\n{} - Right", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->left, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const FunctionCallExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "FunctionCallExpression"; - ss << std::format("\n{} - Callee", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->callee, padding + 4) - ); - - if (! node->arguments.empty()) { - ss << std::format("\n{} - Arguments", paddingStr); - - for (const auto &arg : node->arguments) { - ss << std::format( - "\n{} - {}", - paddingStr, - toString(arg, padding + 4) - ); - } - } - - return ss.str(); - } - - std::string toString(const SliceAccessExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SliceAccessExpression"; - ss << std::format("\n{} - Slice", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->slice, padding + 4) - ); - - ss << std::format("\n{} - Index", paddingStr); - - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->index, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const SliceRangeExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SliceRangeExpression"; - ss << std::format("\n{} - Slice", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->slice, padding + 4) - ); - - if (node->start) { - ss << std::format("\n{} - Start", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->start, padding + 4) - ); - } - - if (node->end) { - ss << std::format("\n{} - End", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->end, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const MemberAccessExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "MemberAccessExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->object, padding + 4) - ); - - ss << std::format("\n{} - Member '{}'", paddingStr, node->memberName); - - return ss.str(); - } - - std::string toString(const PointerAccessExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "PointerAccessExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->object, padding + 4) - ); - - ss << std::format("\n{} - Member '{}'", paddingStr, node->memberName); - - return ss.str(); - } - - std::string toString(const ScopeAccessExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ScopeAccessExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->scope, padding + 4) - ); - - if (! node->genericParams.empty()) { - ss << std::format("\n{} - GenericParams", paddingStr); - - for (const auto &gp : node->genericParams) { - ss - << std::format("\n{} - {}", paddingStr, toString(gp, padding + 4)); - } - } - - ss << std::format("\n{} - Member '{}'", paddingStr, node->memberName); - - return ss.str(); - } - - std::string toString(const ReflectionExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ReflectionExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->object, padding + 4) - ); - - if (node->attribute) { - ss - << std::format("\n{} - Attribute '{}'", paddingStr, *node->attribute); - } - - return ss.str(); - } - - std::string toString(const SliceCreationExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SliceCreationExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->object, padding + 4) - ); - - ss << std::format("\n{} - Length", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->length, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const SliceLengthExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SliceLengthExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->object, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const SlicePtrExprNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SlicePtrExpression"; - ss << std::format("\n{} - Object", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->object, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const ExpressionNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const CharLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const NullLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const StringLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const FloatLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const IntegerLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const BooleanLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const StructLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SliceLtrlNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const IdentifierExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const UnaryExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const BinaryExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const AssignExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const CompoundAssignExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const FunctionCallExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SliceAccessExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SliceRangeExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const MemberAccessExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const PointerAccessExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ScopeAccessExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SliceCreationExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SliceLengthExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SlicePtrExprNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ReflectionExprNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const CodeBlockStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "CodeBlock"; - - for (const auto &gp : node->statements) { - ss << std::format("\n{} - {}", paddingStr, toString(gp, padding + 2)); - } - - return ss.str(); - } - - std::string toString(const VariableStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "VariableDeclaration"; - ss << std::format("\n{} - Name '{}'", paddingStr, node->name); - ss << std::format( - "\n{} - Mutability '{}'", - paddingStr, - node->mutability == Mutability::Mutable ? "let" : "def" - ); - - if (node->type) { - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->type, padding + 4) - ); - } - - if (node->initializer) { - ss << std::format("\n{} - Initializer", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->initializer, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const IfStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "IfStatement"; - - if (node->unwrappedVar) { - ss << std::format( - "\n{} - UnwrappedVar '{}'", - paddingStr, - *node->unwrappedVar - ); - } - - ss << std::format("\n{} - Condition", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->condition, padding + 4) - ); - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - if (node->elseBranch) { - ss << std::format("\n{} - ElseBranch", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->elseBranch, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const ElseStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ElseStatement"; - - if (node->unwrappedVar) { - ss << std::format( - "\n{} - UnwrappedVar '{}'", - paddingStr, - *node->unwrappedVar - ); - } - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const DeferStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "DeferStatement"; - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const ErrDeferStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ErrDeferStatement"; - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const ReturnStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ReturnStatement"; - - if (node->value) { - ss << std::format("\n{} - Expression", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->value, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const BreakStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "BreakStatement"; - - if (node->label) { - ss << std::format("\n{} - Label '{}'", paddingStr, *node->label); - } - - return ss.str(); - } - - std::string toString(const ContinueStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ContinueStatement"; - - if (node->label) { - ss << std::format("\n{} - Label '{}'", paddingStr, *node->label); - } - - return ss.str(); - } - - std::string toString(const MatchStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "MatchStatement"; - - ss << std::format("\n{} - Value", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->value, padding + 4) - ); - - if (!node->matchCases.empty()) { - ss << std::format("\n{} - Cases", paddingStr); - for (const auto &cas : node->matchCases) { - ss << std::format( - "\n{} - {}", - paddingStr, - toString(cas, padding + 4) - ); - } - } - - if (node->defaultCase) { - ss << std::format("\n{} - DefaultCase", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->defaultCase, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const SwitchStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "SwitchStatement"; - - ss << std::format("\n{} - Value", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->value, padding + 4) - ); - - if (!node->switchCases.empty()) { - ss << std::format("\n{} - Cases", paddingStr); - for (const auto &cas : node->switchCases) { - ss << std::format( - "\n{} - {}", - paddingStr, - toString(cas, padding + 4) - ); - } - } - - if (node->defaultCase) { - ss << std::format("\n{} - DefaultCase", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->defaultCase, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const CForStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "CForStatement"; - - if (node->label) { - ss << std::format( - "\n{} - Label '{}'", - paddingStr, - *node->label - ); - } - - if (node->preLoop) { - ss << std::format("\n{} - PreLoop", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->preLoop, padding + 4) - ); - } - - ss << std::format("\n{} - Condition", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->condition, padding + 4) - ); - - if (node->postLoop) { - ss << std::format("\n{} - PostLoop", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->postLoop, padding + 4) - ); - } - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const RangeForStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ForRangeStatement"; - - if (node->label) { - ss << std::format( - "\n{} - Label '{}'", - paddingStr, - *node->label - ); - } - - ss << std::format( - "\n{} - Variable '{}'{}", - paddingStr, - node->varName, - node->varMutability == Mutability::Mutable - ? " [mut]" - : "" - ); - - ss << std::format("\n{} - Range", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->range, padding + 4) - ); - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const WhileStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "WhileStatement"; - - if (node->label) { - ss << std::format( - "\n{} - Label '{}'", - paddingStr, - *node->label - ); - } - - if (node->unwrappedVar) { - ss << std::format( - "\n{} - UnwrappedVar '{}'", - paddingStr, - *node->unwrappedVar - ); - } - - ss << std::format("\n{} - Condition", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->condition, padding + 4) - ); - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - if (node->elseBranch) { - ss << std::format("\n{} - ElseBranch", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(*node->elseBranch, padding + 4) - ); - } - - return ss.str(); - } - - std::string toString(const DoWhileStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "DoWhileStatement"; - - if (node->label) { - ss << std::format( - "\n{} - Label '{}'", - paddingStr, - *node->label - ); - } - - ss << std::format("\n{} - Condition", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->condition, padding + 4) - ); - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const InfLoopStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "InfLoopStatement"; - - if (node->label) { - ss << std::format( - "\n{} - Label '{}'", - paddingStr, - *node->label - ); - } - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const ExpressionStmtNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "ExpressionStatement"; - - ss << std::format("\n{} - Expression", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->expression, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const MatchCaseNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "MatchCase"; - - if (node->unwrappedVar) { - ss << std::format( - "\n{} - UnwrappedVar '{}'", - paddingStr, - *node->unwrappedVar - ); - } - - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->matchType, padding + 2) - ); - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const SwitchCaseNode &node, std::size_t padding) { - std::stringstream ss; - auto paddingStr = createPadding(padding); - - ss << "MatchCase"; - - ss << std::format("\n{} - Matcher", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->matchExpr, padding + 4) - ); - - ss << std::format("\n{} - Body", paddingStr); - ss << std::format( - "\n{} - {}", - paddingStr, - toString(node->body, padding + 4) - ); - - return ss.str(); - } - - std::string toString(const StatementNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const VariableStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const IfStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const DeferStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ErrDeferStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ReturnStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const BreakStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ContinueStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const MatchStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const SwitchStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const CForStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const RangeForStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const WhileStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const DoWhileStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const InfLoopStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ExpressionStmtNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const ElseBranchNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const ElseStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const IfStmtNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const DeferableNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const ExpressionStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const CodeBlockStmtNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(const PreLoopStmtNode &node, std::size_t padding) { - auto visitor = OverloadSet{ - [padding](const VariableStmtNode &node) -> std::string { - return toString(node, padding); - }, - [padding](const ExpressionStmtNode &node) -> std::string { - return toString(node, padding); - }, - }; - - return std::visit(visitor, node); - } - - std::string toString(UnaryOperator op) { - using enum UnaryOperator; - - switch (op) { - case Not: return "Not (!)"; - case Minus: return "Minus (-)"; - case BitNot: return "BitNot (~)"; - case Ampersand: return "Ampersand (&)"; - case Star: return "Star (*)"; - default: std::unreachable(); break; - } - - std::unreachable(); - } - - std::string toString(BinaryOperator op) { - using enum BinaryOperator; - - switch (op) { - case Equal: return "Equal (==)"; - case NotEqual: return "NotEqual (!=)"; - case GreaterThan: return "GreaterThan (>)"; - case LessThan: return "LessThan (<)"; - case GreaterEqual: return "GreaterEqual (>=)"; - case LessEqual: return "LessEqual (<=)"; - case BitAnd: return "BitAnd (&)"; - case BitXor: return "BitXor (^)"; - case BitOr: return "BitOr (|)"; - case LeftShift: return "LeftShift (<<)"; - case RightShift: return "RightShift (>>)"; - case Adition: return "Adition (+)"; - case Substraction: return "Substraction (-)"; - case Multiplication: return "Multiplication (*)"; - case Division: return "Division (/)"; - case Modulo: return "Modulo (%)"; - case BoolAnd: return "BoolAnd (&&)"; - case BoolOr: return "BoolOr (||)"; - default: std::unreachable(); break; - } - - std::unreachable(); - } - - std::string toString(CompoundAssignOperator op) { - using enum CompoundAssignOperator; - - switch (op) { - case Addition: return "Addition (+)"; - case Substraction: return "Substraction (-)"; - case Multiplication: return "Multiplication (*)"; - case Division: return "Division (/)"; - case Modulo: return "Modulo (%)"; - case BitAnd: return "BitAnd (&)"; - case BitOr: return "BitOr (|)"; - case LeftShift: return "LeftShift (<<)"; - case RightShift: return "RightShift (>>)"; - case BoolAnd: return "BoolAnd (&&)"; - case BoolOr: return "BoolOr (||)"; - default: std::unreachable(); break; - } - - std::unreachable(); - } - -} // namespace arti::lang::ast diff --git a/lib/src/Parser/Declarations.cpp b/lib/src/Parser/Declarations.cpp index 85810d7..67be10e 100644 --- a/lib/src/Parser/Declarations.cpp +++ b/lib/src/Parser/Declarations.cpp @@ -4,24 +4,21 @@ namespace arti::lang { Expected> Parser::parseTopLevelDeclaration() { - auto peekToken = tokenizer.peek(); - bool exportable = false; + if (auto exported = matchAndConsume(TokenV::kwExport); ! exported) { + return Unexpected<>{ std::move(exported).error() }; + } + else if (exported.value()) { + exportable = true; + } + + auto peekToken = tokenizer.peek(); + if (! peekToken) { return Unexpected<>{ std::move(peekToken).error() }; } - if (peekToken->value == TokenV::kwExport) { - exportable = true; - std::ignore = tokenizer.consume(); - peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected<>{ std::move(peekToken).error() }; - } - } - if (peekToken->value == TokenV::kwImport) { if (exportable) { return langException( @@ -32,13 +29,12 @@ namespace arti::lang { ); } - auto node = parseImportDeclaration(); - - if (! node) { + if (auto node = parseImportDeclaration(); ! node) { return Unexpected<>{ std::move(node).error() }; } - - return ast::TopLevelDeclNode{ std::move(node).value() }; + else { + return ast::TopLevelDeclNode{ std::move(node).value() }; + } } else if (peekToken->value == TokenV::kwUsing) { if (exportable) { @@ -50,68 +46,48 @@ namespace arti::lang { ); } - auto node = parseAliasDeclaration(); - - if (! node) { + if (auto node = parseAliasDeclaration(); ! node) { return Unexpected<>{ std::move(node).error() }; } - - return ast::TopLevelDeclNode{ std::move(node).value() }; + else { + return ast::TopLevelDeclNode{ std::move(node).value() }; + } } else if (peekToken->value == TokenV::kwModule) { - auto node = parseModuleDeclaration(); - - if (! node) { + if (auto node = parseModuleDeclaration(); ! node) { return Unexpected<>{ std::move(node).error() }; } - - (*node)->isExported = exportable; - - return ast::TopLevelDeclNode{ std::move(node).value() }; + else { + (*node)->isExported = exportable; + return ast::TopLevelDeclNode{ std::move(node).value() }; + } } else if (peekToken->value == TokenV::kwStruct) { - auto node = parseStructDeclaration(); - - if (! node) { + if (auto node = parseStructDeclaration(); ! node) { return Unexpected<>{ std::move(node).error() }; } - - (*node)->isExported = exportable; - - return ast::TopLevelDeclNode{ std::move(node).value() }; + else { + (*node)->isExported = exportable; + return ast::TopLevelDeclNode{ std::move(node).value() }; + } } else if (peekToken->value == TokenV::kwEnum) { - auto node = parseEnumDeclaration(); - - if (! node) { + if (auto node = parseEnumDeclaration(); ! node) { return Unexpected<>{ std::move(node).error() }; } - - (*node)->isExported = exportable; - - return ast::TopLevelDeclNode{ std::move(node).value() }; + else { + (*node)->isExported = exportable; + return ast::TopLevelDeclNode{ std::move(node).value() }; + } } else if (peekToken->value == TokenV::kwFn) { - auto node = parseFunctionDeclaration(); - - if (! node) { + if (auto node = parseFunctionDeclaration(); ! node) { return Unexpected<>{ std::move(node).error() }; } - - (*node)->isExported = exportable; - - return ast::TopLevelDeclNode{ std::move(node).value() }; - } - else if (peekToken->value == TokenV::opRSquirly) { - return std::nullopt; - } - else if (peekToken->value != TokenV::tkEOF) { - return langException( - peekToken->line, - peekToken->column, - toString(*peekToken), - "top level declaration" - ); + else { + (*node)->isExported = exportable; + return ast::TopLevelDeclNode{ std::move(node).value() }; + } } return std::nullopt; @@ -119,176 +95,120 @@ namespace arti::lang { Expected Parser::parseImportDeclaration() { auto node = ast::MakeNode(); - node->importAll = false; - auto kw = tokenizer.peek(); - - if (! kw) { + if (auto kw = consume(TokenV::kwImport, "'import' keyword"); ! kw) { return Unexpected<>{ std::move(kw).error() }; } + else { + node->location = { kw->line, kw->column }; + } - node->location.line = kw->line; - node->location.column = kw->column; - - std::ignore = tokenizer.consume(); - - auto target = parseNamespacedIdentifier(); - - if (! target) { + if (auto target = parseNamespacedIdentifier(); ! target) { return Unexpected<>{ std::move(target).error() }; } - - node->importTarget = std::move(target).value(); - - auto peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + else { + node->importTarget = std::move(target).value(); } - if (peekNext->value == TokenV::opAccess) { - auto peekStar = tokenizer.peek(1); - - if (! peekStar) { - return Unexpected<>{ std::move(peekStar).error() }; + if (auto acc = matchAndConsume(TokenV::opAccess); ! acc) { + return Unexpected<>{ std::move(acc).error() }; + } + else if (acc.value()) { + if (auto star = matchAndConsume(TokenV::opStar); ! star) { + return Unexpected<>{ std::move(star).error() }; } + else if (star.value()) { + node->importAll = true; + } + else { + auto star = tokenizer.peek(); - if (peekStar->value != TokenV::opStar) { return langException( - peekStar->line, - peekStar->column, - toString(*peekStar), + star->line, + star->column, + toString(*star), "identifier or '*'" ); } - - node->importAll = true; - std::ignore = tokenizer.consume(2); - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } } - if (peekNext->value != TokenV::opSemicolon) { - return langException( - peekNext->line, - peekNext->column, - toString(*peekNext) - ); + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; } - std::ignore = tokenizer.consume(); - return node; } Expected Parser::parseAliasDeclaration() { auto node = ast::MakeNode(); - auto kw = tokenizer.peek(); - - if (! kw) { + if (auto kw = consume(TokenV::kwUsing, "'using' keyword"); ! kw) { return Unexpected<>{ std::move(kw).error() }; } - - node->location.line = kw->line; - node->location.column = kw->column; - - std::ignore = tokenizer.consume(); - - auto aliased = tokenizer.peek(); - - if (! aliased) { - return Unexpected<>{ std::move(aliased).error() }; + else { + node->location = { kw->line, kw->column }; } - if (aliased->value != TokenV::tkIdentifier) { - return langException( - aliased->line, - aliased->column, - toString(*aliased), - "identifier" - ); + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->alias = ident->strValue; } - std::ignore = tokenizer.consume(); - node->alias = aliased->strValue; - - auto eq = tokenizer.peekExpect(0, TokenV::opAssign); - - if (! eq) { + if (auto eq = consume(TokenV::opAssign, "'='"); ! eq) { return Unexpected{ std::move(eq).error() }; } - std::ignore = tokenizer.consume(); - - auto type = parseType(); - - if (! type) { + if (auto type = parseType(); ! type) { return Unexpected{ std::move(type).error() }; } - - node->target = std::move(type).value(); - - auto semicolon = tokenizer.peekExpect(0, TokenV::opSemicolon); - - if (! semicolon) { - return Unexpected{ std::move(semicolon).error() }; + else { + node->target = std::move(type).value(); } - std::ignore = tokenizer.consume(); + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } return node; } Expected Parser::parseModuleDeclaration() { auto node = ast::MakeNode(); + auto decl = ast::Optional{}; + bool keepParsing = true; - auto kw = tokenizer.peek(); - - if (! kw) { + if (auto kw = consume(TokenV::kwModule, "'module' keyword"); ! kw) { return Unexpected<>{ std::move(kw).error() }; } - - node->location.line = kw->line; - node->location.column = kw->column; - - std::ignore = tokenizer.consume(); - - auto moduleName = parseNamespacedIdentifier(); - - if (! moduleName) { - return Unexpected<>{ std::move(moduleName).error() }; + else { + node->location = { kw->line, kw->column }; } - node->name = std::move(moduleName).value(); - - auto lsquirly = tokenizer.peekExpect(0, TokenV::opLSquirly); - - if (! lsquirly) { - return Unexpected{ std::move(lsquirly).error() }; + if (auto name = parseNamespacedIdentifier(); ! name) { + return Unexpected<>{ std::move(name).error() }; + } + else { + node->name = std::move(name).value(); } - std::ignore = tokenizer.consume(); - - bool keepParsing = true; - auto decl = ast::Optional{}; - + if (auto lsquirly = consume(TokenV::opLSquirly, "'{'"); ! lsquirly) { + return Unexpected<>{ std::move(lsquirly).error() }; + } + while (keepParsing) { - auto idecl = parseTopLevelDeclaration(); - - if (! idecl) { - return Unexpected<>{ std::move(idecl).error() }; - } - - decl = std::move(idecl).value(); - - if (! decl.has_value()) { - keepParsing = false; + if (auto ok = parseTopLevelDeclaration(); ! ok) { + return Unexpected<>{ std::move(ok).error() }; } else { + decl = std::move(ok).value(); + + if (! decl.has_value()) { + keepParsing = false; + continue; + } + if (std::holds_alternative(*decl)) { node->childModules.push_back( std::get(std::move(*decl)) @@ -325,100 +245,60 @@ namespace arti::lang { } } - auto rsquirly = tokenizer.peekExpect(0, TokenV::opRSquirly); - - if (! rsquirly) { - return Unexpected{ std::move(rsquirly).error() }; + if (auto rsquirly = consume(TokenV::opRSquirly, "'{'"); ! rsquirly) { + return Unexpected<>{ std::move(rsquirly).error() }; } - std::ignore = tokenizer.consume(); - return node; } Expected Parser::parseStructDeclaration() { auto node = ast::MakeNode(); - auto kw = tokenizer.peek(); - - if (! kw) { + if (auto kw = consume(TokenV::kwStruct, "'struct' keyword"); ! kw) { return Unexpected<>{ std::move(kw).error() }; } + else { + node->location = { kw->line, kw->column }; + } - node->location.line = kw->line; - node->location.column = kw->column; - - std::ignore = tokenizer.consume(); - - auto name = tokenizer.peek(); - - if (! name) { + if (auto name = consume(TokenV::tkIdentifier, "identifier"); ! name) { return Unexpected<>{ std::move(name).error() }; } - - if (name->value != TokenV::tkIdentifier) { - return langException( - name->line, - name->column, - toString(*name), - "identifier" - ); - } - std::ignore = tokenizer.consume(); - - node->name = name->strValue; - - auto peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + else { + node->name = name->strValue; } - if (peekNext->value == TokenV::opLt) { - std::ignore = tokenizer.consume(); - - auto generics = parseGenericParamsList(); - - if (! generics) { - return Unexpected<>{ std::move(generics).error() }; + if (auto hasLt = matchAndConsume(TokenV::opLt); ! hasLt) { + return Unexpected<>{ std::move(hasLt).error() }; + } + else if (hasLt.value()) { + if (auto params = parseGenericParamsList(); ! params) { + return Unexpected<>{ std::move(params).error() }; } + else { + node->genericParams = std::move(params).value(); - node->genericParams = std::move(*generics); - - if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) { - return Unexpected{ std::move(closeG).error() }; - } - std::ignore = tokenizer.consume(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + if (auto hasGt = consume(TokenV::opGt, "'>'"); ! hasGt) { + return Unexpected<>{ std::move(hasGt ).error() }; + } } } - if (peekNext->value != TokenV::opLSquirly) { - return langException( - peekNext->line, - peekNext->column, - toString(*peekNext), - "'{'" - ); + if (auto lsquirly = consume(TokenV::opLSquirly, "'{'"); ! lsquirly) { + return Unexpected<>{ std::move(lsquirly).error() }; } - std::ignore = tokenizer.consume(); - auto members = parseStructMembersList(); - - if (! members) { + if (auto members = parseStructMembersList(); ! members) { return Unexpected<>{ std::move(members).error() }; } - - node->structMembers = std::move(members).value(); - - if (auto closeS = tokenizer.peekExpect(0, TokenV::opRSquirly); ! closeS) { - return Unexpected{ std::move(closeS).error() }; + else { + node->structMembers = std::move(members).value(); + } + + if (auto rsquirly = consume(TokenV::opRSquirly, "'}'"); ! rsquirly) { + return Unexpected<>{ std::move(rsquirly).error() }; } - std::ignore = tokenizer.consume(); return node; } @@ -426,86 +306,50 @@ namespace arti::lang { Expected Parser::parseEnumDeclaration() { auto node = ast::MakeNode(); - auto kw = tokenizer.peek(); - - if (! kw) { + if (auto kw = consume(TokenV::kwEnum, "'enum' keyword"); ! kw) { return Unexpected<>{ std::move(kw).error() }; } + else { + node->location = { kw->line, kw->column }; + } - node->location.line = kw->line; - node->location.column = kw->column; - - std::ignore = tokenizer.consume(); - - auto name = tokenizer.peek(); - - if (! name) { + if (auto name = consume(TokenV::tkIdentifier, "identifier"); ! name) { return Unexpected<>{ std::move(name).error() }; } - - if (name->value != TokenV::tkIdentifier) { - return langException( - name->line, - name->column, - toString(*name), - "identifier" - ); - } - std::ignore = tokenizer.consume(); - - node->name = name->strValue; - - auto peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + else { + node->name = name->strValue; } - if (peekNext->value == TokenV::opLt) { - std::ignore = tokenizer.consume(); - - auto generics = parseGenericParamsList(); - - if (! generics) { - return Unexpected<>{ std::move(generics).error() }; + if (auto hasLt = matchAndConsume(TokenV::opLt); ! hasLt) { + return Unexpected<>{ std::move(hasLt).error() }; + } + else if (hasLt.value()) { + if (auto params = parseGenericParamsList(); ! params) { + return Unexpected<>{ std::move(params).error() }; } + else { + node->genericParams = std::move(params).value(); - node->genericParams = std::move(*generics); - - if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) { - return Unexpected{ std::move(closeG).error() }; - } - std::ignore = tokenizer.consume(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + if (auto hasGt = consume(TokenV::opGt, "'>'"); ! hasGt) { + return Unexpected<>{ std::move(hasGt ).error() }; + } } } - if (peekNext->value != TokenV::opLSquirly) { - return langException( - peekNext->line, - peekNext->column, - toString(*peekNext), - "'{'" - ); + if (auto lsquirly = consume(TokenV::opLSquirly, "'{'"); ! lsquirly) { + return Unexpected<>{ std::move(lsquirly).error() }; } - std::ignore = tokenizer.consume(); - auto members = parseEnumMembersList(); - - if (! members) { + if (auto members = parseEnumMembersList(); ! members) { return Unexpected<>{ std::move(members).error() }; } - - node->enumMembers = std::move(members).value(); - - if (auto closeS = tokenizer.peekExpect(0, TokenV::opRSquirly); ! closeS) { - return Unexpected{ std::move(closeS).error() }; + else { + node->enumMembers = std::move(members).value(); + } + + if (auto rsquirly = consume(TokenV::opRSquirly, "'}'"); ! rsquirly) { + return Unexpected<>{ std::move(rsquirly).error() }; } - std::ignore = tokenizer.consume(); return node; } @@ -520,21 +364,48 @@ namespace arti::lang { return Unexpected{ std::move(peekToken).error() }; } - while (peekToken->value != TokenV::opGt) { - auto param = parseGenericParam(); + bool keepParsing = true; - if (! param) { + if (auto comma = tokenizer.peek(); + comma and comma->value == TokenV::opComma) { + return langException( + comma->line, + comma->column, + toString(*comma), + "'typename' keyword" + ); + } + + while (keepParsing) { + if (auto param = parseGenericParam(); ! param) { return Unexpected{ std::move(param).error() }; } - - paramsList.push_back(std::move(param).value()); - - peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected{ std::move(peekToken).error() }; + else { + paramsList.push_back(std::move(param).value()); } - } + + if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { + return Unexpected{ std::move(comma).error() }; + } + else if (! comma.value()) { + if (peekToken = tokenizer.peek(); ! peekToken) { + return Unexpected{ std::move(peekToken).error() }; + } + else { + if (peekToken->value != TokenV::opGt) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "',' or '>'" + ); + } + else { + keepParsing = false; + } + } + } + } return paramsList; } @@ -542,41 +413,19 @@ namespace arti::lang { Expected Parser::parseGenericParam() { auto node = ast::MakeNode(); - if (auto kwTypename = tokenizer.peekExpect(0, TokenV::kwTypename); - ! kwTypename) { - return Unexpected{ std::move(kwTypename).error() }; + if (auto kw = consume(TokenV::kwTypename, "'typename' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; } else { - node->location = { .line = kwTypename->line, - .column = kwTypename->column }; + node->location = { kw->line, kw->column }; } - std::ignore = tokenizer.consume(); - if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { return Unexpected{ std::move(ident).error() }; } else { node->name = ident->strValue; } - std::ignore = tokenizer.consume(); - - auto sc = tokenizer.peek(); - - if (! sc) { - return Unexpected{ std::move(sc).error() }; - } - - if (sc->value == TokenV::opComma) { - std::ignore = tokenizer.consume(); - } - else if (sc->value != TokenV::opGt) { - return langException( - sc->line, - sc->column, - toString(*sc), - "'}' or ','" - ); - } return node; } @@ -585,26 +434,38 @@ namespace arti::lang { Parser::parseStructMembersList() { auto membersList = ast::Vector{}; - auto peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected{ std::move(peekToken).error() }; + if (auto comma = tokenizer.peek(); + comma and comma->value == TokenV::opComma) { + return langException( + comma->line, + comma->column, + toString(*comma), + "identifier or '}'" + ); } - while (peekToken->value != TokenV::opRSquirly) { - auto member = parseStructMember(); + bool keepParsing = true; - if (! member) { + while (keepParsing) { + if (auto member = parseStructMember(); ! member) { return Unexpected{ std::move(member).error() }; } + else { + membersList.push_back(std::move(member).value()); + } - membersList.push_back(std::move(member).value()); + if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { + return Unexpected<>{ std::move(comma).error() }; + } - peekToken = tokenizer.peek(); - - if (! peekToken) { + if (auto peekToken = tokenizer.peek(); ! peekToken) { return Unexpected{ std::move(peekToken).error() }; } + else { + if (peekToken->value == TokenV::opRSquirly) { + keepParsing = false; + } + } } return membersList; @@ -613,45 +474,23 @@ namespace arti::lang { Expected Parser::parseStructMember() { auto node = ast::MakeNode(); - if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) { - return Unexpected{ std::move(ident).error() }; + if (auto ident = consume(TokenV::tkIdentifier, "'identifier'"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; } else { - node->location = { .line = ident->line, .column = ident->column }; - + node->location = { ident->line, ident->column }; node->name = ident->strValue; } - std::ignore = tokenizer.consume(); - if (auto colon = tokenizer.peekExpect(0, TokenV::opColon); ! colon) { + if (auto colon = consume(TokenV::opColon, "':'"); ! colon) { return Unexpected{ std::move(colon).error() }; } - std::ignore = tokenizer.consume(); - - auto type = parseType(); - - if (! type) { + + if (auto type = parseType(); ! type) { return Unexpected{ std::move(type).error() }; } - - node->type = std::move(type).value(); - - auto sc = tokenizer.peek(); - - if (! sc) { - return Unexpected{ std::move(sc).error() }; - } - - if (sc->value == TokenV::opComma) { - std::ignore = tokenizer.consume(); - } - else if (sc->value != TokenV::opRSquirly) { - return langException( - sc->line, - sc->column, - toString(*sc), - "'}' or ','" - ); + else { + node->type = std::move(type).value(); } return node; @@ -660,26 +499,38 @@ namespace arti::lang { Expected> Parser::parseEnumMembersList() { auto membersList = ast::Vector{}; - auto peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected{ std::move(peekToken).error() }; + if (auto comma = tokenizer.peek(); + comma and comma->value == TokenV::opComma) { + return langException( + comma->line, + comma->column, + toString(*comma), + "identifier or '}'" + ); } - while (peekToken->value != TokenV::opRSquirly) { - auto member = parseEnumMember(); + bool keepParsing = true; - if (! member) { + while (keepParsing) { + if (auto member = parseEnumMember(); ! member) { return Unexpected{ std::move(member).error() }; } + else { + membersList.push_back(std::move(member).value()); + } - membersList.push_back(std::move(member).value()); + if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { + return Unexpected<>{ std::move(comma).error() }; + } - peekToken = tokenizer.peek(); - - if (! peekToken) { + if (auto peekToken = tokenizer.peek(); ! peekToken) { return Unexpected{ std::move(peekToken).error() }; } + else { + if (peekToken->value == TokenV::opRSquirly) { + keepParsing = false; + } + } } return membersList; @@ -688,55 +539,28 @@ namespace arti::lang { Expected Parser::parseEnumMember() { auto node = ast::MakeNode(); - if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) { - return Unexpected{ std::move(ident).error() }; + if (auto ident = consume(TokenV::tkIdentifier, "'identifier'"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; } else { - node->location = { .line = ident->line, .column = ident->column }; - + node->location = { ident->line, ident->column }; node->name = ident->strValue; } - std::ignore = tokenizer.consume(); - auto sc = tokenizer.peek(); - - if (! sc) { - return Unexpected{ std::move(sc).error() }; + if (auto hasLParen = matchAndConsume(TokenV::opLParen); ! hasLParen) { + return Unexpected{ std::move(hasLParen).error() }; } - - if (sc->value == TokenV::opLParen) { - std::ignore = tokenizer.consume(); - - auto type = parseType(); - - if (! type) { + else if (hasLParen.value()) { + if (auto type = parseType(); ! type) { return Unexpected{ std::move(type).error() }; } + else { + node->type = std::move(type).value(); - node->type = std::move(type).value(); - - if (auto closeP = tokenizer.peekExpect(0, TokenV::opRParen); ! closeP) { - return Unexpected{ std::move(closeP).error() }; + if (auto hasRParen = consume(TokenV::opRParen, "')'"); ! hasRParen) { + return Unexpected{ std::move(hasRParen).error() }; + } } - std::ignore = tokenizer.consume(); - - sc = tokenizer.peek(); - - if (! sc) { - return Unexpected{ std::move(sc).error() }; - } - } - - if (sc->value == TokenV::opComma) { - std::ignore = tokenizer.consume(); - } - else if (sc->value != TokenV::opRSquirly) { - return langException( - sc->line, - sc->column, - toString(*sc), - "'}' or ','" - ); } return node; @@ -745,147 +569,74 @@ namespace arti::lang { Expected Parser::parseFunctionDeclaration() { auto node = ast::MakeNode(); - auto kw = tokenizer.peek(); - - if (! kw) { + if (auto kw = consume(TokenV::kwFn, "'fn' keyword"); ! kw) { return Unexpected<>{ std::move(kw).error() }; } + else { + node->location = { kw->line, kw->column }; + } - node->location.line = kw->line; - node->location.column = kw->column; - - std::ignore = tokenizer.consume(); - - auto name = tokenizer.peek(); - - if (! name) { + if (auto name = consume(TokenV::tkIdentifier, "identifier"); ! name) { return Unexpected<>{ std::move(name).error() }; } - - if (name->value != TokenV::tkIdentifier) { - return langException( - name->line, - name->column, - toString(*name), - "identifier" - ); - } - std::ignore = tokenizer.consume(); - - node->name = name->strValue; - - auto peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + else { + node->name = name->strValue; } - if (peekNext->value == TokenV::opLt) { - std::ignore = tokenizer.consume(); - - auto generics = parseGenericParamsList(); - - if (! generics) { - return Unexpected<>{ std::move(generics).error() }; - } - - node->genericParams = std::move(*generics); - - if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) { - return Unexpected{ std::move(closeG).error() }; - } - std::ignore = tokenizer.consume(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } + if (auto hasLt = matchAndConsume(TokenV::opLt); ! hasLt) { + return Unexpected<>{ std::move(hasLt).error() }; } - - if (peekNext->value != TokenV::opLParen) { - return langException( - peekNext->line, - peekNext->column, - toString(*peekNext), - "'('" - ); - } - std::ignore = tokenizer.consume(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } - - if (peekNext->value != TokenV::opRParen) { - auto params = parseFunctionParamsList(); - - if (! params) { + else if (hasLt.value()) { + if (auto params = parseGenericParamsList(); ! params) { return Unexpected<>{ std::move(params).error() }; } + else { + node->genericParams = std::move(params).value(); - node->functionParams = std::move(params).value(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } - - if (peekNext->value != TokenV::opRParen) { - return langException( - peekNext->line, - peekNext->column, - toString(*peekNext), - "')'" - ); - } - } - std::ignore = tokenizer.consume(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } - - if (peekNext->value == TokenV::opArrow) { - std::ignore = tokenizer.consume(); - - auto retType = parseType(); - - if (! retType) { - return Unexpected<>{ std::move(retType).error() }; - } - - node->returnType = std::move(retType).value(); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + if (auto hasGt = consume(TokenV::opGt, "'>'"); ! hasGt) { + return Unexpected<>{ std::move(hasGt ).error() }; + } } } - if (auto openS = tokenizer.peekExpect(0, TokenV::opLSquirly); ! openS) { - return Unexpected{ std::move(openS).error() }; - } - std::ignore = tokenizer.consume(); - - auto body = parseCodeBlock(); - - if (! body) { - return Unexpected{ std::move(body).error() }; + if (auto lparen = consume(TokenV::opLParen, "'('"); ! lparen) { + return Unexpected<>{ std::move(lparen).error() }; } - node->functionBody = std::move(body).value(); - - if (auto closeS = tokenizer.peekExpect(0, TokenV::opRSquirly); ! closeS) { - return Unexpected{ std::move(closeS).error() }; + if (auto rparen = tokenizer.peek(); ! rparen) { + return Unexpected<>{ std::move(rparen).error() }; + } + else if (rparen->value != TokenV::opRParen) { + if (auto params = parseFunctionParamsList(); ! params) { + return Unexpected<>{ std::move(params).error() }; + } + else { + node->functionParams = std::move(params).value(); + } + } + + if (auto rparen = consume(TokenV::opRParen, "')'"); ! rparen) { + return Unexpected<>{ std::move(rparen).error() }; + } + + if (auto hasArrow = matchAndConsume(TokenV::opArrow); ! hasArrow) { + return Unexpected<>{ std::move(hasArrow).error() }; + } + else if (hasArrow.value()) { + if (auto type = parseType(); ! type) { + return Unexpected<>{ std::move(type).error() }; + } + else { + node->returnType = std::move(type).value(); + } + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->functionBody = std::move(body).value(); } - std::ignore = tokenizer.consume(); return node; } @@ -894,41 +645,54 @@ namespace arti::lang { Parser::parseFunctionParamsList() { auto params = ast::Vector{}; - auto peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected<>{ std::move(peekToken).error() }; + if (auto comma = tokenizer.peek(); + comma and comma->value == TokenV::opComma) { + return langException( + comma->line, + comma->column, + toString(*comma), + "identifier, 'this' keyword or ')'" + ); } - if (peekToken->value == TokenV::kwThis) { + if (auto hasThis = match(TokenV::kwThis); ! hasThis) { + return Unexpected<>{ std::move(hasThis).value() }; + } + else if (hasThis.value()) { auto thisParam = parseFunctionParamThis(); - - if (! thisParam) { + if (auto thisá¹”aram = parseFunctionParamThis(); ! thisParam) { return Unexpected<>{ std::move(thisParam).error() }; } + else { + params.push_back(std::move(thisParam).value()); + } - params.push_back(std::move(thisParam).value()); - - peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected<>{ std::move(peekToken).error() }; + if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { + return Unexpected<>{ std::move(comma).error() }; } } + + bool keepParsing = true; - while (peekToken->value != TokenV::opRParen) { - auto param = parseFunctionParam(); - - if (! param) { + while (keepParsing) { + if (auto param = parseFunctionParam(); ! param) { return Unexpected<>{ std::move(param).error() }; } + else { + params.push_back(std::move(param).value()); - params.push_back(std::move(param).value()); + if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { + return Unexpected<>{ std::move(comma).error() }; + } - peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected<>{ std::move(peekToken).error() }; + if (auto peekToken = tokenizer.peek(); ! peekToken) { + return Unexpected{ std::move(peekToken).error() }; + } + else { + if (peekToken->value == TokenV::opRParen) { + keepParsing = false; + } + } } } @@ -938,45 +702,23 @@ namespace arti::lang { Expected Parser::parseFunctionParamThis() { auto node = ast::MakeNode(); - node->isThis = true; - - auto kw = tokenizer.peek(); - - if (! kw) { - return Unexpected<>{ std::move(kw).error() }; + if (auto thisToken = consume(TokenV::kwThis, "'this' keyword"); + ! thisToken) { + return Unexpected<>{ std::move(thisToken).error() }; } + else { + node->isThis = true; + node->location.line = thisToken->line; + node->location.column = thisToken->column; + node->name = "this"; - node->location.line = kw->line; - node->location.column = kw->column; - node->name = "this"; - - std::ignore = tokenizer.consume(); - - auto type = parseType(); - - if (! type) { - return Unexpected{ std::move(type).error() }; - } - - node->type = std::move(type).value(); - - auto sc = tokenizer.peek(); - - if (! sc) { - return Unexpected{ std::move(sc).error() }; - } - - if (sc->value == TokenV::opComma) { - std::ignore = tokenizer.consume(); - } - else if (sc->value != TokenV::opRParen) { - return langException( - sc->line, - sc->column, - toString(*sc), - "'}' or ','" - ); - } + if (auto type = parseType(); ! type) { + return Unexpected<>{ std::move(type).error() }; + } + else { + node->type = std::move(type).value(); + } + } return node; } @@ -986,47 +728,24 @@ namespace arti::lang { node->isThis = false; - if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) { - return Unexpected{ std::move(ident).error() }; + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; } else { + node->name = ident->strValue; node->location.line = ident->line; node->location.column = ident->column; - - node->name = ident->strValue; - - std::ignore = tokenizer.consume(); } - if (auto colon = tokenizer.peekExpect(0, TokenV::opColon); ! colon) { + if (auto colon = consume(TokenV::opColon, "':'"); ! colon) { return Unexpected{ std::move(colon).error() }; } - std::ignore = tokenizer.consume(); - auto type = parseType(); - - if (! type) { + if (auto type = parseType(); ! type) { return Unexpected{ std::move(type).error() }; } - - node->type = std::move(type).value(); - - auto sc = tokenizer.peek(); - - if (! sc) { - return Unexpected{ std::move(sc).error() }; - } - - if (sc->value == TokenV::opComma) { - std::ignore = tokenizer.consume(); - } - else if (sc->value != TokenV::opRParen) { - return langException( - sc->line, - sc->column, - toString(*sc), - "'}' or ','" - ); + else { + node->type = std::move(type).value(); } return node; diff --git a/lib/src/Parser/Parser.cpp b/lib/src/Parser/Parser.cpp index c27476f..3f4119d 100644 --- a/lib/src/Parser/Parser.cpp +++ b/lib/src/Parser/Parser.cpp @@ -14,30 +14,28 @@ namespace arti::lang { Expected Parser::parse() { auto unit = ast::MakeNode(); - auto tlDecl = ast::Optional{}; + auto decl = ast::Optional{}; bool keepParsing = true; unit->unitName = this->unitName; while (keepParsing) { - if (auto ok = parseTopLevelDeclaration(); ok) { - tlDecl = std::move(ok).value(); + if (auto ok = parseTopLevelDeclaration(); ! ok) { + return Unexpected<>{ std::move(ok).error() }; + } + else { + decl = std::move(ok).value(); - if (! tlDecl.has_value()) { + if (! decl.has_value()) { keepParsing = false; } else { - unit->declarations.push_back(std::move(tlDecl).value()); + unit->declarations.push_back(std::move(decl).value()); } } - else { - return Unexpected<>{ std::move(ok).error() }; - } } - auto eof = tokenizer.peekExpect(0, TokenV::tkEOF); - - if (! eof) { + if (auto eof = consume(TokenV::tkEOF, "end of compilation unit"); ! eof) { return Unexpected<>{ std::move(eof).error() }; } diff --git a/lib/src/Parser/Statements.cpp b/lib/src/Parser/Statements.cpp index 5008542..9e41c81 100644 --- a/lib/src/Parser/Statements.cpp +++ b/lib/src/Parser/Statements.cpp @@ -8,6 +8,10 @@ namespace arti::lang { auto stmt = ast::Optional{}; bool keepParsing = true; + if (auto lsquirly = consume(TokenV::opLSquirly, "'{'"); ! lsquirly) { + return Unexpected<>{ std::move(lsquirly).error() }; + } + while (keepParsing) { if (auto ok = parseStatement(); ok) { stmt = std::move(ok).value(); @@ -24,12 +28,20 @@ namespace arti::lang { } } + if (auto rsquirly = consume(TokenV::opRSquirly, "'}'"); ! rsquirly) { + return Unexpected<>{ std::move(rsquirly).error() }; + } + return node; } Expected> Parser::parseStatement() { - + /* TODO: Implement statement parsing logic. + * This is intentionally stubbed while the parser architecture + * is being in development. + * Currently, the compiler is in a 'Declarations-Only' state. */ + return std::nullopt; } diff --git a/lib/src/Parser/Types.cpp b/lib/src/Parser/Types.cpp index e10d4a8..49c6eb2 100644 --- a/lib/src/Parser/Types.cpp +++ b/lib/src/Parser/Types.cpp @@ -1,138 +1,130 @@ #include +#include + namespace arti::lang { Expected Parser::parseNamespacedIdentifier() { auto node = ast::MakeNode(); - auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); + bool keepParsing = true; - if (! ident) { - return Unexpected<>{ std::move(ident).error() }; - } - else { - node->location = { .line = ident->line, .column = ident->column }; - - node->identParts.emplace_back(ident->strValue); - } - std::ignore = tokenizer.consume(); - - auto peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } - - while (peekNext->value == TokenV::opAccess) { - ident = tokenizer.peek(1); - - if (! ident) { - return node; + while (keepParsing) { + if (auto ident = match(TokenV::tkIdentifier); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else if (ident.value()) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->location = { .line = ident->line, .column = ident->column }; + node->identParts.emplace_back(ident->strValue); + } } else { - if (ident->value != TokenV::tkIdentifier) { - return node; - } - - node->identParts.emplace_back(ident->strValue); + return node; } - std::ignore = tokenizer.consume(2); - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + if (auto access = match(TokenV::opAccess); ! access) { + return Unexpected<>{ std::move(access).error() }; + } + else if (access.value()) { + if (auto ident = match(TokenV::tkIdentifier, 1); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else if (not ident.value()) { + keepParsing = false; + } + else { + if (auto colon = consume(TokenV::opAccess, "':'"); ! colon) { + return Unexpected<>{ std::move(colon).error() }; + } + } + } + else { + keepParsing = false; } } - + return node; } Expected Parser::parseType() { auto node = ast::MakeNode(); + auto currentNode = ast::TypeExpressionNode{}; - if (auto peekNext = tokenizer.peek(); ! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + if (auto nextToken = tokenizer.peek(); ! nextToken) { + return Unexpected<>{ std::move(nextToken).error() }; } else { - node->location = { .line = peekNext->line, .column = peekNext->column }; - - if (peekNext->value != TokenV::tkIdentifier) { - auto qualifiers = parseTypeQualifiers(); - - if (! qualifiers) { - return Unexpected<>{ std::move(qualifiers).error() }; - } + node->location = { .line = nextToken->line, .column = nextToken->column }; + } + if (auto ident = match(TokenV::tkIdentifier); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else if (not ident.value()) { + if (auto qualifiers = parseTypeQualifiers(); ! qualifiers) { + return Unexpected<>{ std::move(qualifiers).error() }; + } + else { node->qualifiers = std::move(qualifiers).value(); } } - auto identType = parseNamespacedIdentifier(); - - if (! identType) { + if (auto identType = parseNamespacedIdentifier(); ! identType) { return Unexpected<>{ std::move(identType).error() }; } + else { + currentNode = ast::MakeNode(); - auto currentNode = ast::TypeExpressionNode{}; + std::get(currentNode)->location = + (*identType)->location; - currentNode = ast::MakeNode(); - - std::get(currentNode)->location = - (*identType)->location; - - std::get(currentNode)->typeName = - std::move(identType).value(); - - auto peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + std::get(currentNode)->typeName = + std::move(identType).value(); } - if (peekNext->value == TokenV::opLt) { - std::ignore = tokenizer.consume(); - - auto args = parseGenericArgumentsList(); - - if (! args) { - return Unexpected<>{ std::move(args).error() }; + if (auto lt = matchAndConsume(TokenV::opLt); ! lt) { + return Unexpected<>{ std::move(lt).error() }; + } + else if (lt.value()) { + if (auto genericArgs = parseGenericArgumentsList(); ! genericArgs) { + return Unexpected<>{ std::move(genericArgs).error() }; } + else { + auto genParamsNode = ast::MakeNode(); - if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) { - return Unexpected<>{ std::move(closeG).error() }; - } - std::ignore = tokenizer.consume(); + genParamsNode->location = std::visit( + [](const auto &node) { return node->location; }, + currentNode + ); - auto newNode = ast::MakeNode(); + genParamsNode->baseType = std::move(currentNode); + genParamsNode->genericArgs = std::move(genericArgs).value(); + currentNode = std::move(genParamsNode); - newNode->location = std::visit( - [](const auto &node) { return node->location; }, - currentNode - ); - - newNode->baseType = std::move(currentNode); - newNode->genericArgs = std::move(args).value(); - currentNode = std::move(newNode); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + if (auto gt = consume(TokenV::opGt, "'>'"); ! gt) { + return Unexpected<>{ std::move(gt).error() }; + } } } - while (peekNext->value == TokenV::opAccess) { - std::ignore = tokenizer.consume(); + bool keepParsing = false; - auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); + if (auto access = matchAndConsume(TokenV::opAccess); ! access) { + return Unexpected<>{ std::move(access).error() }; + } + else if (access.value()) { + keepParsing = true; + } - if (! ident) { + while (keepParsing) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { return Unexpected<>{ std::move(ident).error() }; } else { - std::ignore = tokenizer.consume(); - auto newNode = ast::MakeNode(); newNode->location = std::visit( @@ -143,44 +135,38 @@ namespace arti::lang { newNode->typeName = ident->strValue; newNode->baseType = std::move(currentNode); currentNode = std::move(newNode); + } - peekNext = tokenizer.peek(); + if (auto lt = matchAndConsume(TokenV::opLt); ! lt) { + return Unexpected<>{ std::move(lt).error() }; + } + else if (lt.value()) { + if (auto genericArgs = parseGenericArgumentsList(); ! genericArgs) { + return Unexpected<>{ std::move(genericArgs).error() }; + } + else { + auto genParamsNode = ast::MakeNode(); - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; + genParamsNode->location = std::visit( + [](const auto &node) { return node->location; }, + currentNode + ); + + genParamsNode->baseType = std::move(currentNode); + genParamsNode->genericArgs = std::move(genericArgs).value(); + currentNode = std::move(genParamsNode); + + if (auto gt = consume(TokenV::opGt, "'>'"); ! gt) { + return Unexpected<>{ std::move(gt).error() }; + } } } - if (peekNext->value == TokenV::opLt) { - std::ignore = tokenizer.consume(); - - auto args = parseGenericArgumentsList(); - - if (! args) { - return Unexpected<>{ std::move(args).error() }; - } - - if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) { - return Unexpected<>{ std::move(closeG).error() }; - } - std::ignore = tokenizer.consume(); - - auto newNode = ast::MakeNode(); - - newNode->location = std::visit( - [](const auto &node) { return node->location; }, - currentNode - ); - - newNode->baseType = std::move(currentNode); - newNode->genericArgs = std::move(args).value(); - currentNode = std::move(newNode); - - peekNext = tokenizer.peek(); - - if (! peekNext) { - return Unexpected<>{ std::move(peekNext).error() }; - } + if (auto access = matchAndConsume(TokenV::opAccess); ! access) { + return Unexpected<>{ std::move(access).error() }; + } + else { + keepParsing = access.value(); } } @@ -235,7 +221,7 @@ namespace arti::lang { case opLBracket: std::ignore = tokenizer.consume(); - peekToken = tokenizer.peekExpect(0, opRBracket); + peekToken = tokenizer.peekExpect(opRBracket); if (! peekToken) { return Unexpected<>{ std::move(peekToken).error() }; @@ -269,29 +255,46 @@ namespace arti::lang { return Unexpected{ std::move(peekToken).error() }; } - while (peekToken->value != TokenV::opGt) { - auto type = parseType(); + bool keepParsing = true; - if (! type) { + if (auto comma = tokenizer.peek(); + comma and comma->value == TokenV::opComma) { + return langException( + comma->line, + comma->column, + toString(*comma), + "type" + ); + } + + while (keepParsing) { + if (auto type = parseType(); ! type) { return Unexpected<>{ std::move(type).error() }; } - - args.push_back(std::move(type).value()); - - peekToken = tokenizer.peek(); - - if (! peekToken) { - return Unexpected{ std::move(peekToken).error() }; + else { + args.push_back(std::move(type).value()); } - if (peekToken->value == TokenV::opComma) { - std::ignore = tokenizer.consume(); - - peekToken = tokenizer.peek(); - - if (! peekToken) { + if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { + return Unexpected{ std::move(comma).error() }; + } + else if (! comma.value()) { + if (peekToken = tokenizer.peek(); ! peekToken) { return Unexpected{ std::move(peekToken).error() }; } + else { + if (peekToken->value != TokenV::opGt) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "',' or '>'" + ); + } + else { + keepParsing = false; + } + } } } diff --git a/lib/src/Tokenizer/Tokenizer.cpp b/lib/src/Tokenizer/Tokenizer.cpp index f93e51d..03a3a73 100644 --- a/lib/src/Tokenizer/Tokenizer.cpp +++ b/lib/src/Tokenizer/Tokenizer.cpp @@ -106,8 +106,15 @@ namespace arti::lang { return tokensBuffer.at(n); } - Expected - Tokenizer::peekExpect(std::size_t n, TokenV tokenType) noexcept { + Expected Tokenizer::peekExpect( + TokenV tokenType, + std::string_view message, + std::size_t n + ) noexcept { + if (message.empty()) { + message = toString(tokenType); + } + if (tokensBuffer.size() > (n + 1)) { auto tokenAt = tokensBuffer.at(n); @@ -116,7 +123,7 @@ namespace arti::lang { tokenAt.line, tokenAt.column, toString(tokenAt), - toString(tokenType) + message ); } @@ -125,7 +132,7 @@ namespace arti::lang { auto token = peek(n); - if (!token) { + if (! token) { return token; } @@ -137,7 +144,7 @@ namespace arti::lang { tokensBuffer.pop_back(); tokensBuffer.push_back(*token); token->column += 1; - token->strValue = std::string_view{token->strValue.begin() + 1, 1}; + token->strValue = std::string_view{ token->strValue.begin() + 1, 1 }; tokensBuffer.push_back(*token); token = peekTok; } @@ -147,7 +154,7 @@ namespace arti::lang { token->line, token->column, toString(*token), - toString(tokenType) + message ); }