#pragma once #include #include "parser/lexer.hpp" #include "parser/nodes.hpp" #include "prelude/error.hpp" class AstParser { public: AstParser(Lexer* lexer) : m_lexer(lexer) {} public: ExternNode* ParseExtern() { m_lexer->NextExpect(TokenType::Id); return new ExternNode(m_lexer->token().string); } FnDeclNode* ParseFnDecl() { // Function Declaration m_lexer->NextExpect(TokenType::Id); StringView name = m_lexer->token().string; m_lexer->NextExpect('('); Builder params; // TODO: support multiple params if (m_lexer->seek_token()->token != ')') { m_lexer->NextExpect(TokenType::Id); params.Push(m_lexer->token().string); } m_lexer->NextExpect(')'); m_lexer->NextExpect('{'); auto compound = new CompoundNode(); while (m_lexer->seek_token()->token != '}') { compound->addNode(ParseStatement()); } m_lexer->NextExpect('}'); return new FnDeclNode(name, compound, params.view()); } FnCallNode* ParseFnCall(const StringView& name) { // m_lexer->NextExpect(TokenType::Id); // char* name = strdup(m_lexer->token().string); m_lexer->NextExpect('('); Builder args; while (m_lexer->seek_token()->token != ')') { auto arg = ParseExpression(); args.Push(arg); if (m_lexer->seek_token()->token == ',') assert(m_lexer->NextToken()); } m_lexer->NextExpect(')'); return new FnCallNode(name, std::move(args.view())); } Node* ParseFactor() { auto token = m_lexer->seek_token(); switch (token->token) { case TokenType::IntLiteral: // integer { m_lexer->NextExpect(TokenType::IntLiteral); auto node = new IntLiteralNode(m_lexer->token().int_number); return node; } case TokenType::Id: // variable name or function call { m_lexer->NextExpect(TokenType::Id); auto name = m_lexer->token().string; token = m_lexer->seek_token(); if (token->token == '(') { return ParseFnCall(name); } return new VariableNode(name); } default: // fprintf(stderr, "%s:%d:%d: ERROR: unexpected token while parsing %ld\n", m_lexer->filename(), token->line_number, token->offset_start, token->token); ErrorLogger::Raise(Error::ParseError(m_lexer->filename(), StringView::FromFormat("unexpected token while parsing '%d'", token->token), token->line_number, token->offset_start)); break; } assert(0 && "unreachable"); } Node* ParseTerm() { auto t = ParseFactor(); for (auto op = m_lexer->seek_token(); is_one_of(op->token, '/', '*'); op = m_lexer->seek_token()) { m_lexer->NextToken(); ExpressionNode::Operator eop; assert(static_cast(ExpressionNode::Operator::COUNT_OPERATORS) == 4 && "some operators may not be handled"); switch((char)op->token) { case '/': eop = ExpressionNode::Operator::Divide; break; case '*': eop = ExpressionNode::Operator::Multiply; break; default: assert(false && "should be unreachable"); break; } auto expr = new ExpressionNode(t, ParseTerm(), eop); t = expr; } return t; } Node* ParseExpression() { auto t = ParseTerm(); for (auto op = m_lexer->seek_token(); is_one_of(op->token, '+', '-'); op = m_lexer->seek_token()) { m_lexer->NextToken(); ExpressionNode::Operator eop; assert(static_cast(ExpressionNode::Operator::COUNT_OPERATORS) == 4 && "some operators may not be handled"); switch((char)op->token) { case '+': eop = ExpressionNode::Operator::Plus; break; case '-': eop = ExpressionNode::Operator::Minus; break; default: assert(false && "should be unreachable"); break; } auto expr = new ExpressionNode(t, ParseTerm(), eop); t = expr; } return t; } VarDeclNode* ParseVarDecl() { m_lexer->NextExpect(TokenType::Local); m_lexer->NextExpect(TokenType::Id); auto name = m_lexer->token().string; m_lexer->NextExpect('='); Node* value = ParseExpression(); return new VarDeclNode(name, value); } Node* ParseStatement() { auto token = m_lexer->seek_token(); assert(token != nullptr); switch(token->token) { case TokenType::Local: return ParseVarDecl(); default: return ParseExpression(); } assert(0 && "unreachable"); return nullptr; } ProgramNode* Parse() { auto program = new ProgramNode; while (m_lexer->NextToken()) { auto token = m_lexer->token(); switch(token.token) { case TokenType::Fn: program->PushFunction(ParseFnDecl()); break; case TokenType::Extern: program->PushExtern(ParseExtern()); break; default: { ErrorLogger::Raise(Error::ParseError(m_lexer->filename(), StringView::FromFormat("unexpected token while parsing '%d'", token.token), token.line_number, token.offset_start)); assert(false); } break; } } return program; } private: void Exit(int status) { std::exit(status); } private: Lexer* m_lexer; };