diff --git a/docs/grammar.ebnf b/docs/grammar.ebnf index a99b01b..23e99cc 100644 --- a/docs/grammar.ebnf +++ b/docs/grammar.ebnf @@ -170,7 +170,7 @@ non_exportable_declaration = "switch" "(" ")" "{" * ? "}" = - ( "(" ")" )? "->" + ( "|" "|" )? "->" = "->" diff --git a/lib/include/artichoke/Parser/Parser.hpp b/lib/include/artichoke/Parser/Parser.hpp index eddba4e..11ab366 100644 --- a/lib/include/artichoke/Parser/Parser.hpp +++ b/lib/include/artichoke/Parser/Parser.hpp @@ -121,6 +121,9 @@ namespace arti::lang { Expected parseIfStatement(); + Expected + parseElseStatement(); + Expected parseDeferStatement(); @@ -142,6 +145,9 @@ namespace arti::lang { Expected parseSwitchStatement(); + Expected + parseForLoopStatement(); + Expected parseCForStatement(); @@ -157,6 +163,12 @@ namespace arti::lang { Expected parseInfLoopStatement(); + Expected + parseExpressionStatement(); + + Expected + parseExpression(); + private: std::string unitName; std::string sourceCode; diff --git a/lib/src/Parser/Expressions.cpp b/lib/src/Parser/Expressions.cpp index c03cfc7..94039e0 100644 --- a/lib/src/Parser/Expressions.cpp +++ b/lib/src/Parser/Expressions.cpp @@ -20,3 +20,13 @@ // // //============================================================================// +#include + +namespace arti::lang { + + Expected + Parser::parseExpression() { + return {}; + } + +} // namespace arti::lang diff --git a/lib/src/Parser/Statements.cpp b/lib/src/Parser/Statements.cpp index f418b64..dcaddf4 100644 --- a/lib/src/Parser/Statements.cpp +++ b/lib/src/Parser/Statements.cpp @@ -22,6 +22,8 @@ #include +#include + namespace arti::lang { Expected Parser::parseCodeBlock() { @@ -35,7 +37,10 @@ namespace arti::lang { } while (keepParsing) { - if (auto ok = parseStatement(); ok) { + if (auto ok = parseStatement(); ! ok) { + return Unexpected<>{ std::move(ok).error() }; + } + else { stmt = std::move(ok).value(); if (! stmt.has_value()) { @@ -45,26 +50,1239 @@ namespace arti::lang { node->statements.push_back(std::move(stmt).value()); } } - else { - return Unexpected<>{ std::move(ok).error() }; - } } 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. */ + ast::Optional label; + + auto peekToken = tokenizer.peek(); + + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + + if (peekToken->value == TokenV::tkIdentifier) { + if (auto isLabel = match(TokenV::opLabel, 1); ! isLabel) { + return Unexpected<>{ std::move(isLabel).error() }; + } + else if (isLabel.value()) { + auto labelName = consume(TokenV::tkIdentifier, "identifier").value(); + std::ignore = consume(TokenV::opLabel, "':='"); + + peekToken = tokenizer.peek(); + + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + + label = labelName.strValue; + } + } + + if (peekToken->value == TokenV::kwLet || + peekToken->value == TokenV::kwDef) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseVariableStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwIf) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseIfStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwDefer) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseDeferStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwErrDefer) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseErrDeferStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwReturn) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseReturnStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwBreak) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseBreakStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwContinue) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseContinueStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwMatch) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseMatchStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwSwitch) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseSwitchStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwFor) { + if (auto stmt = parseForLoopStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + if (label.has_value()) { + std::visit( + OverloadSet( + [&label](ast::CForStmtNode &stmt) { + stmt->label = label.value(); + }, + [&label](ast::RangeForStmtNode &stmt) { + stmt->label = label.value(); + }, + [](auto &) {} + ), + stmt.value() + ); + } + + return std::move(stmt).value(); + } + } + else if (peekToken->value == TokenV::kwWhile) { + if (auto stmt = parseWhileStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + if (label.has_value()) { + stmt.value()->label = label.value(); + } + + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwDo) { + if (auto stmt = parseDoWhileStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + if (label.has_value()) { + stmt.value()->label = label.value(); + } + + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else if (peekToken->value == TokenV::kwLoop) { + if (auto stmt = parseInfLoopStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + if (label.has_value()) { + stmt.value()->label = label.value(); + } + + return ast::StatementNode{ std::move(stmt).value() }; + } + } + else { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseExpressionStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } + return std::nullopt; } - + + Expected + Parser::parseVariableStatement() { + auto node = ast::MakeNode(); + auto peekToken = tokenizer.peek(); + + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + + node->location = { + .line = peekToken->line, + .column = peekToken->column, + }; + + if (peekToken->value == TokenV::kwLet) { + node->mutability = ast::Mutability::Mutable; + } + else if (peekToken->value == TokenV::kwDef) { + node->mutability = ast::Mutability::Constant; + } + else { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "variable declaration keyword, i.e. any of ( let, def )" + ); + } + std::ignore = tokenizer.consume(); + + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->name = ident->strValue; + } + + if (auto colon = matchAndConsume(TokenV::opColon); ! colon) { + return Unexpected<>{ std::move(colon).error() }; + } + else if (colon.value()) { + if (auto type = parseType(); ! type) { + return Unexpected<>{ std::move(type).error() }; + } + else { + node->type = std::move(type).value(); + } + } + + if (auto assign = matchAndConsume(TokenV::opAssign); ! assign) { + return Unexpected<>{ std::move(assign).error() }; + } + else if(assign.value()) { + if (auto expr = parseExpression(); ! expr) { + return Unexpected<>{ std::move(expr).error() }; + } + else { + node->initializer = std::move(expr).value(); + } + } + + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } + + if (node->type == std::nullopt and node->initializer == std::nullopt) { + /* TODO: Is this the correct error code for this case? */ + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "variable declaration type or initializer" + ); + } + + return node; + } + + Expected + Parser::parseIfStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwIf, "'if' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column + }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto condition = parseExpression(); ! condition) { + return Unexpected<>{ std::move(condition).error() }; + } + else { + node->condition = std::move(condition).value(); + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + if (auto unwrap = matchAndConsume(TokenV::opOr); ! unwrap) { + return Unexpected<>{ std::move(unwrap).error() }; + } + else if (unwrap.value()) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->unwrappedVar = ident->strValue; + } + + if (auto closeUnwrap = consume(TokenV::opOr, "'|'"); ! closeUnwrap) { + return Unexpected<>{ std::move(closeUnwrap).error() }; + } + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + if (auto hasElse = match(TokenV::kwElse); ! hasElse) { + return Unexpected<>{ std::move(hasElse).error() }; + } + else if (hasElse.value()) { + if (auto elseStmt = parseElseStatement(); ! elseStmt) { + return Unexpected<>{ std::move(elseStmt).error() }; + } + else { + node->elseBranch = std::move(elseStmt).value(); + } + } + + return node; + } + + Expected + Parser::parseElseStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwElse, "'else' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto tailIf = match(TokenV::kwIf); ! tailIf) { + return Unexpected<>{ std::move(tailIf).error() }; + } + else if (tailIf.value()) { + node.reset(); + + if (auto ifStmt = parseIfStatement(); ! ifStmt) { + return Unexpected<>{ std::move(ifStmt).error() }; + } + else { + return std::move(ifStmt).value(); + } + } + + if (auto unwrap = matchAndConsume(TokenV::opOr); ! unwrap) { + return Unexpected<>{ std::move(unwrap).error() }; + } + else if (unwrap.value()) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->unwrappedVar = ident->strValue; + } + + if (auto closeUnwrap = consume(TokenV::opOr, "'|'"); ! closeUnwrap) { + return Unexpected<>{ std::move(closeUnwrap).error() }; + } + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + return node; + } + + Expected + Parser::parseDeferStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwDefer, "'defer' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto isBlock = match(TokenV::opLSquirly); ! isBlock) { + return Unexpected<>{ std::move(isBlock).error() }; + } + else if (isBlock.value()) { + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + } + else { + auto peekToken = tokenizer.peek(); + + if (not peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + + if (auto stmt = parseExpressionStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + node->body = std::move(stmt).value(); + } + } + + return node; + } + + Expected + Parser::parseErrDeferStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwErrDefer, "'errdefer' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto isBlock = match(TokenV::opLSquirly); ! isBlock) { + return Unexpected<>{ std::move(isBlock).error() }; + } + else if (isBlock.value()) { + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + } + else { + auto peekToken = tokenizer.peek(); + + if (not peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + + if (auto stmt = parseExpressionStatement(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + node->body = std::move(stmt).value(); + } + } + + return node; + } + + Expected + Parser::parseReturnStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwReturn, "'return' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto skipExpr = match(TokenV::opSemicolon); ! skipExpr) { + return Unexpected<>{ std::move(skipExpr).error() }; + } + else if (! skipExpr.value()) { + if (auto stmt = parseExpression(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + node->value = std::move(stmt).value(); + } + } + + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } + + return node; + } + + Expected + Parser::parseBreakStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwBreak, "'break' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + 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->label = ident->strValue; + } + } + + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } + + return node; + } + + Expected + Parser::parseContinueStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwContinue, "'continue' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + 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->label = ident->strValue; + } + } + + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } + + return node; + } + + Expected + Parser::parseMatchStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwMatch, "'match' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto condition = parseExpression(); ! condition) { + return Unexpected<>{ std::move(condition).error() }; + } + else { + node->value = std::move(condition).value(); + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + if (auto lSquirly = consume(TokenV::opLSquirly, "'{'"); ! lSquirly) { + return Unexpected<>{ std::move(lSquirly).error() }; + } + + bool keepParsing = true; + + while (keepParsing) { + if (auto isDefault = match(TokenV::kwUnderscore); ! isDefault) { + return Unexpected<>{ std::move(isDefault).error() }; + } + else if (isDefault.value()) { + keepParsing = false; + + if (auto under = consume(TokenV::kwUnderscore, "'_' keyword"); + ! under) { + return Unexpected<>{ std::move(under).error() }; + } + + if (auto arrow = consume(TokenV::opArrow, "'->'"); ! arrow) { + return Unexpected<>{ std::move(arrow).error() }; + } + + if (auto defCase = parseCodeBlock(); ! defCase) { + return Unexpected<>{ std::move(defCase).error() }; + } + else { + node->defaultCase = std::move(defCase).value(); + } + } + else { + auto curCase = ast::MakeNode(); + + if (auto type = parseType(); ! type) { + return Unexpected<>{ std::move(type).error() }; + } + else { + curCase->location = type.value()->location; + curCase->matchType = std::move(type).value(); + } + + if (auto unwrap = matchAndConsume(TokenV::opOr); ! unwrap) { + return Unexpected<>{ std::move(unwrap).error() }; + } + else if (unwrap.value()) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); + ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + curCase->unwrappedVar = ident->strValue; + } + + if (auto closeUnwrap = consume(TokenV::opOr, "'|'"); ! closeUnwrap) { + return Unexpected<>{ std::move(closeUnwrap).error() }; + } + } + + if (auto arrow = consume(TokenV::opArrow, "'->'"); ! arrow) { + return Unexpected<>{ std::move(arrow).error() }; + } + + if (auto caseBody = parseCodeBlock(); ! caseBody) { + return Unexpected<>{ std::move(caseBody).error() }; + } + else { + curCase->body = std::move(caseBody).value(); + } + + node->matchCases.push_back(std::move(curCase)); + } + + if (auto close = match(TokenV::opRSquirly); ! close) { + return Unexpected<>{ std::move(close).error() }; + } + else if (close.value()) { + keepParsing = false; + } + } + + if (auto rSquirly = consume(TokenV::opRSquirly, "'}'"); ! rSquirly) { + return Unexpected<>{ std::move(rSquirly).error() }; + } + + return node; + } + + Expected + Parser::parseSwitchStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwSwitch, "'switch' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto condition = parseExpression(); ! condition) { + return Unexpected<>{ std::move(condition).error() }; + } + else { + node->value = std::move(condition).value(); + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + if (auto lSquirly = consume(TokenV::opLSquirly, "'{'"); ! lSquirly) { + return Unexpected<>{ std::move(lSquirly).error() }; + } + + bool keepParsing = true; + + while (keepParsing) { + if (auto isDefault = match(TokenV::kwUnderscore); ! isDefault) { + return Unexpected<>{ std::move(isDefault).error() }; + } + else if (isDefault.value()) { + keepParsing = false; + + if (auto under = consume(TokenV::kwUnderscore, "'_' keyword"); + ! under) { + return Unexpected<>{ std::move(under).error() }; + } + + if (auto arrow = consume(TokenV::opArrow, "'->'"); ! arrow) { + return Unexpected<>{ std::move(arrow).error() }; + } + + if (auto defCase = parseCodeBlock(); ! defCase) { + return Unexpected<>{ std::move(defCase).error() }; + } + else { + node->defaultCase = std::move(defCase).value(); + } + } + else { + auto curCase = ast::MakeNode(); + + if (auto expr = parseExpression(); ! expr) { + return Unexpected<>{ std::move(expr).error() }; + } + else { + curCase->location = std::visit( + [](const auto &exprNode) -> ast::SourceLocation { + return exprNode->location; + }, + expr.value() + ); + curCase->matchExpr = std::move(expr).value(); + } + + if (auto arrow = consume(TokenV::opArrow, "'->'"); ! arrow) { + return Unexpected<>{ std::move(arrow).error() }; + } + + if (auto caseBody = parseCodeBlock(); ! caseBody) { + return Unexpected<>{ std::move(caseBody).error() }; + } + else { + curCase->body = std::move(caseBody).value(); + } + + node->switchCases.push_back(std::move(curCase)); + } + + if (auto close = match(TokenV::opRSquirly); ! close) { + return Unexpected<>{ std::move(close).error() }; + } + else if (close.value()) { + keepParsing = false; + } + } + + if (auto rSquirly = consume(TokenV::opRSquirly, "'}'"); ! rSquirly) { + return Unexpected<>{ std::move(rSquirly).error() }; + } + + return node; + } + + Expected + Parser::parseForLoopStatement() { + bool isRange = false; + + auto isLet = match(TokenV::kwLet, 2); + if (! isLet) { + return Unexpected<>{ std::move(isLet).error() }; + } + + auto isDef = match(TokenV::kwDef, 2); + if (! isDef) { + return Unexpected<>{ std::move(isDef).error() }; + } + + if (isLet.value() || isDef.value()) { + auto hasRangeOp = match(TokenV::opLabel, 4); + + if (! hasRangeOp) { + return Unexpected<>{ std::move(hasRangeOp).error() }; + } + + isRange = hasRangeOp.value(); + } + + if (isRange) { + return parseRangeForStatement().transform( + [](auto &&val) -> ast::StatementNode { + return std::forward(val); + } + ); + } + else { + return parseCForStatement().transform( + [](auto &&val) -> ast::StatementNode { + return std::forward(val); + } + ); + } + } + + Expected + Parser::parseCForStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwFor, "'for' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto skipPre = match(TokenV::opSemicolon); ! skipPre) { + return Unexpected<>{ std::move(skipPre).error() }; + } + else if (not skipPre.value()) { + auto isLet = match(TokenV::kwLet); + if (! isLet) { + return Unexpected<>{ std::move(isLet).error() }; + } + + auto isDef = match(TokenV::kwDef); + if (! isDef) { + return Unexpected<>{ std::move(isDef).error() }; + } + + if (isLet.value() || isDef.value()) { + if (auto preStmt = parseVariableStatement(); ! preStmt) { + return Unexpected<>{ std::move(preStmt).error() }; + } + else { + node->preLoop = std::move(preStmt).value(); + } + } + else { + if (auto preStmt = parseExpressionStatement(); ! preStmt) { + return Unexpected<>{ std::move(preStmt).error() }; + } + else { + node->preLoop = std::move(preStmt).value(); + } + } + } + + if (auto condition = parseExpression(); ! condition) { + return Unexpected<>{ std::move(condition).error() }; + } + else { + node->condition = std::move(condition).value(); + } + + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } + + if (auto skipPost = match(TokenV::opRParen); ! skipPost) { + return Unexpected<>{ std::move(skipPost).error() }; + } + else if (not skipPost.value()) { + if (auto postStmt = parseExpression(); ! postStmt) { + return Unexpected<>{ std::move(postStmt).error() }; + } + else { + node->postLoop = std::move(postStmt).value(); + } + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + return node; + } + + Expected + Parser::parseRangeForStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwFor, "'for' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto isLet = matchAndConsume(TokenV::kwLet); ! isLet) { + return Unexpected<>{ std::move(isLet).error() }; + } + else if (isLet.value()) { + node->varMutability = ast::Mutability::Mutable; + } + else if (auto isDef = matchAndConsume(TokenV::kwDef); ! isDef) { + return Unexpected<>{ std::move(isDef).error() }; + } + else if (isDef.value()) { + node->varMutability = ast::Mutability::Constant; + } + else { + auto peekToken = tokenizer.peek(); + + if (! peekToken) { + return Unexpected<>{ std::move(peekToken).error() }; + } + + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "variable declarator, i.e. any of ( let, def )" + ); + } + + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->varName = ident->strValue; + } + + if (auto assign = consume(TokenV::opLabel, "':='"); ! assign) { + return Unexpected<>{ std::move(assign).error() }; + } + + if (auto range = parseExpression(); ! range) { + return Unexpected<>{ std::move(range).error() }; + } + else { + node->range = std::move(range).value(); + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + return node; + } + + Expected + Parser::parseWhileStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwWhile, "'while' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column + }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto condition = parseExpression(); ! condition) { + return Unexpected<>{ std::move(condition).error() }; + } + else { + node->condition = std::move(condition).value(); + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + if (auto unwrap = matchAndConsume(TokenV::opOr); ! unwrap) { + return Unexpected<>{ std::move(unwrap).error() }; + } + else if (unwrap.value()) { + if (auto ident = consume(TokenV::tkIdentifier, "identifier"); ! ident) { + return Unexpected<>{ std::move(ident).error() }; + } + else { + node->unwrappedVar = ident->strValue; + } + + if (auto closeUnwrap = consume(TokenV::opOr, "'|'"); ! closeUnwrap) { + return Unexpected<>{ std::move(closeUnwrap).error() }; + } + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + if (auto hasElse = match(TokenV::kwElse); ! hasElse) { + return Unexpected<>{ std::move(hasElse).error() }; + } + else if (hasElse.value()) { + if (auto elseStmt = parseElseStatement(); ! elseStmt) { + return Unexpected<>{ std::move(elseStmt).error() }; + } + else { + node->elseBranch = std::move(elseStmt).value(); + } + } + + return node; + } + + Expected + Parser::parseDoWhileStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwDo, "'do' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column + }; + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + if (auto kw = consume(TokenV::kwWhile, "'while' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + + if (auto lParen = consume(TokenV::opLParen, "'('"); ! lParen) { + return Unexpected<>{ std::move(lParen).error() }; + } + + if (auto condition = parseExpression(); ! condition) { + return Unexpected<>{ std::move(condition).error() }; + } + else { + node->condition = std::move(condition).value(); + } + + if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + + return node; + } + + Expected + Parser::parseInfLoopStatement() { + auto node = ast::MakeNode(); + + if (auto kw = consume(TokenV::kwLoop, "'loop' keyword"); ! kw) { + return Unexpected<>{ std::move(kw).error() }; + } + else { + node->location = { + .line = kw->line, + .column = kw->column, + }; + } + + if (auto body = parseCodeBlock(); ! body) { + return Unexpected<>{ std::move(body).error() }; + } + else { + node->body = std::move(body).value(); + } + + return node; + } + + Expected + Parser::parseExpressionStatement() { + auto node = ast::MakeNode(); + + if (auto expr = parseExpression(); ! expr) { + return Unexpected<>{ std::move(expr).error() }; + } + else { + node->location = std::visit( + [](const auto &exprNode) -> ast::SourceLocation { + return exprNode->location; + }, + expr.value() + ); + node->expression = std::move(expr).value(); + } + + if (auto semicolon = consume(TokenV::opSemicolon, "';'"); ! semicolon) { + return Unexpected<>{ std::move(semicolon).error() }; + } + + return node; + } } // namespace arti::lang