Files
camellya/interpreter.h
2026-01-13 22:52:55 +08:00

152 lines
4.7 KiB
C++

#ifndef CAMELLYA_INTERPRETER_H
#define CAMELLYA_INTERPRETER_H
#include "ast.h"
#include "value.h"
#include <map>
#include <memory>
#include <stdexcept>
namespace camellya {
class RuntimeError : public std::runtime_error {
public:
explicit RuntimeError(const std::string& message) : std::runtime_error(message) {}
};
class ReturnException : public std::exception {
public:
ValuePtr value;
explicit ReturnException(ValuePtr value) : value(std::move(value)) {}
};
class Environment {
public:
std::shared_ptr<Environment> parent;
std::map<std::string, ValuePtr> values;
Environment() : parent(nullptr) {}
explicit Environment(std::shared_ptr<Environment> parent) : parent(std::move(parent)) {}
void define(const std::string& name, ValuePtr value) {
values[name] = std::move(value);
}
ValuePtr get(const std::string& name) const {
auto it = values.find(name);
if (it != values.end()) {
return it->second;
}
if (parent && parent->has(name)) {
return parent->get(name);
}
// Fallback: resolve as field on 'this' instance if present
const Environment* env = this;
while (env) {
auto this_it = env->values.find("this");
if (this_it != env->values.end() &&
this_it->second && this_it->second->type() == Type::INSTANCE) {
auto instance = std::dynamic_pointer_cast<InstanceValue>(this_it->second);
auto field_it = instance->fields.find(name);
if (field_it != instance->fields.end()) {
return field_it->second;
}
break;
}
env = env->parent.get();
}
throw RuntimeError("Undefined variable '" + name + "'.");
}
void set(const std::string& name, ValuePtr value) {
auto it = values.find(name);
if (it != values.end()) {
it->second = std::move(value);
return;
}
if (parent && parent->has(name)) {
parent->set(name, std::move(value));
return;
}
// Fallback: assign to field on 'this' instance if present
Environment* env = this;
while (env) {
auto this_it = env->values.find("this");
if (this_it != env->values.end() &&
this_it->second && this_it->second->type() == Type::INSTANCE) {
auto instance = std::dynamic_pointer_cast<InstanceValue>(this_it->second);
auto field_it = instance->fields.find(name);
if (field_it != instance->fields.end()) {
field_it->second = std::move(value);
return;
}
break;
}
env = env->parent.get();
}
throw RuntimeError("Undefined variable '" + name + "'.");
}
bool has(const std::string& name) const {
if (values.find(name) != values.end()) {
return true;
}
if (parent) {
return parent->has(name);
}
return false;
}
};
class Interpreter {
public:
Interpreter();
void execute(const Program& program);
ValuePtr evaluate(const Expr& expr);
void execute_statement(const Stmt& stmt);
std::shared_ptr<Environment> environment;
std::shared_ptr<Environment> global_environment;
private:
void register_native_functions();
ValuePtr eval_binary(const BinaryExpr& expr);
ValuePtr eval_unary(const UnaryExpr& expr);
ValuePtr eval_literal(const LiteralExpr& expr);
ValuePtr eval_variable(const VariableExpr& expr);
ValuePtr eval_assign(const AssignExpr& expr);
ValuePtr eval_call(const CallExpr& expr);
ValuePtr eval_get(const GetExpr& expr);
ValuePtr eval_set(const SetExpr& expr);
ValuePtr eval_index(const IndexExpr& expr);
ValuePtr eval_index_set(const IndexSetExpr& expr);
ValuePtr eval_list(const ListExpr& expr);
ValuePtr eval_map(const MapExpr& expr);
void exec_expr_stmt(const ExprStmt& stmt);
void exec_var_decl(const VarDecl& stmt);
void exec_block(const BlockStmt& stmt);
void exec_if(const IfStmt& stmt);
void exec_while(const WhileStmt& stmt);
void exec_for(const ForStmt& stmt);
void exec_return(const ReturnStmt& stmt);
void exec_function_decl(const FunctionDecl& stmt);
void exec_class_decl(const ClassDecl& stmt);
ValuePtr call_function(const FunctionValue& func, const std::vector<ValuePtr>& arguments);
ValuePtr create_default_value(const std::string& type_name);
};
} // namespace camellya
#endif // CAMELLYA_INTERPRETER_H