#include "parser.hpp" #include #include using std::string, std::to_string, std::vector; Expression::~Expression() = default; // class Binary string Binary::as_string() { return "(" + token_name(op->tokentype) + " " + left->as_string() + " " + right->as_string() + ")"; } Binary::Binary(Expression *_left, Token *_operator, Expression *_right) : left(_left), op(_operator), right(_right){}; Binary::~Binary() = default; // class Grouping string Grouping::as_string() { return "(" + expr->as_string() + ")"; } Grouping::Grouping(Expression *_expr) : expr(_expr){}; Grouping::~Grouping() = default; // class Unary string Unary::as_string() { return token_name(op->tokentype) + right->as_string(); } Unary::Unary(Token *_operator, Expression *_right) : op(_operator), right(_right){}; Unary::~Unary() = default; // class Literal string Literal::as_string() { string text; if (holds_alternative(value)) { return "\"" + get(value) + "\""; } if (holds_alternative(value)) { return to_string(get(value)); } if (holds_alternative(value)) { return get(value) ? "True" : "False"; } if (holds_alternative(value)) { return "NULL"; } return "unexpected"; } // class Parser Result Parser::parse(vector tokenlist) { tokens = tokenlist; current_token = 0; return expression(); } Token Parser::peek() { return tokens[current_token]; }; bool Parser::is_at_end() { return peek().tokentype == Token::END_OF_FILE; }; Token *Parser::previous() { return &tokens[current_token - 1]; }; Token *Parser::advance() { if (!is_at_end()) current_token += 1; return previous(); } bool Parser::check(Token::Type type) { if (is_at_end()) { return false; } return peek().tokentype == type; } bool Parser::match(int count, ...) { va_list list; va_start(list, count); for (int i = 0; i < count; i++) { Token::Type ttc = va_arg(list, Token::Type); // cout << token_name(ttc) << "\n"; if (check(ttc)) { advance(); return true; } } return false; }; Result Parser::consume(Token::Type typ, string message) { if (check(typ)) { return advance(); } return error(peek(), message); } Error Parser::error(Token token, string message) { std::cout << token.as_string() << " " << message; return Error(message); // TODO no exceptions } Result Parser::primary() { if (match(1, Token::Type::FALSE)) return new Literal(false); if (match(1, Token::Type::TRUE)) return new Literal(true); if (match(1, Token::Type::NIL)) return new Literal(new NilType()); if (match(1, Token::Type::NUMBER)) { return new Literal(stod(previous()->literal)); } if (match(1, Token::Type::STRING)) { return new Literal(previous()->literal); } if (match(1, Token::Type::LEFT_PAREN)) { auto expr = expression(); Result r = consume(Token::Type::RIGHT_PAREN, "Expect ')'."); if (is_err(r)) { return Err(r); } return new Grouping(Ok(expr)); } return Error("Expected an expression"); } Result Parser::unary() { if (match(2, Token::BANG, Token::Type::MINUS)) { Token *op = previous(); Result right = unary(); if (is_ok(right)) { return new Unary(op, Ok(right)); } } return primary(); } Result Parser::expression() { return equality(); } Result Parser::factor() { Result expr = unary(); if (is_err(expr)) { return expr; } while (match(2, Token::Type::SLASH, Token::Type::STAR)) { Token *op = previous(); auto right = unary(); if (is_err(right)) { return right; } expr = new Binary(Ok(expr), op, Ok(right)); } return expr; } Result Parser::term() { auto expr = factor(); if (is_err(expr)) { return expr; } while (match(2, Token::Type::MINUS, Token::Type::PLUS)) { Token *op = previous(); auto right = factor(); if (is_err(right)) { return right; } expr = new Binary(Ok(expr), op, Ok(right)); } return expr; } Result Parser::equality(void) { auto expr = comparison(); if (is_err(expr)) { return expr; } while (match(2, Token::Type::BANG_EQUAL, Token::Type::BANG_EQUAL)) { Token *op = previous(); auto right = comparison(); if (is_err(right)) { return right; } return new Binary(Ok(expr), op, Ok(right)); } return expr; } Result Parser::comparison(void) { auto expr = term(); if (is_err(expr)) { return expr; } while (match(4, Token::Type::GREATER, Token::Type::GREATER_EQUAL, Token::Type::LESS, Token::Type::LESS_EQUAL)) { Token *op = previous(); auto right = term(); if (is_err(right)) { return right; } expr = new Binary(Ok(expr), op, Ok(right)); } return expr; }