comptime-API: strip the byte-weld; pivot to a flat-memory comptime VM
The byte-weld (sx structs whose layout was validated to mirror the compiler's Zig records) plus the serialization/marshaling bridge was the wrong direction: it bolted a parallel layout regime and hand-built byte-copies onto a comptime value model that fundamentally isn't bytes. Strip the struct-weld machinery: - compiler_lib.zig loses the type registry (weldStruct / bound_types / BoundType / FieldLayout / findType / SxField / LayoutMismatch / validateStructLayout); it is now just the intern/text_of function host-call bridge (kept as the Phase-3 compiler-call seed). - nominal.zig loses validateWeldedStruct / weldedFieldOrderStr + the sd.abi == .zig validation call. - Remove the struct-weld unit tests and examples 0625/0627 (welded structs) + 1183/1186 (weld-layout diagnostics). - The #library / abi / extern syntax stays. Record the new direction: a bytecode VM over flat, byte-addressable memory so comptime values are native bytes (no weld/validation/marshal), target-aware (preserves cross-compilation) and sandboxed. See current/PLAN-COMPILER-VM.md (Phase 0 strip -> Phase 1 flat-memory value model -> Phase 2 bytecode -> Phase 3 compiler-API on flat memory). design/comptime-compiler-api.md gets a SUPERSEDED banner. Also drop the "~500 lines / split the step" rule from CLAUDE.md.
This commit is contained in:
@@ -1,139 +1,11 @@
|
||||
// Tests for the comptime `compiler` library's binding registry.
|
||||
// Tests for the comptime `compiler` library's function bridge.
|
||||
|
||||
const std = @import("std");
|
||||
const compiler_lib = @import("compiler_lib.zig");
|
||||
const types = @import("types.zig");
|
||||
|
||||
// Lock: `findType("Field")` resolves to the welded `StructInfo.Field` type, and
|
||||
// its baked layout EQUALS the real Zig type's `@sizeOf`/`@alignOf`/`@offsetOf`.
|
||||
// This is the foundation the layout sub-step builds on — the welded record's
|
||||
// offsets come from the implementation, so they can't drift.
|
||||
test "compiler_lib: Field welds to StructInfo.Field's real layout" {
|
||||
const FieldZig = types.TypeInfo.StructInfo.Field;
|
||||
|
||||
const bt = compiler_lib.findType("Field") orelse return error.MissingBoundType;
|
||||
|
||||
try std.testing.expectEqualStrings("Field", bt.sx_name);
|
||||
try std.testing.expectEqual(@sizeOf(FieldZig), bt.size);
|
||||
try std.testing.expectEqual(@alignOf(FieldZig), bt.alignment);
|
||||
|
||||
// Two u32 fields, in declaration order.
|
||||
try std.testing.expectEqual(@as(usize, 2), bt.fields.len);
|
||||
|
||||
try std.testing.expectEqualStrings("name", bt.fields[0].name);
|
||||
try std.testing.expectEqual(@offsetOf(FieldZig, "name"), bt.fields[0].offset);
|
||||
try std.testing.expectEqual(@as(usize, 4), bt.fields[0].size);
|
||||
|
||||
try std.testing.expectEqualStrings("ty", bt.fields[1].name);
|
||||
try std.testing.expectEqual(@offsetOf(FieldZig, "ty"), bt.fields[1].offset);
|
||||
try std.testing.expectEqual(@as(usize, 4), bt.fields[1].size);
|
||||
|
||||
// Sanity: the concrete shape the design calls out — two u32s, 8 bytes.
|
||||
try std.testing.expectEqual(@as(usize, 8), bt.size);
|
||||
try std.testing.expectEqual(@as(usize, 0), bt.fields[0].offset);
|
||||
try std.testing.expectEqual(@as(usize, 4), bt.fields[1].offset);
|
||||
}
|
||||
|
||||
// Lock: a name NOT on the export list is unreachable — `findType` returns null
|
||||
// (the safety boundary; the welded-decl path falls through to a clean error,
|
||||
// never a silent default).
|
||||
test "compiler_lib: unexported name returns null" {
|
||||
try std.testing.expect(compiler_lib.findType("NotExported") == null);
|
||||
try std.testing.expect(compiler_lib.findType("") == null);
|
||||
}
|
||||
|
||||
// Lock: a faithful sx header for `Field` validates clean (the natural two-u32
|
||||
// layout matches the welded type).
|
||||
test "compiler_lib: validateStructLayout accepts a faithful Field header" {
|
||||
const bt = compiler_lib.findType("Field").?;
|
||||
const sx = [_]compiler_lib.SxField{
|
||||
.{ .name = "name", .size = 4 },
|
||||
.{ .name = "ty", .size = 4 },
|
||||
};
|
||||
try std.testing.expect(compiler_lib.validateStructLayout(bt, &sx, 8) == null);
|
||||
}
|
||||
|
||||
// Lock: every drift the assertion is meant to catch surfaces as the right
|
||||
// `LayoutMismatch` variant (field count / name / size / total), and the first
|
||||
// mismatch wins.
|
||||
test "compiler_lib: validateStructLayout flags each kind of drift" {
|
||||
const bt = compiler_lib.findType("Field").?;
|
||||
|
||||
// Wrong field count (one field instead of two).
|
||||
{
|
||||
const sx = [_]compiler_lib.SxField{.{ .name = "name", .size = 4 }};
|
||||
const m = compiler_lib.validateStructLayout(bt, &sx, 4).?;
|
||||
try std.testing.expect(m == .field_count);
|
||||
try std.testing.expectEqual(@as(usize, 2), m.field_count.expected);
|
||||
try std.testing.expectEqual(@as(usize, 1), m.field_count.got);
|
||||
}
|
||||
// Wrong field name (reorder / rename) at index 1.
|
||||
{
|
||||
const sx = [_]compiler_lib.SxField{
|
||||
.{ .name = "name", .size = 4 },
|
||||
.{ .name = "kind", .size = 4 },
|
||||
};
|
||||
const m = compiler_lib.validateStructLayout(bt, &sx, 8).?;
|
||||
try std.testing.expect(m == .field_name);
|
||||
try std.testing.expectEqual(@as(usize, 1), m.field_name.index);
|
||||
try std.testing.expectEqualStrings("ty", m.field_name.expected);
|
||||
try std.testing.expectEqualStrings("kind", m.field_name.got);
|
||||
}
|
||||
// Wrong field size (retype to an 8-byte field).
|
||||
{
|
||||
const sx = [_]compiler_lib.SxField{
|
||||
.{ .name = "name", .size = 4 },
|
||||
.{ .name = "ty", .size = 8 },
|
||||
};
|
||||
const m = compiler_lib.validateStructLayout(bt, &sx, 12).?;
|
||||
try std.testing.expect(m == .field_size);
|
||||
try std.testing.expectEqual(@as(usize, 1), m.field_size.index);
|
||||
try std.testing.expectEqual(@as(usize, 4), m.field_size.expected);
|
||||
try std.testing.expectEqual(@as(usize, 8), m.field_size.got);
|
||||
}
|
||||
// Right fields, wrong total (padding drift).
|
||||
{
|
||||
const sx = [_]compiler_lib.SxField{
|
||||
.{ .name = "name", .size = 4 },
|
||||
.{ .name = "ty", .size = 4 },
|
||||
};
|
||||
const m = compiler_lib.validateStructLayout(bt, &sx, 16).?;
|
||||
try std.testing.expect(m == .total_size);
|
||||
try std.testing.expectEqual(@as(usize, 8), m.total_size.expected);
|
||||
try std.testing.expectEqual(@as(usize, 16), m.total_size.got);
|
||||
}
|
||||
}
|
||||
|
||||
// Lock: `StructInfo` is reflected in MEMORY order — Zig reorders it from source
|
||||
// order (name, fields, is_protocol, nominal_id) to (fields@0, name@16,
|
||||
// nominal_id@20, is_protocol@24). The registry must present the fields in that
|
||||
// memory order, since an sx welded header must declare them so to be
|
||||
// byte-identical.
|
||||
test "compiler_lib: StructInfo is reflected in Zig memory order" {
|
||||
const StructInfoZig = types.TypeInfo.StructInfo;
|
||||
const bt = compiler_lib.findType("StructInfo").?;
|
||||
|
||||
try std.testing.expectEqual(@sizeOf(StructInfoZig), bt.size);
|
||||
try std.testing.expectEqual(@as(usize, 4), bt.fields.len);
|
||||
|
||||
// Memory order: fields, name, nominal_id, is_protocol.
|
||||
try std.testing.expectEqualStrings("fields", bt.fields[0].name);
|
||||
try std.testing.expectEqual(@offsetOf(StructInfoZig, "fields"), bt.fields[0].offset);
|
||||
try std.testing.expectEqualStrings("name", bt.fields[1].name);
|
||||
try std.testing.expectEqual(@offsetOf(StructInfoZig, "name"), bt.fields[1].offset);
|
||||
try std.testing.expectEqualStrings("nominal_id", bt.fields[2].name);
|
||||
try std.testing.expectEqual(@offsetOf(StructInfoZig, "nominal_id"), bt.fields[2].offset);
|
||||
try std.testing.expectEqualStrings("is_protocol", bt.fields[3].name);
|
||||
try std.testing.expectEqual(@offsetOf(StructInfoZig, "is_protocol"), bt.fields[3].offset);
|
||||
|
||||
// Offsets are strictly ascending (memory order).
|
||||
try std.testing.expect(bt.fields[0].offset < bt.fields[1].offset);
|
||||
try std.testing.expect(bt.fields[1].offset < bt.fields[2].offset);
|
||||
try std.testing.expect(bt.fields[2].offset < bt.fields[3].offset);
|
||||
}
|
||||
|
||||
// Lock: the welded-function export list resolves the round-trip readers and
|
||||
// rejects unexported names (the boundary the interp's dispatch consults).
|
||||
// Lock: the compiler-function export list resolves the round-trip readers and
|
||||
// rejects unexported names (the boundary `weldedCompilerFn` + the interp's
|
||||
// dispatch consult).
|
||||
test "compiler_lib: findFn resolves exported functions, rejects others" {
|
||||
try std.testing.expect(compiler_lib.findFn("intern") != null);
|
||||
try std.testing.expect(compiler_lib.findFn("text_of") != null);
|
||||
|
||||
Reference in New Issue
Block a user