#include "Interpreter.h" #include "Evaluator.h" #include "Executor.h" #include "BobStdLib.h" #include "ErrorReporter.h" #include "Environment.h" #include "Expression.h" #include Interpreter::Interpreter(bool isInteractive) : isInteractive(isInteractive), errorReporter(nullptr) { evaluator = std::make_unique(this); executor = std::make_unique(this, evaluator.get()); environment = std::make_shared(); } Interpreter::~Interpreter() = default; void Interpreter::interpret(std::vector> statements) { executor->interpret(statements); } void Interpreter::execute(const std::shared_ptr& statement, ExecutionContext* context) { statement->accept(executor.get(), context); } void Interpreter::executeBlock(std::vector> statements, std::shared_ptr env, ExecutionContext* context) { executor->executeBlock(statements, env, context); } Value Interpreter::evaluate(const std::shared_ptr& expr) { Value result = expr->accept(evaluator.get()); if (inThunkExecution) { return result; } return runTrampoline(result); } Value Interpreter::runTrampoline(Value initialResult) { Value current = initialResult; while (current.isThunk()) { current = current.asThunk()->execute(); } return current; } bool Interpreter::isTruthy(Value object) { return diagnostics.isTruthy(object); } bool Interpreter::isEqual(Value a, Value b) { return diagnostics.isEqual(a, b); } std::string Interpreter::stringify(Value object) { return diagnostics.stringify(object); } void Interpreter::addStdLibFunctions() { BobStdLib::addToEnvironment(environment, *this, errorReporter); } void Interpreter::addBuiltinFunction(std::shared_ptr func) { builtinFunctions.push_back(func); } void Interpreter::addFunction(std::shared_ptr function) { functions.push_back(function); } void Interpreter::setErrorReporter(ErrorReporter* reporter) { errorReporter = reporter; if (environment) { environment->setErrorReporter(reporter); } } bool Interpreter::isInteractiveMode() const { return isInteractive; } std::shared_ptr Interpreter::getEnvironment() { return environment; } void Interpreter::setEnvironment(std::shared_ptr env) { environment = env; } void Interpreter::reportError(int line, int column, const std::string& errorType, const std::string& message, const std::string& lexeme) { if (errorReporter) { errorReporter->reportError(line, column, errorType, message, lexeme); } } void Interpreter::cleanupUnusedFunctions() { diagnostics.cleanupUnusedFunctions(functions); } void Interpreter::cleanupUnusedThunks() { diagnostics.cleanupUnusedThunks(thunks); } void Interpreter::forceCleanup() { diagnostics.forceCleanup(builtinFunctions, functions, thunks); } Value Interpreter::evaluateCallExprInline(const std::shared_ptr& expression) { Value callee = evaluate(expression->callee); if (callee.isBuiltinFunction()) { // Handle builtin functions with direct evaluation std::vector arguments; for (const auto& argument : expression->arguments) { arguments.push_back(evaluate(argument)); } BuiltinFunction* builtinFunction = callee.asBuiltinFunction(); return builtinFunction->func(arguments, expression->paren.line, expression->paren.column); } if (!callee.isFunction()) { std::string errorMsg = "Can only call functions, got " + callee.getType(); if (errorReporter) { errorReporter->reportError(expression->paren.line, expression->paren.column, "Runtime Error", errorMsg, ""); } throw std::runtime_error(errorMsg); } Function* function = callee.asFunction(); std::vector arguments; for (const auto& argument : expression->arguments) { arguments.push_back(evaluate(argument)); } // Check arity (like original) if (arguments.size() != function->params.size()) { if (errorReporter) { errorReporter->reportError(expression->paren.line, expression->paren.column, "Runtime Error", "Expected " + std::to_string(function->params.size()) + " arguments but got " + std::to_string(arguments.size()) + ".", ""); } throw std::runtime_error("Expected " + std::to_string(function->params.size()) + " arguments but got " + std::to_string(arguments.size()) + "."); } // Check if this is a tail call for inline TCO if (expression->isTailCall) { auto thunk = std::make_shared([this, function, arguments]() -> Value { ScopedEnv _env(environment); environment = std::make_shared(function->closure); environment->setErrorReporter(errorReporter); for (size_t i = 0; i < function->params.size(); i++) { environment->define(function->params[i], arguments[i]); } ExecutionContext context; context.isFunctionBody = true; ScopedThunkFlag _inThunk(inThunkExecution); for (const auto& stmt : function->body) { stmt->accept(executor.get(), &context); if (context.hasReturn) { return context.returnValue; } } return context.returnValue; }); thunks.push_back(thunk); thunkCreationCount++; if (thunkCreationCount >= CLEANUP_THRESHOLD) { cleanupUnusedThunks(); thunkCreationCount = 0; } return Value(thunk); } else { ScopedEnv _env(environment); environment = std::make_shared(function->closure); environment->setErrorReporter(errorReporter); for (size_t i = 0; i < function->params.size(); i++) { environment->define(function->params[i], arguments[i]); } ExecutionContext context; context.isFunctionBody = true; for (const auto& stmt : function->body) { stmt->accept(executor.get(), &context); if (context.hasReturn) { return context.returnValue; } } return context.returnValue; } }