223 lines
7.2 KiB
C++

#include "ast_interpreter.hh"
#include "expr.hh"
#include "stmt.hh"
#include "../error_handler.hh"
#include "../tokenizer.hh"
#include <memory>
#include <string>
#include <vector>
#include <cassert>
#include <iostream>
extern ErrorHandler error_handler;
void AstInterpreter::interpret(const std::vector<Stmt> &statements) {
try {
for (const Stmt & stmt : statements) {
execute(stmt);
}
} catch (RuntimeException e) {
error_handler.runtime_error(e);
}
}
void AstInterpreter::execute(const Stmt &stmt) {
switch (stmt.type) {
case StmtType::EXPRESSION: return execute_expression_statement(stmt);
case StmtType::PRINT: return execute_print_statement(stmt);
case StmtType::VAR: return execute_var_statement(stmt);
}
}
void AstInterpreter::execute_expression_statement(const Stmt &stmt) {
std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(stmt.value);
assert(ptr != nullptr);
evaluate(ptr->expr);
}
void AstInterpreter::execute_print_statement(const Stmt &stmt) {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(stmt.value);
assert(ptr != nullptr);
Object value{evaluate(ptr->expr)};
std::cout << value << '\n';
}
void AstInterpreter::execute_var_statement(const Stmt &stmt) {
Object value{};
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(stmt.value);
assert(ptr != nullptr);
if (ptr->expr.type == ExprType::LITERAL) {
std::shared_ptr<_Literal> eptr = std::get<std::shared_ptr<_Literal>>(ptr->expr.value);
assert(eptr != nullptr);
if (eptr->value.type == ObjectType::NIL) {
environment.define(ptr->name.lexeme, value);
return;
}
}
value = evaluate(ptr->expr);
environment.define(ptr->name.lexeme, value);
}
Object AstInterpreter::evaluate(const Expr &expr) {
switch (expr.type) {
case ExprType::BINARY: return evaluate_binary_expression(expr);
case ExprType::GROUPING: return evaluate_grouping_expression(expr);
case ExprType::LITERAL: return evaluate_literal_expression(expr);
case ExprType::UNARY: return evaluate_unary_expression(expr);
case ExprType::VARIABLE: return evaluate_variable_expression(expr);
case ExprType::ASSIGN: return evaluate_assignment_expression(expr);
}
}
Object AstInterpreter::evaluate_binary_expression(const Expr &expr) {
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(expr.value);
assert(ptr != nullptr);
Object left = evaluate(ptr->left);
Object right = evaluate(ptr->right);
if (left.type == ObjectType::NUMBER && right.type == ObjectType::NUMBER) {
double left_val = std::get<double>(left.value);
double right_val = std::get<double>(right.value);
switch (ptr->op.type) {
case TokenType::PLUS: return left_val + right_val;
case TokenType::MINUS: return left_val - right_val;
case TokenType::STAR: return left_val * right_val;
case TokenType::SLASH: {
if (right_val == 0) {
throw RuntimeException{ptr->op, "Division by zero."};
}
return left_val / right_val;
}
case TokenType::GREATER: return left_val > right_val;
case TokenType::GREATER_EQUAL: return left_val >= right_val;
case TokenType::LESS: return left_val < right_val;
case TokenType::LESS_EQUAL: return left_val <= right_val;
case TokenType::BANG_EQUAL: return left_val != right_val;
case TokenType::EQUAL_EQUAL: return left_val == right_val;
default: throw RuntimeException{ptr->op, "Operator " + ptr->op.lexeme + " is not supported for numbers."};
}
}
if (left.type == ObjectType::STRING_LIT) {
right = Object{StringObjectType::LITERAL, right.to_string()};
}
if (right.type == ObjectType::STRING_LIT) {
left = Object{StringObjectType::LITERAL, left.to_string()};
}
if (left.type == ObjectType::STRING_LIT && right.type == ObjectType::STRING_LIT) {
std::string left_val = std::get<std::string>(left.value);
std::string right_val = std::get<std::string>(right.value);
switch (ptr->op.type) {
case TokenType::PLUS: return Object{StringObjectType::LITERAL, left_val + right_val};
case TokenType::BANG_EQUAL: return left_val != right_val;
case TokenType::EQUAL_EQUAL: return left_val == right_val;
default: throw RuntimeException{ptr->op, "Operator " + ptr->op.lexeme + " is not supported for strings."};
}
}
if (left.type == ObjectType::BOOL && right.type == ObjectType::BOOL) {
bool left_val = std::get<bool>(left.value);
bool right_val = std::get<bool>(right.value);
switch (ptr->op.type) {
case TokenType::BANG_EQUAL: return left_val != right_val;
case TokenType::EQUAL_EQUAL: return left_val == right_val;
default: throw RuntimeException{ptr->op, "Operator " + ptr->op.lexeme + " is not supported for booleans."};
}
}
if (left.type == ObjectType::NIL && right.type == ObjectType::NIL) {
switch (ptr->op.type) {
case TokenType::BANG_EQUAL: return false;
case TokenType::EQUAL_EQUAL: return true;
default: throw RuntimeException{ptr->op, "Operator " + ptr->op.lexeme + " is not supported for null."};
}
}
if (left.type == ObjectType::NIL) {
switch (ptr->op.type) {
case TokenType::BANG_EQUAL: return true;
case TokenType::EQUAL_EQUAL: return false;
default: break;
}
}
throw RuntimeException{ptr->op, "Operator " + ptr->op.lexeme + " is not supported for operands " + left.to_string() + " and " + right.to_string() + "."};
}
Object AstInterpreter::evaluate_grouping_expression(const Expr &expr) {
std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(expr.value);
assert(ptr != nullptr);
return evaluate(ptr->expr);
}
Object AstInterpreter::evaluate_literal_expression(const Expr &expr) {
std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(expr.value);
assert(ptr != nullptr);
return ptr->value;
}
Object AstInterpreter::evaluate_unary_expression(const Expr &expr) {
std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(expr.value);
assert(ptr != nullptr);
Object right = evaluate(ptr->right);
switch (ptr->op.type) {
case TokenType::MINUS: {
switch (right.type) {
case ObjectType::NUMBER: {
double value = std::get<double>(right.value);
return -value;
}
default: throw RuntimeException{ptr->op, "Operand to unary operator - must be a number."};
}
}
case TokenType::BANG:
return !is_truthy(right);
default: break;
}
return Object{};
}
Object AstInterpreter::evaluate_variable_expression(const Expr &expr) {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(expr.value);
assert(ptr != nullptr);
return environment.get(ptr->name);
}
Object AstInterpreter::evaluate_assignment_expression(const Expr &expr) {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(expr.value);
assert(ptr != nullptr);
Object value = evaluate(ptr->value);
environment.assign(ptr->name, value);
return value;
}
bool AstInterpreter::is_truthy(const Object &object) {
switch (object.type) {
case ObjectType::NIL: return false;
case ObjectType::BOOL: {
bool value = std::get<bool>(object.value);
return value;
}
default: return true;
}
}