#include "interpreter.h" #include #include #include namespace camellya { Interpreter::Interpreter() { global_environment = std::make_shared(); environment = global_environment; register_native_functions(); } void Interpreter::register_native_functions() { // print function - supports format strings auto print_func = std::make_shared("print", [](const std::vector& args) -> ValuePtr { if (args.empty()) { std::cout << std::endl; return std::make_shared(); } // Simple print: just concatenate all arguments for (size_t i = 0; i < args.size(); ++i) { if (i > 0) std::cout << " "; std::cout << args[i]->to_string(); } std::cout << std::endl; return std::make_shared(); }); global_environment->define("print", print_func); // len function auto len_func = std::make_shared("len", [](const std::vector& args) -> ValuePtr { if (args.size() != 1) { throw RuntimeError("len() expects 1 argument."); } auto& arg = args[0]; if (arg->type() == Type::LIST) { auto list = std::dynamic_pointer_cast(arg); return std::make_shared(static_cast(list->size())); } else if (arg->type() == Type::STRING) { auto str = std::dynamic_pointer_cast(arg); return std::make_shared(static_cast(str->value.length())); } else if (arg->type() == Type::MAP) { auto map = std::dynamic_pointer_cast(arg); return std::make_shared(static_cast(map->pairs.size())); } throw RuntimeError("len() expects list, string, or map."); }); global_environment->define("len", len_func); } void Interpreter::execute(const Program& program) { for (const auto& stmt : program.statements) { execute_statement(*stmt); } } ValuePtr Interpreter::evaluate(const Expr& expr) { if (auto* binary = dynamic_cast(&expr)) { return eval_binary(*binary); } else if (auto* unary = dynamic_cast(&expr)) { return eval_unary(*unary); } else if (auto* literal = dynamic_cast(&expr)) { return eval_literal(*literal); } else if (auto* variable = dynamic_cast(&expr)) { return eval_variable(*variable); } else if (auto* assign = dynamic_cast(&expr)) { return eval_assign(*assign); } else if (auto* call = dynamic_cast(&expr)) { return eval_call(*call); } else if (auto* get = dynamic_cast(&expr)) { return eval_get(*get); } else if (auto* set = dynamic_cast(&expr)) { return eval_set(*set); } else if (auto* index = dynamic_cast(&expr)) { return eval_index(*index); } else if (auto* index_set = dynamic_cast(&expr)) { return eval_index_set(*index_set); } else if (auto* list = dynamic_cast(&expr)) { return eval_list(*list); } else if (auto* map = dynamic_cast(&expr)) { return eval_map(*map); } throw RuntimeError("Unknown expression type."); } void Interpreter::execute_statement(const Stmt& stmt) { if (auto* expr_stmt = dynamic_cast(&stmt)) { exec_expr_stmt(*expr_stmt); } else if (auto* var_decl = dynamic_cast(&stmt)) { exec_var_decl(*var_decl); } else if (auto* block = dynamic_cast(&stmt)) { exec_block(*block); } else if (auto* if_stmt = dynamic_cast(&stmt)) { exec_if(*if_stmt); } else if (auto* while_stmt = dynamic_cast(&stmt)) { exec_while(*while_stmt); } else if (auto* for_stmt = dynamic_cast(&stmt)) { exec_for(*for_stmt); } else if (auto* return_stmt = dynamic_cast(&stmt)) { exec_return(*return_stmt); } else if (auto* func_decl = dynamic_cast(&stmt)) { exec_function_decl(*func_decl); } else if (auto* class_decl = dynamic_cast(&stmt)) { exec_class_decl(*class_decl); } } ValuePtr Interpreter::eval_binary(const BinaryExpr& expr) { ValuePtr left = evaluate(*expr.left); ValuePtr right = evaluate(*expr.right); if (expr.op == "+") { if (left->type() == Type::NUMBER && right->type() == Type::NUMBER) { double l = std::dynamic_pointer_cast(left)->value; double r = std::dynamic_pointer_cast(right)->value; return std::make_shared(l + r); } if (left->type() == Type::STRING && right->type() == Type::STRING) { const auto& l = std::dynamic_pointer_cast(left)->value; const auto& r = std::dynamic_pointer_cast(right)->value; return std::make_shared(l + r); } throw RuntimeError("Operands of '+' must be both numbers or both strings."); } if (expr.op == "-" || expr.op == "*" || expr.op == "/" || expr.op == "%") { if (left->type() != Type::NUMBER || right->type() != Type::NUMBER) { throw RuntimeError("Operands must be numbers."); } double l = std::dynamic_pointer_cast(left)->value; double r = std::dynamic_pointer_cast(right)->value; if (expr.op == "-") return std::make_shared(l - r); if (expr.op == "*") return std::make_shared(l * r); if (expr.op == "/") { if (r == 0) throw RuntimeError("Division by zero."); return std::make_shared(l / r); } if (expr.op == "%") return std::make_shared(std::fmod(l, r)); } if (expr.op == "==" ) { return std::make_shared(values_equal(left, right)); } if (expr.op == "!=") { return std::make_shared(!values_equal(left, right)); } if (expr.op == "<" || expr.op == "<=" || expr.op == ">" || expr.op == ">=") { if (left->type() != Type::NUMBER || right->type() != Type::NUMBER) { throw RuntimeError("Operands must be numbers."); } double l = std::dynamic_pointer_cast(left)->value; double r = std::dynamic_pointer_cast(right)->value; if (expr.op == "<") return std::make_shared(l < r); if (expr.op == "<=") return std::make_shared(l <= r); if (expr.op == ">") return std::make_shared(l > r); if (expr.op == ">=") return std::make_shared(l >= r); } if (expr.op == "and") { if (!is_truthy(left)) return left; return right; } if (expr.op == "or") { if (is_truthy(left)) return left; return right; } throw RuntimeError("Unknown binary operator: " + expr.op); } ValuePtr Interpreter::eval_unary(const UnaryExpr& expr) { ValuePtr operand = evaluate(*expr.operand); if (expr.op == "-") { if (operand->type() != Type::NUMBER) { throw RuntimeError("Operand must be a number."); } double value = std::dynamic_pointer_cast(operand)->value; return std::make_shared(-value); } if (expr.op == "!") { return std::make_shared(!is_truthy(operand)); } throw RuntimeError("Unknown unary operator: " + expr.op); } ValuePtr Interpreter::eval_literal(const LiteralExpr& expr) { return std::visit([](auto&& arg) -> ValuePtr { using T = std::decay_t; if constexpr (std::is_same_v) { return std::make_shared(arg); } else if constexpr (std::is_same_v) { return std::make_shared(arg); } else if constexpr (std::is_same_v) { return std::make_shared(arg); } else { return std::make_shared(); } }, expr.value); } ValuePtr Interpreter::eval_variable(const VariableExpr& expr) { return environment->get(expr.name); } ValuePtr Interpreter::eval_assign(const AssignExpr& expr) { ValuePtr value = evaluate(*expr.value); environment->set(expr.name, value); return value; } ValuePtr Interpreter::eval_call(const CallExpr& expr) { ValuePtr callee = evaluate(*expr.callee); std::vector arguments; for (const auto& arg : expr.arguments) { arguments.push_back(evaluate(*arg)); } if (callee->type() == Type::FUNCTION) { auto func = std::dynamic_pointer_cast(callee); return call_function(*func, arguments); } else if (callee->type() == Type::CLASS) { // Class instantiation auto klass = std::dynamic_pointer_cast(callee); auto instance = std::make_shared(klass); // If there is an init method, call it like a constructor ValuePtr init_val = instance->get("init"); if (init_val && init_val->type() == Type::FUNCTION) { auto init_func = std::dynamic_pointer_cast(init_val); call_function(*init_func, arguments); } return instance; } throw RuntimeError("Can only call functions and classes."); } ValuePtr Interpreter::eval_get(const GetExpr& expr) { ValuePtr object = evaluate(*expr.object); if (object->type() == Type::INSTANCE) { auto instance = std::dynamic_pointer_cast(object); return instance->get(expr.name); } throw RuntimeError("Only instances have properties."); } ValuePtr Interpreter::eval_set(const SetExpr& expr) { ValuePtr object = evaluate(*expr.object); if (object->type() == Type::INSTANCE) { auto instance = std::dynamic_pointer_cast(object); ValuePtr value = evaluate(*expr.value); instance->set(expr.name, value); return value; } throw RuntimeError("Only instances have fields."); } ValuePtr Interpreter::eval_index(const IndexExpr& expr) { ValuePtr object = evaluate(*expr.object); ValuePtr index = evaluate(*expr.index); if (object->type() == Type::LIST) { auto list = std::dynamic_pointer_cast(object); if (index->type() != Type::NUMBER) { throw RuntimeError("List index must be a number."); } size_t idx = static_cast(std::dynamic_pointer_cast(index)->value); return list->get(idx); } else if (object->type() == Type::MAP) { auto map = std::dynamic_pointer_cast(object); if (index->type() != Type::STRING) { throw RuntimeError("Map key must be a string."); } std::string key = std::dynamic_pointer_cast(index)->value; return map->get(key); } throw RuntimeError("Only lists and maps support indexing."); } ValuePtr Interpreter::eval_index_set(const IndexSetExpr& expr) { ValuePtr object = evaluate(*expr.object); ValuePtr index = evaluate(*expr.index); ValuePtr value = evaluate(*expr.value); if (object->type() == Type::LIST) { auto list = std::dynamic_pointer_cast(object); if (index->type() != Type::NUMBER) { throw RuntimeError("List index must be a number."); } size_t idx = static_cast(std::dynamic_pointer_cast(index)->value); list->set(idx, value); return value; } else if (object->type() == Type::MAP) { auto map = std::dynamic_pointer_cast(object); if (index->type() != Type::STRING) { throw RuntimeError("Map key must be a string."); } std::string key = std::dynamic_pointer_cast(index)->value; map->set(key, value); return value; } throw RuntimeError("Only lists and maps support index assignment."); } ValuePtr Interpreter::eval_list(const ListExpr& expr) { auto list = std::make_shared(); for (const auto& elem : expr.elements) { list->push(evaluate(*elem)); } return list; } ValuePtr Interpreter::eval_map(const MapExpr& expr) { auto map = std::make_shared(); for (const auto& [key_expr, value_expr] : expr.pairs) { ValuePtr key = evaluate(*key_expr); ValuePtr value = evaluate(*value_expr); if (key->type() != Type::STRING) { throw RuntimeError("Map keys must be strings."); } std::string key_str = std::dynamic_pointer_cast(key)->value; map->set(key_str, value); } return map; } void Interpreter::exec_expr_stmt(const ExprStmt& stmt) { evaluate(*stmt.expression); } void Interpreter::exec_var_decl(const VarDecl& stmt) { ValuePtr value; if (stmt.initializer) { value = evaluate(*stmt.initializer); } else { value = create_default_value(stmt.type_name); } environment->define(stmt.name, value); } void Interpreter::exec_block(const BlockStmt& stmt) { auto previous = environment; environment = std::make_shared(environment); try { for (const auto& statement : stmt.statements) { execute_statement(*statement); } } catch (...) { environment = previous; throw; } environment = previous; } void Interpreter::exec_if(const IfStmt& stmt) { ValuePtr condition = evaluate(*stmt.condition); if (is_truthy(condition)) { execute_statement(*stmt.then_branch); } else if (stmt.else_branch) { execute_statement(*stmt.else_branch); } } void Interpreter::exec_while(const WhileStmt& stmt) { while (is_truthy(evaluate(*stmt.condition))) { execute_statement(*stmt.body); } } void Interpreter::exec_for(const ForStmt& stmt) { auto previous = environment; environment = std::make_shared(environment); try { if (stmt.initializer) { execute_statement(*stmt.initializer); } while (!stmt.condition || is_truthy(evaluate(*stmt.condition))) { execute_statement(*stmt.body); if (stmt.increment) { evaluate(*stmt.increment); } } } catch (...) { environment = previous; throw; } environment = previous; } void Interpreter::exec_return(const ReturnStmt& stmt) { ValuePtr value = stmt.value ? evaluate(*stmt.value) : std::make_shared(); throw ReturnException(value); } void Interpreter::exec_function_decl(const FunctionDecl& stmt) { auto func_decl = std::make_shared(stmt); auto func = std::make_shared(stmt.name, func_decl); environment->define(stmt.name, func); } void Interpreter::exec_class_decl(const ClassDecl& stmt) { auto klass = std::make_shared(stmt.name); for (const auto& member : stmt.members) { if (auto* var_decl = dynamic_cast(member.get())) { klass->add_field(var_decl->name, var_decl->type_name); } else if (auto* func_decl = dynamic_cast(member.get())) { auto func_decl_ptr = std::make_shared(*func_decl); auto func = std::make_shared(func_decl->name, func_decl_ptr); klass->add_method(func_decl->name, func); } } environment->define(stmt.name, klass); } ValuePtr Interpreter::call_function(const FunctionValue& func, const std::vector& arguments) { if (func.is_native) { return func.native_func(arguments); } // Bind parameters if (func.declaration->parameters.size() != arguments.size()) { throw RuntimeError(std::format("Expected {} arguments but got {}.", func.declaration->parameters.size(), arguments.size())); } auto previous = environment; environment = std::make_shared(global_environment); // Bind 'this' for methods if (func.bound_instance) { environment->define("this", func.bound_instance); } // Bind parameters to the new environment for (size_t i = 0; i < arguments.size(); ++i) { environment->define(func.declaration->parameters[i].second, arguments[i]); } try { execute_statement(*func.declaration->body); } catch (const ReturnException& ret) { environment = previous; return ret.value; } environment = previous; return std::make_shared(); } ValuePtr Interpreter::create_default_value(const std::string& type_name) { if (type_name == "number") { return std::make_shared(0.0); } else if (type_name == "string") { return std::make_shared(""); } else if (type_name == "bool") { return std::make_shared(false); } else if (type_name == "list") { return std::make_shared(); } else if (type_name == "map") { return std::make_shared(); } else if (environment->has(type_name)) { // It's a class type ValuePtr klass = environment->get(type_name); if (klass->type() == Type::CLASS) { auto klass_ptr = std::dynamic_pointer_cast(klass); auto instance = std::make_shared(klass_ptr); // If the class defines init(), call it with no arguments ValuePtr init_val = instance->get("init"); if (init_val && init_val->type() == Type::FUNCTION) { auto init_func = std::dynamic_pointer_cast(init_val); call_function(*init_func, {}); } return instance; } } return std::make_shared(); } } // namespace camellya