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.
109 lines
3.7 KiB
Zig
109 lines
3.7 KiB
Zig
//! 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;
|
|
}
|