feat(Parser): Expanding parser capabilities (might clean later)
Signed-off-by: erick-alcachofa <erick@artichoke.dev>
This commit is contained in:
parent
552cda58e7
commit
66eca2f24a
@ -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));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -278,7 +278,7 @@ namespace arti::lang::ast {
|
||||
auto paddingStr = createPadding(padding);
|
||||
|
||||
ss << std::format(
|
||||
"Import {} {}",
|
||||
"Import {}{}",
|
||||
toString(node->importTarget, padding),
|
||||
node->importAll ? "::*" : ""
|
||||
);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user