From c523375dbedd0fe55c2aeabe9aa28f253ead485c Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Sun, 3 Aug 2025 19:17:21 +0100 Subject: [PATCH] Started implementing parser --- parser/inc/Parser.h | 2 +- parser/src/Parser.cpp | 109 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/parser/inc/Parser.h b/parser/inc/Parser.h index 5598fd7..e9f196e 100644 --- a/parser/inc/Parser.h +++ b/parser/inc/Parser.h @@ -15,7 +15,7 @@ namespace LXC::Parser name{}, contents{} {} - FunctionAST(FunctionAST&& other) : + FunctionAST(FunctionAST&& other) noexcept : name{}, contents{} {} diff --git a/parser/src/Parser.cpp b/parser/src/Parser.cpp index cb19374..409834a 100644 --- a/parser/src/Parser.cpp +++ b/parser/src/Parser.cpp @@ -23,8 +23,11 @@ namespace LXC::Parser return &input[peekIndex]; } + // Returns a pointer to the current token // + inline const Lexer::Token* At() const { return Peek(0); } + // Advances x-distance in the tokens (default 1) // - inline const Lexer::Token* Next(size_t distance = 1) + inline const Lexer::Token* Advance(size_t distance = 1) { // Adds the distance and checks if in bounds to stop read errors // index += distance; @@ -34,6 +37,19 @@ namespace LXC::Parser return &input[index]; } + // Checks if the tokens are the correct types // + inline bool Expect(const std::span& tokens) const + { + for (int i = 0; i < tokens.size(); i++) + { + const Lexer::Token* current = Peek(i); + if (!current || current->type != tokens[i]) + return false; + } + + return true; + } + // Is the current index in bounds // inline bool InBounds() const { return index < length; } @@ -47,9 +63,90 @@ namespace LXC::Parser const size_t length; }; - static Util::ReturnVal ParseFunction(const ParserContext& ctx) + static void ParseBlock(ParserContext& ctx) { - return Util::FunctionFail(); + // Local lamdba for working out if at the end (static to avoid double initalisation) // + static const std::function AtEnd = [](const ParserContext& context) + { + // Peeks the current tokens type // + const Lexer::Token* current = context.Peek(); + if (current != nullptr) + { + return current->type == Lexer::Token::CloseBrace; + } + + // If nullptr means it has overflowed so it is at the end // + return true; + }; + + // Loops over the body until it reaches the end // + while (!AtEnd(ctx)) + { + // Force ends if it has gone over the end of the tokens // + const Lexer::Token* current = ctx.Advance(); + if (current != nullptr) + { + // Recurses if at the start of another block // + if (current->type == Lexer::Token::OpenBrace) + ParseBlock(ctx); + } + } + + // Advances over the ending close brace // + ctx.Advance(); + } + + static Util::ReturnVal ParseFunction(ParserContext& ctx) + { + // Checks for the sequence of: func funcName( // + if (!ctx.Expect(std::array{ Lexer::Token::FunctionDef, Lexer::Token::OpenCrocodile, Lexer::Token::Identifier, Lexer::Token::CloseCrocodile, Lexer::Token::Identifier, Lexer::Token::OpenParen })) + return Util::FunctionFail(); // <- TODO: Make an actual error + + // Assumes int for now so skips over func // + const Lexer::Token* funcName = ctx.Advance(4); + + // Assigns the name of the function // + FunctionAST currentFunction; + currentFunction.name = funcName->Str(); + + // Looks for the parameters of the function // + const Lexer::Token* paramsStart = ctx.Advance(2); + if (paramsStart == nullptr ) + return Util::FunctionFail(); // <- TODO: Make an actual error + + // Parses the parameters of the function // + if (paramsStart->type == Lexer::Token::Identifier && paramsStart->Str() == "void") + { /* No parameters/arguments for the function */} + + // Loops over the parameters/arguments of the function declaration // + else + { + while (ctx.At()->type != Lexer::Token::CloseParen) + { + // Checks for parameter pattern: identifier, identifier // + if (!ctx.Expect(std::array{ Lexer::Token::Identifier, Lexer::Token::Identifier })) + return Util::FunctionFail(); // <- TODO: Make an actual error + + const Lexer::Token* paramType = ctx.At(); + const Lexer::Token* paramName = ctx.Advance(); + + // Expects a comma or close bracket for the next token // + const Lexer::Token* end = ctx.Advance(); + if (end == nullptr) + return Util::FunctionFail(); // <- TODO: Make an actual error + + if (end->type == Lexer::Token::Comma || end->type == Lexer::Token::CloseParen) + continue; + + return Util::FunctionFail(); // <- TODO: Make an actual error + } + } + + // Parses the function body // + ParseBlock(ctx); + ctx.Advance(); // <- Goes over the closing brace + + return currentFunction; } Util::ReturnVal, ParserError> TurnTokensIntoAST(const Lexer::LexerOutput& input) @@ -58,10 +155,10 @@ namespace LXC::Parser ParserContext ctx(input); // Continues whilst in the bounds of the tokens // - while (ctx.InBounds()) + while (ctx.InBounds()) { // Peeks the next token (guaranteed to not be at the end) // - const Lexer::Token* current = ctx.Peek(); + const Lexer::Token* current = ctx.At(); // Switches over the type of the current token to run the correct logic // switch (current->type) @@ -84,6 +181,6 @@ namespace LXC::Parser } // Returns the output as it has gone through all the tokens // - return std::move(ctx.output); // Moves instead of copying, (required due to std::unique_ptr<>) + return std::move(ctx.output); // Moves instead of copying, (required due to std::unique_ptr<> within the class) } }