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