152 lines
4.7 KiB
C++
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
|