feat(Parser): Expanding parser capabilities (might clean later)

Signed-off-by: erick-alcachofa <erick@artichoke.dev>
This commit is contained in:
erick-alcachofa 2025-10-16 23:22:19 -06:00
parent 552cda58e7
commit 66eca2f24a
Signed by: me
GPG Key ID: 6FA5F8643444BAFA
6 changed files with 463 additions and 12 deletions

View File

@ -1,5 +1,44 @@
#include <print>
#include <fstream>
int main(int, char **) {
std::println("[LOG] Hello world");
#include <artichoke/Parser/Parser.hpp>
int main(int argc, char **argv) {
using namespace arti::lang;
if (argc < 2) {
std::println("Usage:\n {} <filename>", 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<char>(file),
std::istreambuf_iterator<char>() };
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));
}

View File

@ -69,6 +69,100 @@ namespace arti::lang {
Expected<ast::Vector<ast::TypeNode>>
parseGenericArgumentsList();
Expected<ast::Vector<ast::FunctionParamNode>>
parseFunctionParamsList();
Expected<ast::FunctionParamNode>
parseFunctionParam();
Expected<ast::FunctionParamNode>
parseFunctionParamThis();
Expected<ast::CodeBlockStmtNode>
parseCodeBlock();
Expected<ast::Optional<ast::StatementNode>>
parseStatement();
Expected<ast::VariableStmtNode>
parseVariableStatement();
Expected<ast::IfStmtNode>
parseIfStatement();
Expected<ast::DeferStmtNode>
parseDeferStatement();
Expected<ast::ErrDeferStmtNode>
parseErrDeferStatement();
Expected<ast::ReturnStmtNode>
parseReturnStatement();
Expected<ast::BreakStmtNode>
parseBreakStatement();
Expected<ast::ContinueStmtNode>
parseContinueStatement();
Expected<ast::MatchStmtNode>
parseMatchStatement();
Expected<ast::SwitchStmtNode>
parseSwitchStatement();
Expected<ast::CForStmtNode>
parseCForStatement();
Expected<ast::RangeForStmtNode>
parseRangeForStatement();
Expected<ast::WhileStmtNode>
parseWhileStatement();
Expected<ast::DoWhileStmtNode>
parseDoWhileStatement();
Expected<ast::InfLoopStmtNode>
parseInfLoopStatement();
Expected<Token> 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<ExceptCode::ecUnexpectedToken>(
peeked->line,
peeked->column,
toString(*peeked),
expected_name
);
}
std::ignore = tokenizer.consume();
return peeked;
}
Expected<bool> 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;

View File

@ -278,7 +278,7 @@ namespace arti::lang::ast {
auto paddingStr = createPadding(padding);
ss << std::format(
"Import {} {}",
"Import {}{}",
toString(node->importTarget, padding),
node->importAll ? "::*" : ""
);

View File

@ -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<ExceptCode::ecUnexpectedToken>(
peekToken->line,
@ -740,16 +743,293 @@ namespace arti::lang {
}
Expected<ast::FunctionDeclNode> Parser::parseFunctionDeclaration() {
auto node = ast::MakeNode<ast::FunctionDeclNode>();
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<ExceptCode::ecUnexpectedToken>(
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<ExceptCode::ecUnexpectedToken>(
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<ExceptCode::ecUnexpectedToken>(
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<ast::Vector<ast::FunctionParamNode>>
Parser::parseFunctionParamsList() {
auto params = ast::Vector<ast::FunctionParamNode>{};
auto peekToken = tokenizer.peek();
if (! peekToken) {
return Unexpected<>{ std::move(peekToken).error() };
}
return langException<ExceptCode::ecUnimplemented>(
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<ast::FunctionParamNode> Parser::parseFunctionParamThis() {
auto node = ast::MakeNode<ast::FunctionParamNode>();
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<ExceptCode::ecUnexpectedToken>(
sc->line,
sc->column,
toString(*sc),
"'}' or ','"
);
}
return node;
}
Expected<ast::FunctionParamNode> Parser::parseFunctionParam() {
auto node = ast::MakeNode<ast::FunctionParamNode>();
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<ExceptCode::ecUnexpectedToken>(
sc->line,
sc->column,
toString(*sc),
"'}' or ','"
);
}
return node;
}
} // namespace arti::lang

View File

@ -0,0 +1,36 @@
#include <artichoke/Parser/Parser.hpp>
namespace arti::lang {
Expected<ast::CodeBlockStmtNode> Parser::parseCodeBlock() {
auto node = ast::MakeNode<ast::CodeBlockStmtNode>();
auto stmt = ast::Optional<ast::StatementNode>{};
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<ast::Optional<ast::StatementNode>>
Parser::parseStatement() {
}
} // namespace arti::lang

View File

@ -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();