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 <print>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
int main(int, char **) {
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
std::println("[LOG] Hello world");
|
|
||||||
|
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>>
|
Expected<ast::Vector<ast::TypeNode>>
|
||||||
parseGenericArgumentsList();
|
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:
|
private:
|
||||||
std::string unitName;
|
std::string unitName;
|
||||||
std::string sourceCode;
|
std::string sourceCode;
|
||||||
|
|||||||
@ -278,7 +278,7 @@ namespace arti::lang::ast {
|
|||||||
auto paddingStr = createPadding(padding);
|
auto paddingStr = createPadding(padding);
|
||||||
|
|
||||||
ss << std::format(
|
ss << std::format(
|
||||||
"Import {} {}",
|
"Import {}{}",
|
||||||
toString(node->importTarget, padding),
|
toString(node->importTarget, padding),
|
||||||
node->importAll ? "::*" : ""
|
node->importAll ? "::*" : ""
|
||||||
);
|
);
|
||||||
|
|||||||
@ -102,6 +102,9 @@ namespace arti::lang {
|
|||||||
|
|
||||||
return ast::TopLevelDeclNode{ std::move(node).value() };
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
}
|
}
|
||||||
|
else if (peekToken->value == TokenV::opRSquirly) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
else if (peekToken->value != TokenV::tkEOF) {
|
else if (peekToken->value != TokenV::tkEOF) {
|
||||||
return langException<ExceptCode::ecUnexpectedToken>(
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
peekToken->line,
|
peekToken->line,
|
||||||
@ -740,16 +743,293 @@ namespace arti::lang {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expected<ast::FunctionDeclNode> Parser::parseFunctionDeclaration() {
|
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();
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
if (! peekToken) {
|
if (! peekToken) {
|
||||||
return Unexpected<>{ std::move(peekToken).error() };
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
}
|
}
|
||||||
|
|
||||||
return langException<ExceptCode::ecUnimplemented>(
|
if (peekToken->value == TokenV::kwThis) {
|
||||||
peekToken->line,
|
auto thisParam = parseFunctionParamThis();
|
||||||
peekToken->column
|
|
||||||
);
|
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
|
} // 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) {
|
while (peekNext->value == TokenV::opAccess) {
|
||||||
std::ignore = tokenizer.consume();
|
ident = tokenizer.peek(1);
|
||||||
|
|
||||||
ident = tokenizer.peekExpect(0, TokenV::tkIdentifier);
|
|
||||||
|
|
||||||
if (! ident) {
|
if (! ident) {
|
||||||
return Unexpected<>{ std::move(ident).error() };
|
return node;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (ident->value != TokenV::tkIdentifier) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
node->identParts.emplace_back(ident->strValue);
|
node->identParts.emplace_back(ident->strValue);
|
||||||
}
|
}
|
||||||
std::ignore = tokenizer.consume();
|
std::ignore = tokenizer.consume(2);
|
||||||
|
|
||||||
peekNext = tokenizer.peek();
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user