187 lines
3.4 KiB
C++
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();
|
|
}
|
|
}
|