P5.7 Step C: delete interp.zig — the comptime VM is the sole evaluator

The legacy tagged-Value Interpreter is gone. Relocate the Value result-DTO
+ decodeVariantElements into a new comptime_value.zig (the VM<->host
materialization boundary); repoint comptime_vm/emit_llvm/ir-barrel Value to
it and BuildConfig to compiler_hooks; delete the dead valueToReg bridge;
slim compiler_lib.zig to just the name registry (BoundFn{sx_name} + bound_fns
+ findFn — weldedCompilerFn only validates names); simplify printInterpBailDiag
to comptime_vm.last_bail_reason; drop the unused interp_mod import in lower.zig.
rm src/ir/interp.zig + interp.test.zig.

Value is relocated (not eliminated): it survives only as the slim result DTO
at the VM->valueToLLVMConst boundary; the execution-time marshaling the VM
pivot targeted is gone. Drop dead Value.asString/reflectTypeId.

706/0 corpus + 476/476 unit.
This commit is contained in:
agra
2026-06-19 20:05:57 +03:00
parent 103a156b26
commit 7b8be86834
11 changed files with 217 additions and 3721 deletions

108
src/ir/comptime_value.zig Normal file
View File

@@ -0,0 +1,108 @@
//! Comptime VALUE — the result/materialization representation produced by the
//! comptime VM (`comptime_vm.regToValue`) and consumed by
//! `emit_llvm.valueToLLVMConst`. The byte-addressable VM executes natively;
//! this type is only the result DTO at the VM↔host boundary.
const std = @import("std");
const types = @import("types.zig");
const inst_mod = @import("inst.zig");
const TypeId = types.TypeId;
const FuncId = inst_mod.FuncId;
// ── Value ───────────────────────────────────────────────────────────────
pub const Value = union(enum) {
int: i64,
float: f64,
boolean: bool,
string: []const u8,
null_val,
void_val,
undef,
aggregate: []const Value,
slot_ptr: u32, // index into the frame's local slots
func_ref: FuncId,
closure: ClosureVal,
type_tag: TypeId,
heap_ptr: HeapPtr, // pointer into heap-allocated memory
/// Byte-granular raw pointer. Produced by `index_gep` on a string /
/// `[*]u8` aggregate whose data field is itself a raw integer pointer
/// (e.g. from libc_malloc). Store/load through this variant operate
/// on a single byte — matching the heap_ptr semantics for the same
/// op shape.
byte_ptr: usize,
pub const ClosureVal = struct {
func: FuncId,
env: ?[]const Value,
};
/// A pointer to heap-allocated memory, with an optional byte offset.
pub const HeapPtr = struct {
id: u32, // index into the legacy heap (historical)
offset: u32 = 0,
};
pub fn asInt(self: Value) ?i64 {
return switch (self) {
.int => |v| v,
else => null,
};
}
pub fn asFloat(self: Value) ?f64 {
return switch (self) {
.float => |v| v,
.int => |v| @floatFromInt(v), // implicit int→float for convenience
else => null,
};
}
pub fn asBool(self: Value) ?bool {
return switch (self) {
.boolean => |v| v,
else => null,
};
}
pub fn isNull(self: Value) bool {
return self == .null_val;
}
/// Extract the TypeId from a first-class Type value. Returns null
/// for anything else — including `.int(N)` where N happens to be
/// a valid TypeId enum value. The kinds are distinct: a Type IS
/// NOT an int. Use this helper instead of `asInt` when reading a
/// TypeId out of a Value to keep the kind-distinction honest.
pub fn asTypeId(self: Value) ?TypeId {
return switch (self) {
.type_tag => |id| id,
else => null,
};
}
};
/// Normalize a comptime value into the list of EnumVariant element values.
/// A `[]EnumVariant` slice evaluates to a `{ data, len }` aggregate (`len` an
/// int); a `[N]EnumVariant` array literal evaluates to the element aggregate
/// directly. Returns null for any other shape (the caller bails loudly).
pub fn decodeVariantElements(result: Value) ?[]const Value {
const fields = switch (result) {
.aggregate => |f| f,
else => return null,
};
// Slice fat pointer `{ data, len }`: a 2-field aggregate whose 2nd field is
// an integer length. (A 2-VARIANT array can't collide — its 2nd field is an
// EnumVariant aggregate, so `asInt` is null.)
if (fields.len == 2) {
if (fields[1].asInt()) |len_i| {
const len: usize = @intCast(len_i);
switch (fields[0]) {
.aggregate => |arr| return if (len <= arr.len) arr[0..len] else null,
else => return null,
}
}
}
return fields;
}