Lands the full VM/compiler-API arc on branch reify (701/0 both gates): - abi(.compiler) ABI replaces abi(.zig) extern compiler + the fake #library "compiler"; bodiless decl = compiler-API surface, bodied = user compiler-domain fn (lowered for VM eval, emit-skipped). - out is a plain sx fn (libc write) — the out builtin deleted; the VM handles it via host-FFI. trace_resolve + interp_print_frames ported. - 4B VM-native diagnostics: 1179/1180 render proper comptime type construction failed: under strict. - S5a: build_options/set_post_link_callback on abi(.compiler) with BuildConfig threaded into the VM (green intermediate). - 0522 fixed (describe(args: []Type)); regression 0638. Strict deletion-gate down to 4 compiler_call bails (1609/1614/1615/1616) + 1654 (legitimate unresolvable-symbol diagnostic).
88 lines
3.5 KiB
Plaintext
88 lines
3.5 KiB
Plaintext
// Comptime compiler API — the WRITE side: one kind-branching `register_type`
|
|
// minting an actual enum AND a graph of mutually-recursive types (Phase 3).
|
|
//
|
|
// `declare_type` / `pointer_to` / `register_type` are bound to the `compiler`
|
|
// library. They MINT into the type table, so they run at LOWERING time (lazily,
|
|
// on demand) — when a `-> Type` builder's result is first referenced — where the
|
|
// compiler still resolves references to the new types. (`#run` is too late: it
|
|
// runs at emit time, after the type table is frozen.) They take/return real
|
|
// `Type` values (like the metatype's declare/define), and `register_type`
|
|
// branches on the `kind` arg IN THE COMPILER — the codes match the read-side
|
|
// `type_kind`: 1 struct · 2 enum · 3 tagged_union · 4 tuple.
|
|
//
|
|
// Suit :: enum { hearts; spades; diamonds; } (actual, payloadless)
|
|
// GraphA :: enum { self_ref: *A; to_b: B; tag: u32; } (payloads → tagged_union)
|
|
// GraphB :: enum { back_a: *A; self_b: *B; num: u32; }
|
|
//
|
|
// Forward `declare_type` handles + `pointer_to` make the A<->B cycle expressible
|
|
// before either body is filled.
|
|
|
|
#import "modules/std.sx";
|
|
|
|
|
|
Member :: struct { name: string; ty: Type; }
|
|
|
|
StringId :: u32;
|
|
TypeId :: u32;
|
|
|
|
intern :: (s: string) -> StringId abi(.compiler);
|
|
find_type :: (name: StringId) -> TypeId abi(.compiler);
|
|
type_kind :: (t: TypeId) -> i64 abi(.compiler);
|
|
declare_type :: (name: string) -> Type abi(.compiler);
|
|
pointer_to :: (t: Type) -> Type abi(.compiler);
|
|
register_type :: (handle: Type, kind: i64, members: []Member) -> Type abi(.compiler);
|
|
|
|
KIND_ENUM :: 2; // an ACTUAL payloadless enum
|
|
KIND_TAGGED_UNION :: 3; // a payload-carrying enum
|
|
|
|
// An actual enum: variants are names, no payloads (ty = void).
|
|
make_suit :: () -> Type {
|
|
return register_type(declare_type("Suit"), KIND_ENUM, .[
|
|
Member.{ name = "hearts", ty = void },
|
|
Member.{ name = "spades", ty = void },
|
|
Member.{ name = "diamonds", ty = void },
|
|
]);
|
|
}
|
|
Suit :: make_suit();
|
|
|
|
// The mutually-recursive A <-> B graph (payload variants → tagged_union).
|
|
build_graph :: () -> Type {
|
|
hA := declare_type("GraphA");
|
|
hB := declare_type("GraphB");
|
|
register_type(hA, KIND_TAGGED_UNION, .[
|
|
Member.{ name = "self_ref", ty = pointer_to(hA) }, // *A — self-reference
|
|
Member.{ name = "to_b", ty = hB }, // B by value (forward)
|
|
Member.{ name = "tag", ty = u32 }, // a plain payload
|
|
]);
|
|
register_type(hB, KIND_TAGGED_UNION, .[
|
|
Member.{ name = "back_a", ty = pointer_to(hA) }, // *A — back-reference
|
|
Member.{ name = "self_b", ty = pointer_to(hB) }, // *B — self-reference
|
|
Member.{ name = "num", ty = u32 },
|
|
]);
|
|
return hA;
|
|
}
|
|
GraphA :: build_graph();
|
|
|
|
// Reflect the minted types (read side, at #run) to confirm their kinds.
|
|
suit_kind :: #run type_kind(find_type(intern("Suit"))); // 2 = actual enum
|
|
grapha_kind :: #run type_kind(find_type(intern("GraphA"))); // 3 = tagged_union
|
|
|
|
main :: () -> i32 {
|
|
// Suit is a real, usable enum.
|
|
s := Suit.spades;
|
|
if s == {
|
|
case .hearts: { print("hearts\n"); }
|
|
case .spades: { print("spades\n"); }
|
|
case .diamonds: { print("diamonds\n"); }
|
|
}
|
|
// GraphA is a real, usable tagged union.
|
|
a := GraphA.tag(7);
|
|
if a == {
|
|
case .tag: (n) { print("tag={}\n", n); }
|
|
case .self_ref: (p) { print("self_ref\n"); }
|
|
case .to_b: (b) { print("to_b\n"); }
|
|
}
|
|
print("Suit kind={}, GraphA kind={}\n", suit_kind, grapha_kind);
|
|
return 0;
|
|
}
|