#include "ast_interpreter.hh" #include "environment.hh" #include "expr.hh" #include "stmt.hh" #include "../error_handler.hh" #include "../tokenizer.hh" #include #include #include #include #include #include extern ErrorHandler error_handler; void AstInterpreter::interpret(const std::vector &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); case StmtType::BLOCK: { std::shared_ptr<_Block> ptr = std::get>(stmt.value); assert(ptr != nullptr); return execute_block_statement(ptr->statements, Environment{std::make_shared(environment)}); } } } void AstInterpreter::execute_expression_statement(const Stmt &stmt) { std::shared_ptr<_Expression> ptr = std::get>(stmt.value); assert(ptr != nullptr); evaluate(ptr->expr); } void AstInterpreter::execute_print_statement(const Stmt &stmt) { std::shared_ptr<_Print> ptr = std::get>(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>(stmt.value); assert(ptr != nullptr); if (ptr->expr.type == ExprType::LITERAL) { std::shared_ptr<_Literal> eptr = std::get>(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); } void AstInterpreter::execute_block_statement(const std::vector &statements, Environment environment) { Environment previous = this->environment; try { this->environment = environment; for (const auto &stmt : statements) { execute(stmt); } } catch (std::exception) {} this->environment = previous; } 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>(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(left.value); double right_val = std::get(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(left.value); std::string right_val = std::get(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(left.value); bool right_val = std::get(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>(expr.value); assert(ptr != nullptr); return evaluate(ptr->expr); } Object AstInterpreter::evaluate_literal_expression(const Expr &expr) { std::shared_ptr<_Literal> ptr = std::get>(expr.value); assert(ptr != nullptr); return ptr->value; } Object AstInterpreter::evaluate_unary_expression(const Expr &expr) { std::shared_ptr<_Unary> ptr = std::get>(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(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>(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>(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(object.value); return value; } default: return true; } }