irc: PrimOp memory leak and IR_VERSION mismatch

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Iad057cd5f51ef26e7de93ccca7b3d3156a6a6964
This commit is contained in:
raf 2026-02-24 18:40:29 +03:00
commit 28de44c598
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
2 changed files with 420 additions and 69 deletions

View file

@ -69,8 +69,6 @@ struct Evaluator::Impl {
explicit Impl(EvalState& s) : state(s) {}
// Destructor not needed - unique_ptr handles cleanup automatically
IREnvironment* make_env(IREnvironment* parent = nullptr) {
auto env = new IREnvironment(parent);
environments.push_back(std::unique_ptr<IREnvironment>(env));
@ -99,6 +97,39 @@ struct Evaluator::Impl {
thunks.erase(v);
}
// Copy a forced value into a destination Value
void copy_value(Value& dest, Value* src) {
if (!src)
return;
force(src);
state.forceValue(*src, noPos);
switch (src->type()) {
case nInt:
dest.mkInt(src->integer());
break;
case nBool:
dest.mkBool(src->boolean());
break;
case nString:
dest.mkString(src->c_str());
break;
case nPath:
dest.mkPath(src->path());
break;
case nNull:
dest.mkNull();
break;
case nFloat:
dest.mkFloat(src->fpoint());
break;
default:
// For attrs, lists, functions, etc., direct assignment is safe
// as they use reference counting internally
dest = *src;
break;
}
}
void eval_node(const std::shared_ptr<Node>& node, Value& v, IREnvironment* env) {
if (!node) {
v.mkNull();
@ -151,36 +182,7 @@ struct Evaluator::Impl {
if (!bound) {
state.error<EvalError>("variable not found").debugThrow();
}
force(bound);
// Copy the forced value's data into v
// For simple types, use mk* methods to ensure proper initialization
// For complex types (attrs, lists, functions), direct assignment is safe
state.forceValue(*bound, noPos);
switch (bound->type()) {
case nInt:
v.mkInt(bound->integer());
break;
case nBool:
v.mkBool(bound->boolean());
break;
case nString:
v.mkString(bound->c_str());
break;
case nPath:
v.mkPath(bound->path());
break;
case nNull:
v.mkNull();
break;
case nFloat:
v.mkFloat(bound->fpoint());
break;
default:
// For attrs, lists, functions, etc., direct assignment is safe
// as they use reference counting internally
v = *bound;
break;
}
copy_value(v, bound);
} else if (auto* n = node->get_if<LambdaNode>()) {
auto lambda_env = env;
auto body = n->body;
@ -545,37 +547,7 @@ struct Evaluator::Impl {
auto attr = obj->attrs()->get(sym);
if (attr) {
Value* val = attr->value;
force(val);
// Copy the forced value's data into v
// For simple types, use mk* methods to ensure proper initialization
// For complex types (attrs, lists, functions), direct assignment is safe
state.forceValue(*val, noPos);
switch (val->type()) {
case nInt:
v.mkInt(val->integer());
break;
case nBool:
v.mkBool(val->boolean());
break;
case nString:
v.mkString(val->c_str());
break;
case nPath:
v.mkPath(val->path());
break;
case nNull:
v.mkNull();
break;
case nFloat:
v.mkFloat(val->fpoint());
break;
default:
// For attrs, lists, functions, etc., direct assignment is safe
// as they use reference counting internally
v = *val;
break;
}
copy_value(v, attr->value);
} else if (n->default_expr) {
eval_node(*n->default_expr, v, env);
} else {