2025-06-29 22:03:03 +01:00

273 lines
5.3 KiB
C++

#include "parser.hh"
#include "expr.hh"
#include "stmt.hh"
#include "../error_handler.hh"
#include "../tokenizer.hh"
#include <cassert>
extern ErrorHandler error_handler;
std::vector<Stmt> Parser::parse() {
std::vector<Stmt> 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();
}
if (match({TokenType::LEFT_BRACE})) {
return Block(block_statement());
}
return expression_statement();
}
std::vector<Stmt> Parser::block_statement() {
std::vector<Stmt> statements{};
while (!check(TokenType::RIGHT_BRACE) && !is_at_end()) {
statements.push_back(declaration());
}
consume(TokenType::RIGHT_BRACE, "Expect '}' after block.");
return statements;
}
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<std::shared_ptr<_Variable>>(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<TokenType> 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();
}
}