From 66eca2f24a7be69ec065e44f50aa72c0d7247622 Mon Sep 17 00:00:00 2001 From: erick-alcachofa Date: Thu, 16 Oct 2025 23:22:19 -0600 Subject: [PATCH] feat(Parser): Expanding parser capabilities (might clean later) Signed-off-by: erick-alcachofa --- frontend/src/main.cpp | 43 +++- lib/include/artichoke/Parser/Parser.hpp | 94 ++++++++ lib/src/Parser/AST/AST.cpp | 2 +- lib/src/Parser/Declarations.cpp | 288 +++++++++++++++++++++++- lib/src/Parser/Statements.cpp | 36 +++ lib/src/Parser/Types.cpp | 12 +- 6 files changed, 463 insertions(+), 12 deletions(-) diff --git a/frontend/src/main.cpp b/frontend/src/main.cpp index 3e67a25..73cea02 100644 --- a/frontend/src/main.cpp +++ b/frontend/src/main.cpp @@ -1,5 +1,44 @@ #include +#include -int main(int, char **) { - std::println("[LOG] Hello world"); +#include + +int main(int argc, char **argv) { + using namespace arti::lang; + + if (argc < 2) { + std::println("Usage:\n {} ", argv[0]); + return -1; + } + + std::ifstream file; + file.open(argv[1]); + + if (! file.is_open()) { + std::println("Failed to open file {}", argv[1]); + return -1; + } + + std::string buffer{ std::istreambuf_iterator(file), + std::istreambuf_iterator() }; + + auto parser = Parser{ buffer }; + + auto res = parser.parse(); + + if (! res) { + std::println( + "Error at line {} column {}", + res.error().line, + res.error().column + ); + + std::println("{}", res.error().message); + + return -1; + } + + auto ast = std::move(res).value(); + + std::println("{}", ast::toString(ast)); } diff --git a/lib/include/artichoke/Parser/Parser.hpp b/lib/include/artichoke/Parser/Parser.hpp index 9539643..14015ec 100644 --- a/lib/include/artichoke/Parser/Parser.hpp +++ b/lib/include/artichoke/Parser/Parser.hpp @@ -69,6 +69,100 @@ namespace arti::lang { Expected> parseGenericArgumentsList(); + Expected> + parseFunctionParamsList(); + + Expected + parseFunctionParam(); + + Expected + parseFunctionParamThis(); + + Expected + parseCodeBlock(); + + Expected> + parseStatement(); + + Expected + parseVariableStatement(); + + Expected + parseIfStatement(); + + Expected + parseDeferStatement(); + + Expected + parseErrDeferStatement(); + + Expected + parseReturnStatement(); + + Expected + parseBreakStatement(); + + Expected + parseContinueStatement(); + + Expected + parseMatchStatement(); + + Expected + parseSwitchStatement(); + + Expected + parseCForStatement(); + + Expected + parseRangeForStatement(); + + Expected + parseWhileStatement(); + + Expected + parseDoWhileStatement(); + + Expected + parseInfLoopStatement(); + + Expected consume(TokenV type, std::string_view expected_name) { + auto peeked = tokenizer.peek(); + + 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; + } + + Expected matchAndConsume(TokenV type) { + auto peeked = tokenizer.peek(); + + if (! peeked) { + return Unexpected<>{ std::move(peeked).error() }; + } + + if (peeked->value != type) { + return false; + } + + std::ignore = tokenizer.consume(); + + return true; + } + private: std::string unitName; std::string sourceCode; diff --git a/lib/src/Parser/AST/AST.cpp b/lib/src/Parser/AST/AST.cpp index 7242f01..c7e156c 100644 --- a/lib/src/Parser/AST/AST.cpp +++ b/lib/src/Parser/AST/AST.cpp @@ -278,7 +278,7 @@ namespace arti::lang::ast { auto paddingStr = createPadding(padding); ss << std::format( - "Import {} {}", + "Import {}{}", toString(node->importTarget, padding), node->importAll ? "::*" : "" ); diff --git a/lib/src/Parser/Declarations.cpp b/lib/src/Parser/Declarations.cpp index f42fbc3..85810d7 100644 --- a/lib/src/Parser/Declarations.cpp +++ b/lib/src/Parser/Declarations.cpp @@ -102,6 +102,9 @@ namespace arti::lang { 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, @@ -740,16 +743,293 @@ namespace arti::lang { } Expected Parser::parseFunctionDeclaration() { + auto node = ast::MakeNode(); + + auto kw = tokenizer.peek(); + + if (! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + + node->location.line = kw->line; + node->location.column = kw->column; + + std::ignore = tokenizer.consume(); + + auto name = tokenizer.peek(); + + if (! 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() }; + } + + 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 (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) { + return Unexpected<>{ std::move(params).error() }; + } + + 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 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() }; + } + + node->functionBody = std::move(body).value(); + + if (auto closeS = tokenizer.peekExpect(0, TokenV::opRSquirly); ! closeS) { + return Unexpected{ std::move(closeS).error() }; + } + std::ignore = tokenizer.consume(); + + return node; + } + + Expected> + Parser::parseFunctionParamsList() { + auto params = ast::Vector{}; + auto peekToken = tokenizer.peek(); if (! peekToken) { return Unexpected<>{ std::move(peekToken).error() }; } - return langException( - peekToken->line, - peekToken->column - ); + if (peekToken->value == TokenV::kwThis) { + auto thisParam = parseFunctionParamThis(); + + if (! thisParam) { + return Unexpected<>{ std::move(thisParam).error() }; + } + + params.push_back(std::move(thisParam).value()); + + peekToken = tokenizer.peek(); + + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + } + + while (peekToken->value != TokenV::opRParen) { + auto param = parseFunctionParam(); + + if (! param) { + return Unexpected<>{ std::move(param).error() }; + } + + params.push_back(std::move(param).value()); + + peekToken = tokenizer.peek(); + + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + } + + return params; + } + + Expected Parser::parseFunctionParamThis() { + auto node = ast::MakeNode(); + + node->isThis = true; + + auto kw = tokenizer.peek(); + + if (! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + + 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 ','" + ); + } + + return node; + } + + Expected Parser::parseFunctionParam() { + auto node = ast::MakeNode(); + + node->isThis = false; + + if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) { + return Unexpected{ std::move(ident).error() }; + } + else { + 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) { + return Unexpected{ std::move(colon).error() }; + } + 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 ','" + ); + } + + return node; } } // namespace arti::lang diff --git a/lib/src/Parser/Statements.cpp b/lib/src/Parser/Statements.cpp index e69de29..5008542 100644 --- a/lib/src/Parser/Statements.cpp +++ b/lib/src/Parser/Statements.cpp @@ -0,0 +1,36 @@ +#include + +namespace arti::lang { + + Expected Parser::parseCodeBlock() { + auto node = ast::MakeNode(); + + auto stmt = ast::Optional{}; + bool keepParsing = true; + + while (keepParsing) { + if (auto ok = parseStatement(); ok) { + stmt = std::move(ok).value(); + + if (! stmt.has_value()) { + keepParsing = false; + } + else { + node->statements.push_back(std::move(stmt).value()); + } + } + else { + return Unexpected<>{ std::move(ok).error() }; + } + } + + return node; + } + + Expected> + Parser::parseStatement() { + + } + + +} // namespace arti::lang diff --git a/lib/src/Parser/Types.cpp b/lib/src/Parser/Types.cpp index c7b4053..e10d4a8 100644 --- a/lib/src/Parser/Types.cpp +++ b/lib/src/Parser/Types.cpp @@ -24,17 +24,19 @@ namespace arti::lang { } while (peekNext->value == TokenV::opAccess) { - std::ignore = tokenizer.consume(); - - ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); + ident = tokenizer.peek(1); if (! ident) { - return Unexpected<>{ std::move(ident).error() }; + return node; } else { + if (ident->value != TokenV::tkIdentifier) { + return node; + } + node->identParts.emplace_back(ident->strValue); } - std::ignore = tokenizer.consume(); + std::ignore = tokenizer.consume(2); peekNext = tokenizer.peek();