#include "parser.hh" #include "expr.hh" #include "stmt.hh" #include "../error_handler.hh" #include "../tokenizer.hh" #include extern ErrorHandler error_handler; std::vector Parser::parse() { std::vector statements{}; while (!is_at_end()) { statements.push_back(declaration()); } return statements; } Stmt Parser::declaration() { try { if (match({TokenType::VAR})) { return var_declaration(); } return statement(); } catch (ParseException e) { synchronize(); return Expression(Literal(Object{})); } } Stmt Parser::var_declaration() { Token name = consume(TokenType::IDENTIFIER, "Expect variable name."); Expr initializer = Literal(Object{}); if (match({TokenType::EQUAL})) { initializer = expression(); } consume(TokenType::SEMICOLON, "Expect ';' after variable declaration"); return Var(name, initializer); } Stmt Parser::statement() { if (match({TokenType::PRINT})) { return print_statement(); } return expression_statement(); } Stmt Parser::print_statement() { Expr value{expression()}; consume(TokenType::SEMICOLON, "Expect ';' after value."); return Print(value); } Stmt Parser::expression_statement() { Expr value{expression()}; consume(TokenType::SEMICOLON, "Expect ';' after value."); return Expression(value); } Expr Parser::expression() { return assignment(); } Expr Parser::assignment() { Expr expr = equality(); if (match({TokenType::EQUAL})) { Token equals = previous(); Expr value = assignment(); if (expr.type == ExprType::VARIABLE) { std::shared_ptr<_Variable> ptr = std::get>(expr.value); assert(ptr != nullptr); Token name = ptr->name; return Assign(name, value); } error_handler.error(equals, "Invalid assignment target."); } return expr; } Expr Parser::equality() { Expr expr = comparison(); while (match({TokenType::BANG_EQUAL, TokenType::EQUAL_EQUAL})) { Token op = previous(); Expr right = comparison(); expr = Binary(expr, op, right); } return expr; } Expr Parser::comparison() { Expr expr = term(); while (match({TokenType::GREATER, TokenType::GREATER_EQUAL, TokenType::LESS, TokenType::LESS_EQUAL})) { Token op = previous(); Expr right = term(); expr = Binary(expr, op, right); } return expr; } Expr Parser::term() { Expr expr = factor(); while (match({TokenType::MINUS, TokenType::PLUS})) { Token op = previous(); Expr right = factor(); expr = Binary(expr, op, right); } return expr; } Expr Parser::factor() { Expr expr = unary(); while (match({TokenType::SLASH, TokenType::STAR})) { Token op = previous(); Expr right = unary(); expr = Binary(expr, op, right); } return expr; } Expr Parser::unary() { if (match({TokenType::BANG, TokenType::MINUS})) { Token op = previous(); Expr right = unary(); return Unary(op, right); } return primary(); } Expr Parser::primary() { if (match({TokenType::FALSE})) { return Literal(false); } if (match({TokenType::TRUE})) { return Literal(true); } if (match({TokenType::NIL})) { return Literal(Object{}); } if (match({TokenType::NUMBER, TokenType::STRING})) { return Literal(previous().literal); } if (match({TokenType::IDENTIFIER})) { return Variable(previous()); } if (match({TokenType::LEFT_PAREN})) { Expr expr = expression(); consume(TokenType::RIGHT_PAREN, "Expect ')' after expression."); return Grouping(expr); } throw error(peek(), "Expect expression."); } Token Parser::advance() { if (!is_at_end()) { ++current; } return previous(); } Token Parser::peek() { return tokens.at(current); } Token Parser::previous() { return tokens.at(current - 1); } Token Parser::consume(TokenType type, std::string &&message) { if (check(type)) { return advance(); } throw error(peek(), message); } bool Parser::match(std::vector types) { for (const auto &type : types) { if (check(type)) { advance(); return true; } } return false; } bool Parser::check(TokenType type) { if (is_at_end()) { return false; } return peek().type == type; } bool Parser::is_at_end() { return peek().type == TokenType::EOFILE; } ParseException Parser::error(Token token, std::string &message) { error_handler.error(token, message); return ParseException{}; } ParseException Parser::error(Token token, std::string &&message) { return error(token, message); } void Parser::synchronize() { advance(); while (!is_at_end()) { if (previous().type == TokenType::SEMICOLON) { return; } switch (peek().type) { case TokenType::CLASS: case TokenType::FUN: case TokenType::VAR: case TokenType::FOR: case TokenType::IF: case TokenType::WHILE: case TokenType::PRINT: case TokenType::RETURN: return; default: break; } advance(); } }