#pragma once #include "Expression.h" #include "Statement.h" #include "helperFunctions/ShortHands.h" #include "TypeWrapper.h" #include "Environment.h" #include "Value.h" #include "StdLib.h" #include "ErrorReporter.h" #include #include #include #include #include #include // Forward declaration class Interpreter; // RAII helper for thunk execution flag struct ScopedThunkFlag { bool& flag; bool prev; ScopedThunkFlag(bool& f) : flag(f), prev(f) { flag = true; } ~ScopedThunkFlag() { flag = prev; } }; // Thunk class for trampoline-based tail call optimization class Thunk { public: using ThunkFunction = std::function; explicit Thunk(ThunkFunction func) : func(std::move(func)) {} Value execute() const { return func(); } bool isThunk() const { return true; } private: ThunkFunction func; }; class Interpreter : public ExprVisitor, public StmtVisitor { public: Value visitBinaryExpr(const std::shared_ptr& expression) override; Value visitCallExpr(const std::shared_ptr& expression) override; Value visitFunctionExpr(const std::shared_ptr& expression) override; Value visitGroupingExpr(const std::shared_ptr& expression) override; Value visitLiteralExpr(const std::shared_ptr& expression) override; Value visitUnaryExpr(const std::shared_ptr& expression) override; Value visitVarExpr(const std::shared_ptr& expression) override; Value visitIncrementExpr(const std::shared_ptr& expression) override; Value visitAssignExpr(const std::shared_ptr& expression) override; void visitBlockStmt(const std::shared_ptr& statement, ExecutionContext* context = nullptr) override; void visitExpressionStmt(const std::shared_ptr& statement, ExecutionContext* context = nullptr) override; void visitVarStmt(const std::shared_ptr& statement, ExecutionContext* context = nullptr) override; void visitFunctionStmt(const std::shared_ptr& statement, ExecutionContext* context = nullptr) override; void visitReturnStmt(const std::shared_ptr& statement, ExecutionContext* context = nullptr) override; void visitIfStmt(const std::shared_ptr& statement, ExecutionContext* context = nullptr) override; void interpret(std::vector > statements); explicit Interpreter(bool IsInteractive) : IsInteractive(IsInteractive), errorReporter(nullptr){ environment = std::make_shared(); } virtual ~Interpreter() = default; private: std::shared_ptr environment; bool IsInteractive; std::vector > builtinFunctions; std::vector > functions; ErrorReporter* errorReporter; bool inThunkExecution = false; Value evaluate(const std::shared_ptr& expr); Value evaluateWithoutTrampoline(const std::shared_ptr& expr); bool isEqual(Value a, Value b); bool isWholeNumer(double num); void execute(const std::shared_ptr& statement, ExecutionContext* context = nullptr); void executeBlock(std::vector > statements, std::shared_ptr env, ExecutionContext* context = nullptr); void addStdLibFunctions(); // Trampoline execution Value runTrampoline(Value initialResult); public: bool isTruthy(Value object); std::string stringify(Value object); void addBuiltinFunction(std::shared_ptr func); // Error reporting void setErrorReporter(ErrorReporter* reporter) { errorReporter = reporter; if (environment) { environment->setErrorReporter(reporter); } // Add standard library functions after error reporter is set addStdLibFunctions(); } };