187 lines
3.4 KiB
C++

#include "parser.hh"
#include "expr.hh"
#include "../error_handler.hh"
#include "../tokenizer.hh"
#include <optional>
extern ErrorHandler error_handler;
std::optional<Expr> Parser::parse() {
try {
return expression();
} catch (ParseException e) {
return std::nullopt;
}
}
Expr Parser::expression() {
return equality();
}
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::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();
}
}