1#include "gsc/interpreter.hpp"
2#include "gsc/error.hpp"
6void Interpreter::interpret(
7 const std::vector<std::shared_ptr<Stmt>> &statements) {
9 for (
const std::shared_ptr<Stmt> &stmt : statements) {
12 }
catch (RuntimeError &error) {
17std::any Interpreter::evaluate(std::shared_ptr<Expr> expr) {
18 return expr->accept(*
this);
21void Interpreter::execute(std::shared_ptr<Stmt> stmt) { stmt->accept(*
this); }
23void Interpreter::executeBlock(
24 const std::vector<std::shared_ptr<Stmt>> statements,
25 std::shared_ptr<Environment> environment) {
26 std::shared_ptr<Environment> previous =
this->environment;
28 this->environment = environment;
30 for (
const std::shared_ptr<Stmt> &stmt : statements) {
34 this->environment = previous;
38 this->environment = previous;
42void Interpreter::checkNumberOperands(
const Token &op, N... operands) {
43 if (((operands.type() !=
typeid(
int)) && ...)) {
44 throw RuntimeError(std::make_shared<Token>(op),
45 "Operands must be numbers.");
49bool Interpreter::isTruthy(
const std::any &value)
const {
50 if (value.type() ==
typeid(std::nullptr_t)) {
52 }
else if (value.type() ==
typeid(
int)) {
53 return std::any_cast<
int>(value) != 0;
54 }
else if (value.type() ==
typeid(std::string)) {
55 return !std::any_cast<std::string>(value)
57 }
else if (value.type() ==
typeid(
bool)) {
58 return std::any_cast<
bool>(value);
63bool Interpreter::isEqual(
const std::any &a,
const std::any &b)
const {
64 if (a.type() != b.type()) {
66 }
else if (a.type() ==
typeid(std::nullptr_t)) {
68 }
else if (a.type() ==
typeid(
bool)) {
69 return std::any_cast<
bool>(a) == std::any_cast<
bool>(b);
70 }
else if (a.type() ==
typeid(
int)) {
71 return std::any_cast<
int>(a) == std::any_cast<
int>(b);
72 }
else if (a.type() ==
typeid(std::string)) {
73 return std::any_cast<std::string>(a) == std::any_cast<std::string>(b);
79std::string Interpreter::stringify(
const std::any &value)
const {
80 if (value.type() ==
typeid(std::nullptr_t)) {
82 }
else if (value.type() ==
typeid(
bool)) {
83 return std::any_cast<
bool>(value) ?
"true" :
"false";
84 }
else if (value.type() ==
typeid(
int)) {
85 return std::to_string(std::any_cast<
int>(value));
86 }
else if (value.type() ==
typeid(std::string)) {
87 return std::any_cast<std::string>(value);
88 }
else if (value.type() ==
typeid(
const char *)) {
89 return std::any_cast<
const char *>(value);
91 return "Internal error (interpreter): object type not recognized";
95std::any Interpreter::visitGroupingExpr(std::shared_ptr<Grouping> expr) {
96 return evaluate(expr->getExpression());
99std::any Interpreter::visitLiteralExpr(std::shared_ptr<Literal> expr) {
100 return expr->getValue();
103std::any Interpreter::visitUnaryExpr(std::shared_ptr<Unary> expr) {
104 std::any right = evaluate(expr->getRight());
105 Token op = expr->getOp();
107 switch (op.getType()) {
108 case TokenType::MINUS:
109 checkNumberOperands(op, right);
110 return -std::any_cast<
int>(right);
111 case TokenType::BANG:
112 return !isTruthy(right);
115 assert(
false &&
"Unknown unary operator");
120std::any Interpreter::visitBinaryExpr(std::shared_ptr<Binary> expr) {
121 std::any left = evaluate(expr->getLeft());
122 std::any right = evaluate(expr->getRight());
123 Token op = expr->getOp();
125 switch (op.getType()) {
126 case TokenType::PLUS:
127 if (left.type() ==
typeid(
int) && right.type() ==
typeid(
int)) {
128 return std::any_cast<
int>(left) + std::any_cast<
int>(right);
129 }
else if (left.type() ==
typeid(std::string) &&
130 right.type() ==
typeid(std::string)) {
131 return std::any_cast<std::string>(left) +
132 std::any_cast<std::string>(right);
134 throw RuntimeError(std::make_shared<Token>(op),
135 "Operands must be two numbers or two strings.");
137 case TokenType::MINUS:
138 checkNumberOperands(op, left, right);
139 return std::any_cast<
int>(left) - std::any_cast<
int>(right);
140 case TokenType::STAR:
141 checkNumberOperands(op, left, right);
142 return std::any_cast<
int>(left) * std::any_cast<
int>(right);
143 case TokenType::SLASH:
144 checkNumberOperands(op, left, right);
145 if (std::any_cast<
int>(right) == 0) {
146 throw RuntimeError(std::make_shared<Token>(op),
"Division by zero.");
148 return std::any_cast<
int>(left) / std::any_cast<
int>(right);
149 case TokenType::GREATER:
150 checkNumberOperands(op, left, right);
151 return std::any_cast<
int>(left) > std::any_cast<
int>(right);
152 case TokenType::GREATER_EQUAL:
153 checkNumberOperands(op, left, right);
154 return std::any_cast<
int>(left) >= std::any_cast<
int>(right);
155 case TokenType::LESS:
156 checkNumberOperands(op, left, right);
157 return std::any_cast<
int>(left) < std::any_cast<
int>(right);
158 case TokenType::LESS_EQUAL:
159 checkNumberOperands(op, left, right);
160 return std::any_cast<
int>(left) <= std::any_cast<
int>(right);
161 case TokenType::EQUAL_EQUAL:
162 return isEqual(left, right);
163 case TokenType::BANG_EQUAL:
164 return !isEqual(left, right);
167 assert(
false &&
"Unknown binary operator");
172std::any Interpreter::visitLogicalExpr(std::shared_ptr<Logical> expr) {
173 std::any left = evaluate(expr->getLeft());
174 Token op = expr->getOp();
177 if ((op.getType() == TokenType::OR && isTruthy(left)) ||
178 (op.getType() == TokenType::AND && !isTruthy(left))) {
182 return evaluate(expr->getRight());
185std::any Interpreter::visitAssignExpr(std::shared_ptr<Assign> expr) {
186 std::any value = evaluate(expr->getValue());
187 environment->assign(expr->getName(), value);
191std::any Interpreter::visitVariableExpr(std::shared_ptr<Variable> expr) {
192 return environment->get(expr->getName());
195std::any Interpreter::visitBlockStmt(std::shared_ptr<Block> stmt) {
196 executeBlock(stmt->getStatements(),
197 std::make_shared<Environment>(environment));
201std::any Interpreter::visitExpressionStmt(std::shared_ptr<Expression> stmt) {
202 evaluate(stmt->getExpression());
206std::any Interpreter::visitPrintStmt(std::shared_ptr<Print> stmt) {
207 std::any value = evaluate(stmt->getExpression());
208 std::cout << stringify(value) << std::endl;
212std::any Interpreter::visitIfStmt(std::shared_ptr<If> stmt) {
213 std::any condition = evaluate(stmt->getCondition());
214 if (isTruthy(condition)) {
215 execute(stmt->getThenBranch());
216 }
else if (stmt->getElseBranch()) {
217 execute(stmt->getElseBranch());
222std::any Interpreter::visitWhileStmt(std::shared_ptr<While> stmt) {
223 while (isTruthy(evaluate(stmt->getCondition()))) {
224 execute(stmt->getBody());
229std::any Interpreter::visitVarStmt(std::shared_ptr<Var> stmt) {
230 std::any value =
nullptr;
231 if (stmt->getInitializer()) {
232 value = evaluate(stmt->getInitializer());
234 environment->define(stmt->getName().getLexeme(), std::move(value));