// // Created by Bobby Lucero on 5/27/23. // #include #include #include #include #include #include "../headers/Interpreter.h" #include "../headers/helperFunctions/HelperFunctions.h" sptr(Object) Interpreter::visitLiteralExpr(sptr(LiteralExpr) expr) { if(expr->isNull) return msptr(None)(); if(expr->isNumber){ double num; if(expr->value[1] == 'b') { num = binaryStringToLong(expr->value); } else { num = std::stod(expr->value); } return msptr(Number)(num); } return msptr(String)(expr->value); } sptr(Object) Interpreter::visitGroupingExpr(sptr(GroupingExpr) expression) { return evaluate(expression->expression); } sptr(Object) Interpreter::visitUnaryExpr(sptr(UnaryExpr) expression) { sptr(Object) right = evaluate(expression->right); if(expression->oper.type == MINUS) { if(std::dynamic_pointer_cast(right)) { double value = std::dynamic_pointer_cast(right)->value; return msptr(Number)(-value); } else { throw std::runtime_error("Operand must be a number when using: " + expression->oper.lexeme); } } if(expression->oper.type == BANG) { return msptr(Boolean)(!isTruthy(right)); } } sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression) { sptr(Object) left = evaluate(expression->left); sptr(Object) right = evaluate(expression->right); switch (expression->oper.type) { case BANG_EQUAL: return msptr(Boolean)(!isEqual(left, right)); case DOUBLE_EQUAL: return msptr(Boolean)(isEqual(left, right)); default: ; } if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) { double left_double = std::dynamic_pointer_cast(left)->value; double right_double = std::dynamic_pointer_cast(right)->value; switch (expression->oper.type) { case GREATER: return msptr(Boolean)(left_double > right_double); case GREATER_EQUAL: return msptr(Boolean)(left_double >= right_double); case LESS: return msptr(Boolean)(left_double < right_double); case LESS_EQUAL: return msptr(Boolean)(left_double <= right_double); case MINUS: return msptr(Number)(left_double - right_double); case PLUS: return msptr(Number)(left_double + right_double); case SLASH: return msptr(Number)(left_double / right_double); case STAR: return msptr(Number)(left_double * right_double); default: return msptr(None)(); //unreachable } } else if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) { switch (expression->oper.type) { case PLUS: std::string left_string = std::dynamic_pointer_cast(left)->value; std::string right_string = std::dynamic_pointer_cast(right)->value; return msptr(String)(left_string + right_string); } throw std::runtime_error("Cannot use '" + expression->oper.lexeme + "' on two strings"); } else if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) { switch (expression->oper.type) { case STAR: std::string left_string = std::dynamic_pointer_cast(left)->value; double right_number = std::dynamic_pointer_cast(right)->value; if(isWholeNumer(right_number)) { std::stringstream ss; for (int i = 0; i < (int)right_number; ++i) { ss << left_string; } return msptr(String)(ss.str()); } else { throw std::runtime_error("String multiplier must be whole number"); } } throw std::runtime_error("Cannot use '" + expression->oper.lexeme + "' on a string and a number"); } else { throw std::runtime_error("Operands must be of same type when using: " + expression->oper.lexeme); } } sptr(Object) Interpreter::evaluate(sptr(Expr) expr) { return expr->accept(this); } bool Interpreter::isTruthy(sptr(Object) object) { if(auto boolean = std::dynamic_pointer_cast(object)) { boolean->value; } if(auto obj = std::dynamic_pointer_cast(object)) { return false; } return true; } bool Interpreter::isEqual(sptr(Object) a, sptr(Object) b) { if(auto left = std::dynamic_pointer_cast(a)) { if(auto right = std::dynamic_pointer_cast(b)) { return left->value == right->value; } return false; } else if(auto left = std::dynamic_pointer_cast(a)) { if(auto right = std::dynamic_pointer_cast(b)) { return left->value == right->value; } return false; } else if(auto left = std::dynamic_pointer_cast(a)) { if(auto right = std::dynamic_pointer_cast(b)) { return left->value == right->value; } return false; } else if(auto left = std::dynamic_pointer_cast(a)) { if(auto right = std::dynamic_pointer_cast(b)) { return true; } return false; } } void Interpreter::interpret(std::shared_ptr expr) { sptr(Object) value = evaluate(std::move(expr)); std::cout << "\033[0;32m" << stringify(value) << std::endl; } std::string Interpreter::stringify(std::shared_ptr object) { if(std::dynamic_pointer_cast(object)) { return "None"; } else if(auto num = std::dynamic_pointer_cast(object)) { double integral = num->value; double fractional = std::modf(num->value, &integral); std::stringstream ss; if(std::abs(fractional) < std::numeric_limits::epsilon()) { ss << std::fixed << std::setprecision(0) << integral; return ss.str(); } else { ss << std::fixed << std::setprecision(std::numeric_limits::digits10 - 1) << num->value; std::string str = ss.str(); str.erase(str.find_last_not_of('0') + 1, std::string::npos); if (str.back() == '.') { str.pop_back(); } return str; } } else if(auto string = std::dynamic_pointer_cast(object)) { return string->value; } else if(auto Bool = std::dynamic_pointer_cast(object)) { return Bool->value == 1 ? "true" : "false"; } } bool Interpreter::isWholeNumer(double num) { double integral = num; double fractional = std::modf(num, &integral); if(std::abs(fractional) < std::numeric_limits::epsilon()) { return true; } else { return false; } }