// 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"; compiler :: #library "compiler"; Member :: struct { name: string; ty: Type; } StringId :: u32; TypeId :: u32; intern :: (s: string) -> StringId abi(.zig) extern compiler; find_type :: (name: StringId) -> TypeId abi(.zig) extern compiler; type_kind :: (t: TypeId) -> i64 abi(.zig) extern compiler; declare_type :: (name: string) -> Type abi(.zig) extern compiler; pointer_to :: (t: Type) -> Type abi(.zig) extern compiler; register_type :: (handle: Type, kind: i64, members: []Member) -> Type abi(.zig) extern 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; }