#import "modules/std.sx";
#import "modules/math/math.sx";
#import "modules/compiler.sx";
#import "modules/test.sx";
pkg :: #import "modules/testpkg";

// ============================================================
// Comprehensive Smoke Test — exercises every spec feature
// ============================================================

// --- Top-level type declarations ---

Point :: struct { x, y: s32; }

Color :: enum { red; green; blue; }

Shape :: enum {
    circle: f32;
    rect: struct { w, h: f32; };
    none;
}

Overlay :: union {
    f: f32;
    i: s32;
}

Vec2 :: union {
    data: [2]f32;
    struct { x, y: f32; };
}

Defaults :: struct {
    a: s32;
    b: s32 = 99;
    c: s32 = ---;
}

OptNode :: struct {
    value: s32;
    next: ?s32;
}

OptInner :: struct { val: s32; }
OptOuter :: struct { inner: ?OptInner; }

MyFloat :: f64;

Perms :: enum flags { read; write; execute; }

Status :: enum u8 { ok; err; timeout; }

WindowFlags :: enum flags u32 { vsync :: 64; resizable :: 4; hidden :: 128; }

// --- Top-level functions ---

add :: (a: s32, b: s32) -> s32 { a + b; }
mul :: (a: s32, b: s32) -> s32 { a * b; }

identity :: (x: $T) -> T { x; }

pair_add :: (a: $T, b: $U) -> s64 {
    cast(s64) a + cast(s64) b;
}

typed_sum :: (..args: []s32) -> s32 {
    result := 0;
    for args: (it) { result = result + it; }
    result;
}

apply :: (f: (s32, s32) -> s32, x: s32, y: s32) -> s32 {
    f(x, y);
}

void_return :: () {
    return;
}

implicit_return :: (x: s32) -> s32 {
    x * 2;
}

early_return :: (x: s32) -> s32 {
    if x > 10 { return 99; }
    x;
}

vec3 :: (x: f32, y: f32, z: f32) -> Vector(3, f32) {
    .[x, y, z];
}

point_sum :: (p: Point) -> s32 { p.x + p.y; }

// #run compile-time constants
CT_VAL :: #run add(10, 15);
CT_MUL :: #run mul(6, 7);
CT_CHAIN :: #run add(CT_VAL, 5);

// #run compile-time optional tests
ct_opt_coalesce :: () -> s32 {
    x: ?s32 = 42;
    y: ?s32 = null;
    return (x ?? 0) + (y ?? 99);
}
ct_opt_unwrap :: () -> s32 {
    x: ?s32 = 77;
    return x!;
}
ct_opt_guard :: () -> s32 {
    x: ?s32 = 10;
    if x == null { return -1; }
    return x;
}
CT_OPT_COALESCE :: #run ct_opt_coalesce();
CT_OPT_UNWRAP :: #run ct_opt_unwrap();
CT_OPT_GUARD :: #run ct_opt_guard();

// #insert helpers
gen_code :: () -> string {
    return "print(\"insert-ok\\n\");";
}
gen_val :: () -> string {
    return "print(\"insert-gen: {}\\n\", 42);";
}

// --- Foreign function binding ---
libc :: #library "c";
c_abs :: (n: s32) -> s32 #foreign libc "abs";

// --- Protocol declarations (Phase 1: static dispatch only) ---

Counter :: protocol {
    inc :: ();
    get :: () -> s32;
}

Summable :: protocol {
    sum :: () -> s32;
}

SimpleCounter :: struct { val: s32; }

impl Counter for SimpleCounter {
    inc :: (self: *SimpleCounter) { self.val += 1; }
    get :: (self: *SimpleCounter) -> s32 { self.val; }
}

impl Summable for Point {
    sum :: (self: *Point) -> s32 { self.x + self.y; }
}

// Phase 2: #inline protocol for dynamic dispatch
Adder :: protocol #inline {
    add :: (n: s32);
    value :: () -> s32;
}

Accumulator :: struct {
    total: s32;
}

impl Adder for Accumulator {
    add :: (self: *Accumulator, n: s32) { self.total += n; }
    value :: (self: *Accumulator) -> s32 { self.total; }
}

Doubler :: struct { val: s32; }

impl Adder for Doubler {
    add :: (self: *Doubler, n: s32) { self.val = self.val + n + n; }
    value :: (self: *Doubler) -> s32 { self.val; }
}

// Phase 4: default methods
Repeater :: protocol {
    say :: (msg: string);
    say_twice :: (msg: string) {
        self.say(msg);
        self.say(msg);
    }
}

Printer :: struct { count: s32; }

impl Repeater for Printer {
    say :: (self: *Printer, msg: string) {
        self.count += 1;
        out(msg);
    }
}

// P4 edge: Chained default→default calls
Chained :: protocol {
    base :: (msg: string) -> s32;
    wrap :: (msg: string) -> s32 {
        self.base(msg) + 1;
    }
    double_wrap :: (msg: string) -> s32 {
        self.wrap(msg) + self.wrap(msg);
    }
}

ChainImpl :: struct { val: s32; }
impl Chained for ChainImpl {
    base :: (self: *ChainImpl, msg: string) -> s32 {
        self.val += 1;
        msg.len;
    }
}

// Phase 5: Self type
Eq :: protocol {
    eq :: (other: Self) -> bool;
}

impl Eq for Point {
    eq :: (self: *Point, other: Point) -> bool {
        self.x == other.x and self.y == other.y;
    }
}

Cloneable :: protocol {
    clone :: () -> Self;
}

impl Cloneable for Point {
    clone :: (self: *Point) -> Point {
        Point.{ x = self.x, y = self.y };
    }
}

impl Eq for s64 {
    eq :: (self: *s64, other: s64) -> bool {
        self.* == other;
    }
}

// Phase 6: Generic constraints
are_equal :: ($T: Type/Eq, a: T, b: T) -> bool {
    a.eq(b);
}

Hashable :: protocol {
    hash :: () -> s64;
}

impl Hashable for Point {
    hash :: (self: *Point) -> s64 {
        xx self.x * 31 + xx self.y;
    }
}

eq_and_hash :: ($T: Type/Eq/Hashable, a: T, b: T) -> bool {
    if a.hash() != b.hash() { return false; }
    a.eq(b);
}

// P6.4: inline constraint syntax ($T/Protocol)
sum_of_inline :: (a: $T/Summable, b: T) -> s32 {
    a.sum() + b.sum();
}

// Phase 7: Generic struct impls
Pair :: struct ($T: Type) {
    a: T;
    b: T;
}

impl Summable for Pair($T) {
    sum :: (self: *Pair(T)) -> s32 {
        xx self.a + xx self.b;
    }
}

// P6.5: Struct type param constraints
SumBox :: struct ($T: Type/Summable) {
    val: T;
}

// ============================================================
// Struct constants test
Phys :: struct {
    x, y: f32;
    GRAVITY :f32: 9.81;
    MAX_SPEED :: 100;
}

// Init block test struct
Builder :: struct {
    total: s32;
    count: s32;

    add :: (self: *Builder, val: s32) {
        self.total += val;
        self.count += 1;
    }
}

// Global variable for address-of test
g_smoke_val : s32 = 42;

write_to_ptr :: (p: *s32) {
    p.* = 99;
}

main :: () {

    // ========================================================
    // 1. LITERALS
    // ========================================================
    print("=== 1. Literals ===\n");

    // Integer literals
    print("decimal: {}\n", 42);
    print("hex: {}\n", 0xFF);
    print("binary: {}\n", 0b1010);

    // Float literal
    pi := 3.14;
    print("float: {}\n", pi);

    // Explicit f64
    big : f64 = 2.718281828;
    print("f64: {}\n", big);

    // Boolean literals
    print("true: {}\n", true);
    print("false: {}\n", false);

    // String with escapes
    print("escapes: hello\tworld\n");

    // Multi-line string
    ml := "line1
line2";
    print("multiline: {}\n", ml);

    // Heredoc string
    hd := #string END
raw heredoc
END;
    print("heredoc: {}\n", hd);

    // Undefined with type
    undef_val : s32 = ---;
    undef_val = 77;
    print("undef-then-set: {}\n", undef_val);

    // Enum literal (context-inferred)
    c : Color = .green;
    print("enum-lit: {}\n", c);

    // Null pointer
    np : *s32 = null;
    print("null-ptr: {}\n", np);

    // String .len
    slen := "hello";
    print("string-len: {}\n", slen.len);

    // Empty string .len
    es := "";
    print("empty-string: {}\n", es.len);

    // ========================================================
    // 2. OPERATORS & PRECEDENCE
    // ========================================================
    print("=== 2. Operators ===\n");

    // Arithmetic
    print("add: {}\n", 3 + 4);
    print("sub: {}\n", 10 - 3);
    print("mul: {}\n", 6 * 7);
    print("div: {}\n", 20 / 4);
    print("mod: {}\n", 17 % 5);
    print("neg: {}\n", -(5));

    // Comparisons
    print("eq: {}\n", 5 == 5);
    print("neq: {}\n", 5 != 3);
    print("lt: {}\n", 3 < 5);
    print("gt: {}\n", 5 > 3);
    print("le: {}\n", 5 <= 5);
    print("ge: {}\n", 5 >= 3);

    // Chained comparisons
    v := 50;
    print("chain: {}\n", 0 <= v <= 100);
    print("chain-gt: {}\n", 100 > v > 0);
    print("chain-mixed: {}\n", 100 > v >= 0);

    // Equality chains
    print("eq-chain: {}\n", 5 == 5 == 5);
    print("eq-chain-f: {}\n", 5 == 5 == 6);

    // Bitwise
    print("band: {}\n", 0xFF & 0x0F);
    print("bor: {}\n", 1 | 2 | 4);

    // Bitwise XOR
    print("bxor: {}\n", 0xFF ^ 0x0F);
    print("bxor2: {}\n", 6 ^ 3);

    // Bitwise NOT
    print("bnot: {}\n", ~0);
    print("bnot2: {}\n", ~1);

    // Shifts
    print("shl: {}\n", 1 << 4);
    print("shr: {}\n", 256 >> 4);
    print("shl2: {}\n", 3 << 3);
    print("shr2: {}\n", 255 >> 1);

    // Bitwise on variables
    bv1 := 0xFF;
    bv2 := 0x0F;
    print("band-var: {}\n", bv1 & bv2);
    bv3 := 1;
    bv4 := 6;
    print("bor-var: {}\n", bv3 | bv4);
    print("bxor-var: {}\n", bv1 ^ bv2);
    print("shl-var: {}\n", bv3 << 4);
    print("shr-var: {}\n", bv1 >> 4);
    print("bnot-var: {}\n", ~bv2);

    // Bitwise compound assignment
    bca := 0xFF;
    bca &= 0x0F;
    print("and-assign: {}\n", bca);
    bco := 0x0F;
    bco |= 0xF0;
    print("or-assign: {}\n", bco);
    bcx := 0xFF;
    bcx ^= 0x0F;
    print("xor-assign: {}\n", bcx);
    bcs := 1;
    bcs <<= 8;
    print("shl-assign: {}\n", bcs);
    bcr := 256;
    bcr >>= 4;
    print("shr-assign: {}\n", bcr);

    // Modulo on variables
    mv1 := 17;
    mv2 := 5;
    print("mod-var: {}\n", mv1 % mv2);

    // Logical (short-circuit)
    print("and: {}\n", true and true);
    print("and-false: {}\n", true and false);
    print("or: {}\n", false or true);
    print("or-false: {}\n", false or false);

    // Short-circuit verification
    print("short-and: {}\n", false and true);
    print("short-or: {}\n", true or false);

    // Compound assignment
    ca := 10;
    ca += 5;
    print("ca+=: {}\n", ca);
    ca -= 3;
    print("ca-=: {}\n", ca);
    ca *= 2;
    print("ca*=: {}\n", ca);
    ca /= 6;
    print("ca/=: {}\n", ca);

    // Precedence
    print("prec1: {}\n", 2 + 3 * 4);
    print("prec2: {}\n", (2 + 3) * 4);

    // xx explicit cast
    big2 : f64 = 200.7;
    small : u8 = xx big2;
    print("xx-cast: {}\n", small);

    // Implicit widening conversions
    wu : u8 = 200;
    ws : s64 = wu;
    print("widen-u8-s64: {}\n", ws);

    wi3 : s32 = 42;
    wf : f64 = wi3;
    print("widen-s32-f64: {}\n", wf);

    wf32 : f32 = 1.5;
    wf64 : f64 = wf32;
    print("widen-f32-f64: {}\n", wf64);

    wu2 : u8 = 100;
    ws2 : s16 = wu2;
    print("widen-u8-s16: {}\n", ws2);

    // More xx narrowing
    xl : s64 = 12345;
    xs : s32 = xx xl;
    print("xx-s64-s32: {}\n", xs);

    xd : f64 = 1.5;
    xf : f32 = xx xd;
    print("xx-f64-f32: {}\n", xf);

    xdf : f64 = 7.9;
    xdi : s32 = xx xdf;
    print("xx-f64-s32: {}\n", xdi);

    // ========================================================
    // 3. TYPE SYSTEM
    // ========================================================
    print("=== 3. Types ===\n");

    // Primitive types
    v_s8 : s8 = 127;
    v_s16 : s16 = 32000;
    v_s32 : s32 = 100000;
    v_u8 : u8 = 255;
    v_u16 : u16 = 65000;
    v_u32 : u32 = 4000000;
    print("s8: {}\n", v_s8);
    print("s16: {}\n", v_s16);
    print("s32: {}\n", v_s32);
    print("u8: {}\n", v_u8);
    print("u16: {}\n", v_u16);
    print("u32: {}\n", v_u32);

    // Type alias
    mf : MyFloat = 1.5;
    print("alias: {}\n", mf);

    // --- Structs ---
    // Positional literal
    p1 : Point = .{ 1, 2 };
    print("struct-pos: {}\n", p1);

    // Type-prefix literal
    p2 := Point.{ 3, 4 };
    print("struct-prefix: {}\n", p2);

    // Named fields
    p3 := Point.{ y=10, x=20 };
    print("struct-named: {}\n", p3);

    // Shorthand (variable name = field name)
    x : s32 = 5;
    y : s32 = 6;
    p4 := Point.{ x, y };
    print("struct-shorthand: {}\n", p4);

    // Field defaults
    d1 : Defaults;
    print("defaults: a={} b={}\n", d1.a, d1.b);

    // Field access and assignment
    p5 := Point.{ 0, 0 };
    p5.x = 42;
    p5.y = 99;
    print("field-assign: {}\n", p5);

    // --- Enum (payload-less) ---
    ec : Color = .red;
    print("enum: {}\n", ec);

    // Enum comparison
    ce1 : Color = .red;
    ce2 : Color = .red;
    ce3 : Color = .blue;
    print("enum-eq: {}\n", ce1 == ce2);
    print("enum-neq: {}\n", ce1 != ce3);

    // Backing type
    st : Status = .err;
    print("backing: {}\n", st);

    // --- Enum (tagged union) ---
    sh : Shape = .circle(3.14);
    print("tagged: {}\n", sh);

    // Payload access
    radius := sh.circle;
    print("payload: {}\n", radius);

    // Void variant
    sh = .none;
    print("void-variant: {}\n", sh);

    // Variant reassignment
    sh = .circle(1.0);
    print("reassign: {}\n", sh);
    sh = .rect(.{ 5, 3 });
    print("reassign2: {}\n", sh);

    // Type-prefix construction
    tp := Shape.circle(2.5);
    print("enum-prefix: {}\n", tp);

    // Pattern matching
    sh2 : Shape = .rect(.{ 5, 3 });
    if sh2 == {
        case .circle: print("match: circle\n");
        case .rect: print("match: rect\n");
        case .none: print("match: none\n");
    }

    // Match as expression
    sh3 : Shape = .circle(1.0);
    ms := if sh3 == {
        case .circle: 10;
        case .rect: 20;
        case .none: 30;
    }
    print("match-expr: {}\n", ms);

    // Match expression with else
    me_val := 42;
    me_res := if me_val == {
        case 1: 10;
        case 2: 20;
        else: 99;
    }
    print("match-expr-else: {}\n", me_res);

    // Payload capture (block form)
    sh4 : Shape = .circle(9.5);
    if sh4 == {
        case .circle: (r) { print("capture: {}\n", r); }
        case .rect: (sz) { print("capture: {}\n", sz); }
        case .none: print("capture: none\n");
    }

    // Payload capture (arrow form)
    sh_ca : Shape = .circle(7.5);
    if sh_ca == {
        case .circle: (r) => print("capture-arrow: {}\n", r);
        case .rect: (sz) => print("capture-arrow: rect\n");
        case .none: print("capture-arrow: none\n");
    }

    // else arm in match
    num := 42;
    if num == {
        case 1: print("else-match: one\n");
        case 2: print("else-match: two\n");
        else: print("else-match: other\n");
    }

    // Integer pattern matching
    code := 2;
    if code == {
        case 1: print("int-match: one\n");
        case 2: print("int-match: two\n");
        case 3: print("int-match: three\n");
    }

    // Integer match with else
    im_code := 99;
    if im_code == {
        case 1: print("int-match-else: one\n");
        case 2: print("int-match-else: two\n");
        else: print("int-match-else: unknown\n");
    }

    // Bool pattern matching
    bm := true;
    if bm == {
        case true: print("bool-match-t: yes\n");
        case false: print("bool-match-t: no\n");
    }
    bm2 := false;
    if bm2 == {
        case true: print("bool-match-f: yes\n");
        case false: print("bool-match-f: no\n");
    }

    // Bool conditional
    flag := true;
    if flag { print("bool: true\n"); }

    // --- Union (untagged) ---
    o : Overlay = ---;
    o.f = 3.14;
    print("union-f: {}\n", o.f);
    // Type punning — read same bits as s32
    print("union-i: {}\n", o.i);

    // Union member promotion
    uv : Vec2 = ---;
    uv.x = 1.0;
    uv.y = 2.0;
    print("promoted-x: {}\n", uv.x);
    print("promoted-data0: {}\n", uv.data[0]);

    // --- Arrays ---
    arr : [5]s32 = .[10, 20, 30, 40, 50];
    print("arr[2]: {}\n", arr[2]);
    print("arr.len: {}\n", arr.len);

    // Array element assignment
    aa : [3]s32 = .[1, 2, 3];
    aa[1] = 99;
    print("arr-assign: {}\n", aa);

    // --- Slices ---
    sl : []s32 = .[1, 2, 3, 4, 5];
    print("sl[0]: {}\n", sl[0]);
    print("sl.len: {}\n", sl.len);

    // Slice element write
    sla : []s32 = .[10, 20, 30];
    sla[1] = 55;
    print("sl-assign: {}\n", sla);

    // Subslicing
    sub := arr[1..4];
    print("sub: {}\n", sub);
    head := arr[..3];
    print("head: {}\n", head);
    tail := arr[2..];
    print("tail: {}\n", tail);

    // Slice of slice
    sos : []s32 = .[10, 20, 30, 40, 50];
    mid := sos[1..4];
    inner := mid[0..2];
    print("slice-of-slice: {}\n", inner);

    // String subslicing
    msg := "hello world";
    print("strsub: {}\n", msg[6..11]);
    print("str-prefix: {}\n", msg[..5]);
    print("str-suffix: {}\n", msg[6..]);

    // --- Pointers ---
    // Address-of global variable
    write_to_ptr(@g_smoke_val);
    print("global-addr-of: {}\n", g_smoke_val);

    pv := Point.{ 10, 20 };
    ptr := @pv;
    print("deref: {}\n", ptr.*);

    // Auto-deref
    print("auto-deref: {}\n", ptr.x);

    // Many-pointer
    mp : [*]s32 = @arr[0];
    print("mp[0]: {}\n", mp[0]);
    print("mp[3]: {}\n", mp[3]);

    // Many-pointer write
    mpw : [5]s32 = .[10, 20, 30, 40, 50];
    mpw_ptr : [*]s32 = @mpw[0];
    mpw_ptr[2] = 99;
    print("mp-write: {}\n", mpw[2]);

    // Pointer-null comparison
    np : *s32 = null;
    print("ptr==null: {}\n", np == null);
    print("ptr!=null: {}\n", np != null);
    np2 := @pv.x;
    print("ptr2==null: {}\n", np2 == null);
    print("ptr2!=null: {}\n", np2 != null);

    // Pointer to nested struct field
    Inner3 :: struct { a: f32; b: f32; c: f32; }
    Outer3 :: struct { key: s32; inner: Inner3; }
    out3 := Outer3.{ key = 42, inner = Inner3.{ a = 1.0, b = 2.0, c = 3.0 } };
    ip3 := @out3.inner;
    print("ptr-nested-field: {} {} {}\n", ip3.a, ip3.b, ip3.c);

    // Store to many-pointer field must not corrupt adjacent memory
    MpHolder :: struct { items: [*]s64; sentinel: s64; }
    mph := MpHolder.{ items = xx 0, sentinel = 42 };
    mph.items = xx 0;
    print("mp-store-sentinel: {}\n", mph.sentinel);

    // --- Vectors ---
    vc := vec3(1, 3, 2);
    print("vec-construct: {}\n", vc);

    va := vec3(1, 2, 3);
    vb := vec3(4, 5, 6);
    print("vec-add: {}\n", va + vb);
    print("vec-sub: {}\n", vec3(5, 5, 5) - vec3(1, 2, 3));
    print("vec-mul: {}\n", vec3(2, 3, 4) * vec3(1, 2, 3));
    print("vec-div: {}\n", vec3(10, 9, 8) / vec3(2, 3, 4));

    print("vec-scalar: {}\n", vec3(1, 3, 2) * 2.0);
    print("vec-neg: {}\n", -vec3(1, 3, 2));

    ve := vec3(10, 20, 30);
    print("vec-x: {}\n", ve.x);
    print("vec-y: {}\n", ve.y);
    print("vec-z: {}\n", ve.z);
    print("vec-idx: {}\n", ve[1]);

    // ========================================================
    // 4. CONTROL FLOW
    // ========================================================
    print("=== 4. Control Flow ===\n");

    // If-then-else (inline, as expression)
    ite := if true then 1 else 2;
    print("ite: {}\n", ite);

    // If-then-else both branches
    ie_a := if true then 10 else 20;
    ie_b := if false then 10 else 20;
    print("ite-both: {} {}\n", ie_a, ie_b);

    // If block
    if 1 < 2 {
        print("if-block: yes\n");
    }

    // If without else (statement)
    if false { print("should-not-print\n"); }
    print("if-no-else: after\n");

    // Nested if
    nx := 10;
    if nx > 5 {
        if nx > 8 {
            print("nested-if: deep\n");
        }
    }

    // If-else-if chain
    eiv := 2;
    if eiv == 1 {
        print("if-else-if: first\n");
    } else if eiv == 2 {
        print("if-else-if: second\n");
    } else {
        print("if-else-if: other\n");
    }

    // If block as expression
    ibe := 10 + if true { 5; } else { 0; };
    print("if-block-expr: {}\n", ibe);

    // While basic
    wi := 0;
    while wi < 5 { wi += 1; }
    print("while: {}\n", wi);

    // While with false condition (never executes)
    while false { print("should-not-print\n"); }
    print("while-false: skipped\n");

    // While with break
    wb := 0;
    while wb < 100 {
        if wb == 7 { break; }
        wb += 1;
    }
    print("while-break: {}\n", wb);

    // While with continue
    wsum := 0;
    wc := 0;
    while wc < 10 {
        wc += 1;
        if wc % 2 == 0 { continue; }
        wsum += wc;
    }
    print("while-continue: {}\n", wsum);

    // While sum 1..10
    wsum2 := 0;
    wi2 := 1;
    while wi2 <= 10 {
        wsum2 += wi2;
        wi2 += 1;
    }
    print("while-sum: {}\n", wsum2);

    // Nested while
    nw_outer := 0;
    nw_count := 0;
    while nw_outer < 3 {
        nw_inner := 0;
        while nw_inner < 3 {
            nw_count += 1;
            nw_inner += 1;
        }
        nw_outer += 1;
    }
    print("nested-while: {}\n", nw_count);

    // Nested while with break in inner
    nb_outer := 0;
    nb_icount := 0;
    while nb_outer < 5 {
        nb_i := 0;
        while nb_i < 5 {
            if nb_i == 1 { break; }
            nb_i += 1;
        }
        nb_icount += nb_i;
        nb_outer += 1;
        if nb_outer == 2 { break; }
    }
    print("nested-break: {} {}\n", nb_outer, nb_icount);

    // For loop basic
    farr : [4]s32 = .[10, 20, 30, 40];
    out("for:");
    for farr: (it) {
        out(" ");
        out(int_to_string(it));
    }
    out("\n");

    // For with print
    out("for-print:");
    for farr: (it) {
        print(" {}", it);
    }
    out("\n");

    // For with index
    out("for-idx:");
    for farr: (_, ix) {
        out(" ");
        out(int_to_string(ix));
    }
    out("\n");

    // For with print two args
    out("for-2arg:");
    for farr: (it, ix) {
        print(" {}@{}", it, ix);
    }
    out("\n");

    // For with break
    out("for-break:");
    for farr: (it) {
        if it == 30 { break; }
        print(" {}", it);
    }
    out("\n");

    // For with continue
    out("for-continue:");
    for farr: (it) {
        if it == 20 { continue; }
        print(" {}", it);
    }
    out("\n");

    // For on slice
    fsl : []s32 = .[10, 20, 30];
    out("for-slice:");
    for fsl: (it) {
        print(" {}", it);
    }
    out("\n");

    // For on slice with index
    out("for-slice-idx:");
    for fsl: (it, ix) {
        print(" {}:{}", ix, it);
    }
    out("\n");

    // Nested for
    nf_a : [2]s32 = .[0, 1];
    nf_b : [2]s32 = .[0, 1];
    out("for-nested:");
    for nf_a: (oa) {
        for nf_b: (ob) {
            print(" ({},{})", oa, ob);
        }
    }
    out("\n");

    // For with break preserving index
    fbi : [5]s32 = .[10, 20, 30, 40, 50];
    fbi_idx := 0;
    for fbi: (it, ix) {
        if it == 30 { fbi_idx = ix; break; }
    }
    print("for-break-idx: {}\n", fbi_idx);

    // Multiple print placeholders
    print("multi: {} {} {}\n", 1, 2, 3);

    // ========================================================
    // 5. FUNCTIONS & DECLARATIONS
    // ========================================================
    print("=== 5. Functions ===\n");

    // Constant binding
    FORTY_TWO :: 42;
    print("const: {}\n", FORTY_TWO);

    // Typed constant
    TYPED_PI : f64 : 3.14;
    print("typed-const: {}\n", TYPED_PI);

    // Variable with default init
    di : s32;
    print("default-init: {}\n", di);

    // Implicit return
    print("implicit-ret: {}\n", implicit_return(21));

    // Explicit return
    print("early-ret: {}\n", early_return(5));
    print("early-ret2: {}\n", early_return(20));

    // Void return
    void_return();
    print("void-return: ok\n");

    // Generic — single param
    print("generic-s32: {}\n", identity(42));
    print("generic-f32: {}\n", identity(1.5));
    print("generic-bool: {}\n", identity(true));

    // Generic — multiple params
    print("generic-multi: {}\n", pair_add(10, 20));

    // Lambda
    double :: (x: s32) => x * 2;
    print("lambda: {}\n", double(7));

    // Lambda with return type
    halve :: (x: f32) -> f32 => x / 2.0;
    print("lambda-ret: {}\n", halve(10.0));

    // Local function (non-lambda)
    local_add :: (a: s32, b: s32) -> s32 { a + b; }
    print("local-fn: {}\n", local_add(3, 4));

    // Nested function calls
    print("fn-nested: {}\n", add(mul(2, 3), mul(4, 5)));

    // Variadic (typed)
    print("varargs: {}\n", typed_sum(1, 2, 3, 4, 5));

    // Spread
    spread_arr : [3]s32 = .[10, 20, 30];
    print("spread: {}\n", typed_sum(..spread_arr));

    // Function pointers
    fp : (s32, s32) -> s32 = add;
    print("fp: {}\n", fp(3, 4));
    fp = mul;
    print("fp-reassign: {}\n", fp(3, 4));
    print("fp-apply: {}\n", apply(add, 10, 20));

    // ========================================================
    // 6. SCOPING & DEFER
    // ========================================================
    print("=== 6. Scoping ===\n");

    // Scope block with shadowing
    sv := 100;
    {
        sv := 200;
        print("inner: {}\n", sv);
    }
    print("outer: {}\n", sv);

    // Shadow with different type
    st_v := 42;
    print("shadow-type: {}\n", st_v);
    {
        st_v := 3.14;
        print("shadow-type: {}\n", st_v);
    }

    // Nested scopes (3 levels)
    nv := 1;
    {
        nv := 2;
        {
            nv := 3;
            print("nest3: {}\n", nv);
        }
        print("nest2: {}\n", nv);
    }
    print("nest1: {}\n", nv);

    // Scope isolation
    { iso := 100; print("scope-isolate: {}\n", iso); }

    // Reuse name after scope exit
    sr := 1;
    print("scope-reuse: {}\n", sr);
    { sr := 2; print("scope-reuse: {}\n", sr); }
    print("scope-reuse: {}\n", sr);

    // Multiple defers (LIFO order)
    {
        defer print("defer-c\n");
        defer print("defer-b\n");
        defer print("defer-a\n");
    }

    // Four defers
    {
        defer print("d1\n");
        defer print("d2\n");
        defer print("d3\n");
        defer print("d4\n");
    }

    // Defer in nested scopes
    {
        defer print("outer-defer\n");
        {
            defer print("inner-defer\n");
        }
    }

    // Defer in if block
    if true {
        defer print("defer-in-if: deferred\n");
        print("defer-in-if: body\n");
    }

    // ========================================================
    // 7. BUILT-IN FUNCTIONS
    // ========================================================
    print("=== 7. Builtins ===\n");

    // out
    out("out-ok\n");

    // sqrt
    print("sqrt: {}\n", sqrt(9.0));
    print("sqrt-f64: {}\n", sqrt(16.0));

    // size_of
    print("sizeof-s32: {}\n", size_of(s32));
    print("sizeof-f64: {}\n", size_of(f64));
    print("sizeof-struct: {}\n", size_of(Point));

    // align_of
    print("alignof-u8: {}\n", align_of(u8));
    print("alignof-s32: {}\n", align_of(s32));
    print("alignof-s64: {}\n", align_of(s64));
    print("alignof-struct: {}\n", align_of(Point));

    // type_of + category matching
    tv := 42;
    ttype := type_of(tv);
    if ttype == {
        case int: print("typeof: int\n");
        case float: print("typeof: float\n");
        else: print("typeof: other\n");
    }

    // type_of — float
    tf := 3.14;
    if type_of(tf) == {
        case float: print("typeof-float: float\n");
        else: print("typeof-float: other\n");
    }

    // type_of — string
    ts := "hello";
    if type_of(ts) == {
        case string: print("typeof-string: string\n");
        else: print("typeof-string: other\n");
    }

    // type_of — bool
    tb := true;
    if type_of(tb) == {
        case bool: print("typeof-bool: bool\n");
        else: print("typeof-bool: other\n");
    }

    // type_of — struct
    tst := Point.{ 1, 2 };
    if type_of(tst) == {
        case struct: print("typeof-struct: struct\n");
        else: print("typeof-struct: other\n");
    }

    // type_of — enum
    ten : Color = .red;
    if type_of(ten) == {
        case enum: print("typeof-enum: enum\n");
        else: print("typeof-enum: other\n");
    }

    // type_name
    print("typename: {}\n", type_name(Point));

    // field_count on struct
    print("fieldcount: {}\n", field_count(Point));

    // field_count on enum
    print("fieldcount-enum: {}\n", field_count(Color));

    // field_name on struct
    print("fieldname0: {}\n", field_name(Point, 0));
    print("fieldname1: {}\n", field_name(Point, 1));

    // field_name on enum
    print("fieldname-enum0: {}\n", field_name(Color, 0));
    print("fieldname-enum2: {}\n", field_name(Color, 2));

    // field_value (use any_to_string to avoid sext-on-Any bug)
    fv_pt := Point.{ 11, 22 };
    out("fieldval0: ");
    out(any_to_string(field_value(fv_pt, 0)));
    out("\n");
    out("fieldval1: ");
    out(any_to_string(field_value(fv_pt, 1)));
    out("\n");

    // field_index on plain enum
    fi_c : Color = .green;
    print("fieldidx: {}\n", field_index(Color, fi_c));

    // field_index on tagged enum
    fi_sh : Shape = .circle(1.0);
    print("fieldidx-tagged: {}\n", field_index(Shape, fi_sh));
    fi_sh2 : Shape = .none;
    print("fieldidx-tagged2: {}\n", field_index(Shape, fi_sh2));

    // cast
    cval : f64 = 3.7;
    print("cast: {}\n", cast(s32) cval);
    cv2 : s32 = 42;
    print("cast-int-f64: {}\n", cast(f64) cv2);

    // ========================================================
    // 8. COMPILE-TIME
    // ========================================================
    print("=== 8. Comptime ===\n");

    // #run constant
    print("run-const: {}\n", CT_VAL);

    // #run with expression
    print("run-expr: {}\n", CT_MUL);

    // #run chained dependency
    print("run-chain: {}\n", CT_CHAIN);

    // #run comptime optionals
    print("ct-opt-coalesce: {}\n", CT_OPT_COALESCE);           // ct-opt-coalesce: 141
    print("ct-opt-unwrap: {}\n", CT_OPT_UNWRAP);               // ct-opt-unwrap: 77
    print("ct-opt-guard: {}\n", CT_OPT_GUARD);                 // ct-opt-guard: 10

    // #insert with function
    #insert gen_code();

    // #insert additional
    #insert gen_val();

    // ========================================================
    // 9. FLAGS
    // ========================================================
    print("=== 9. Flags ===\n");

    // Combine flags
    perm : Perms = .read | .write;
    print("flags: {}\n", perm);

    // Test flag
    if perm & .read { print("has-read: yes\n"); }
    if perm & .execute { print("has-exec: yes\n"); }

    // Test flag negative
    pt : Perms = .write;
    if pt & .read {
        print("flags-neg: has-read\n");
    } else {
        print("flags-neg: no-read\n");
    }

    // Single flag
    ps : Perms = .execute;
    print("flags-single: {}\n", ps);

    // All flags
    pall : Perms = .read | .write | .execute;
    print("flags-all: {}\n", pall);

    // Cast to int
    print("flags-raw: {}\n", cast(s64) perm);

    // Flags with explicit values
    wf : WindowFlags = .vsync | .resizable;
    print("flags-explicit: {}\n", wf);
    print("flags-explicit-raw: {}\n", cast(s64) wf);

    // --- Multi-target assignment (swap) ---
    print("--- swap ---\n");

    // Variable swap
    {
        sa := 10;
        sb := 20;
        sa, sb = sb, sa;
        print("var swap: {} {}\n", sa, sb);
    }

    // Array element swap
    {
        sarr : [3]s64 = .[1, 2, 3];
        sarr[0], sarr[2] = sarr[2], sarr[0];
        print("arr swap: {} {}\n", sarr[0], sarr[2]);
    }

    // 3-way rotation
    {
        ra := 1;
        rb := 2;
        rc := 3;
        ra, rb, rc = rc, ra, rb;
        print("3-way: {} {} {}\n", ra, rb, rc);
    }

    // --- Tuple destructuring ---
    print("--- destructure ---\n");

    // Basic tuple destructuring
    {
        da, db := (10, 20);
        print("basic: {} {}\n", da, db);
    }

    // Destructure from function return
    {
        dswap :: (a: s64, b: s64) -> (s64, s64) { (b, a); }
        dx, dy := dswap(1, 2);
        print("fn: {} {}\n", dx, dy);
    }

    // Discard with _
    {
        _, dsecond := (100, 200);
        print("discard: {}\n", dsecond);
    }

    // Three elements
    {
        da3, db3, dc3 := (1, 2, 3);
        print("triple: {} {} {}\n", da3, db3, dc3);
    }

    // ========================================================
    // 15. FOREIGN FUNCTION BINDING
    // ========================================================
    print("=== 15. Foreign ===\n");

    // Symbol rename: c_abs maps to C's abs()
    print("foreign-rename: {}\n", c_abs(xx -42));

    // ========================================================
    // 16. COMPOUND ASSIGNMENT TYPE CONVERSION
    // ========================================================
    print("=== 16. Compound Assign ===\n");
    {
        ca_a : f64 = 10.0;
        ca_b : f32 = 3.0;
        ca_a += ca_b;
        print("f64+=f32: {}\n", ca_a);

        ca_c : s64 = 100;
        ca_d : s32 = 7;
        ca_c -= ca_d;
        print("s64-=s32: {}\n", ca_c);
    }

    // ========================================================
    // 17. SLICE/ARRAY .ptr ACCESS
    // ========================================================
    print("=== 17. Slice Ptr ===\n");
    {
        sarr : [5]s32 = .[10, 20, 30, 40, 50];
        ssl := sarr[1..4];
        sp := ssl.ptr;
        print("sl-ptr[0]: {}\n", sp[0]);
        print("sl-ptr[1]: {}\n", sp[1]);
    }

    // ========================================================
    // 18. ARRAYS OF USER-DEFINED TYPES
    // ========================================================
    print("=== 18. Array of Structs ===\n");
    {
        spts : [2]Point = .[Point.{1, 2}, Point.{3, 4}];
        spt2 := spts[1];
        print("arr-struct-x: {}\n", spt2.x);
        for spts: (it) {
            print("for-struct: {}\n", it);
        }
    }

    // ========================================================
    // 19. LOCAL FUNCTION RETURNING STRUCT/ENUM
    // ========================================================
    print("=== 19. Local Fn Return ===\n");
    {
        local_pt :: () -> Point { Point.{42, 99}; }
        lp := local_pt();
        print("local-struct: {} {}\n", lp.x, lp.y);

        local_sh :: () -> Shape { .circle(2.5); }
        ls := local_sh();
        print("local-enum: {}\n", ls);
    }

    // ========================================================
    // 20. PIPE UFCS RETURN TYPE INFERENCE
    // ========================================================
    print("=== 20. UFCS Return Type ===\n");
    {
        p := Point.{3, 4};
        print("direct: {}\n", point_sum(p));
        print("ufcs: {}\n", p |> point_sum());
    }

    // ========================================================
    // 21. TYPE-NAMED VARIABLES (s2, u8, etc.)
    // ========================================================
    print("=== 21. Type-Named Vars ===\n");
    {
        s2 := 42;
        print("s2: {}\n", s2);
        s2 = s2 + 1;
        print("s2+1: {}\n", s2);
    }

    // ========================================================
    // 22. IF-EXPRESSION RETURNING STRUCT
    // ========================================================
    print("=== 22. If-Struct ===\n");
    {
        flag := true;
        p := if flag { Point.{10, 20}; } else { Point.{30, 40}; };
        print("if-struct: {} {}\n", p.x, p.y);
        q := if !flag { Point.{10, 20}; } else { Point.{30, 40}; };
        print("else-struct: {} {}\n", q.x, q.y);
    }

    // ========================================================
    // 23. NESTED ARRAYS (2D)
    // ========================================================
    print("=== 23. Nested Arrays ===\n");
    {
        matrix : [2][3]s32 = .[ .[1, 2, 3], .[4, 5, 6] ];
        print("m[0][0]: {}\n", matrix[0][0]);
        print("m[0][2]: {}\n", matrix[0][2]);
        print("m[1][0]: {}\n", matrix[1][0]);
        print("m[1][2]: {}\n", matrix[1][2]);
    }

    // ========================================================
    // 24. STRING COMPARISON
    // ========================================================
    print("=== 24. String Comparison ===\n");
    {
        a := "hello";
        b := "hello";
        c := "world";
        print("str-eq: {}\n", a == b);
        print("str-neq: {}\n", a != c);
        print("str-diff: {}\n", a == c);
        empty := "";
        print("empty-eq: {}\n", empty == "");
    }

    // ========================================================
    // 25. ARRAY LOOP MUTATION
    // ========================================================
    print("=== 25. Array Loop Mutation ===\n");
    {
        arr : [4]s32 = .[0, 0, 0, 0];
        i := 0;
        while i < 4 {
            arr[i] = xx (i + 1);
            i += 1;
        }
        print("loop-fill: {} {} {} {}\n", arr[0], arr[1], arr[2], arr[3]);
        arr[2] += 10;
        print("compound: {}\n", arr[2]);
    }

    // === 26. #using struct composition ===
    print("=== 26. #using ===\n");
    {
        UBase :: struct { x: s32; y: s32; }
        UExt :: struct { #using UBase; z: s32; }
        e := UExt.{ x = 1, y = 2, z = 3 };
        print("using-x: {}\n", e.x);
        print("using-y: {}\n", e.y);
        print("using-z: {}\n", e.z);

        // #using in middle position
        UHeader :: struct { version: s32; }
        UPacket :: struct { id: s32; #using UHeader; payload: s32; }
        p := UPacket.{ id = 10, version = 42, payload = 99 };
        print("pkt-id: {}\n", p.id);
        print("pkt-ver: {}\n", p.version);
        print("pkt-pay: {}\n", p.payload);

        // Multiple #using
        UPos :: struct { px: s32; py: s32; }
        UCol :: struct { r: s32; g: s32; }
        USprite :: struct { #using UPos; #using UCol; scale: s32; }
        s := USprite.{ px = 10, py = 20, r = 255, g = 128, scale = 1 };
        print("sprite-px: {}\n", s.px);
        print("sprite-r: {}\n", s.r);
        print("sprite-scale: {}\n", s.scale);
    }

    // --- Comptime format ---
    {
        ct_body :: "hello";
        ct_msg :: format("say: {} (len={})", ct_body, ct_body.len);
        print("{}\n", ct_msg);

        ct_num :: 42;
        ct_num_msg :: format("n={}", ct_num);
        print("{}\n", ct_num_msg);
    }

    // --- Tuples ---
    {
        print("=== Tuples ===\n");
        pair := (40, 2);
        print("{}\n", pair.0);
        print("{}\n", pair.1);

        named := (x: 10, y: 20);
        print("{}\n", named.x);
        print("{}\n", named.0);

        single := (42,);
        print("{}\n", single.0);

        zeroed : (s32, s32) = ---;
        print("{}\n", zeroed.0);
        print("{}\n", zeroed.1);
    }

    // --- UFCS Aliases & Pipe ---
    {
        print("=== UFCS Aliases ===\n");

        num_sum :: (a: s64, b: s64) -> s64 { a + b; }
        sum :: ufcs num_sum;

        print("{}\n", num_sum(40, 2));   // 42 — direct call
        print("{}\n", sum(40, 2));       // 42 — alias direct call
        print("{}\n", 40 |> sum(2));     // 42 — pipe UFCS via alias

        print("{}\n", num_sum(40, 2));   // 42 — direct (was tuple full-splat)
        print("{}\n", 40 |> sum(2));     // 42 — pipe (was tuple partial-splat)

        compute :: (a: s64, b: s64, c: s64, d: s64) -> s64 { a + b * c - d; }
        calc :: ufcs compute;

        print("{}\n", compute(1, 2, 3, 4));    // 1+2*3-4 = 3 (was tuple full-splat)
        print("{}\n", compute(1, 2, 3, 4));    // same = 3 (was tuple partial-splat)
        print("{}\n", 1 |> calc(2, 3, 4));     // same = 3 — pipe UFCS

        // Tuple return type
        swap :: (a: s64, b: s64) -> (s64, s64) { (b, a); }
        s := swap(1, 2);
        a := s.0;
        b := s.1;
        print("{}\n", a);                // 2
        print("{}\n", b);                // 1

        wrap :: (x: s64) -> (s64) { (x,); }
        t := wrap(99);
        print("{}\n", t.0);             // 99
    }

    // --- Tuple Operators ---
    {
        print("=== Tuple Operators ===\n");

        // Equality
        print("{}\n", (1, 2) == (1, 2));     // true
        print("{}\n", (1, 2) == (1, 3));     // false
        print("{}\n", (1, 2) != (1, 3));     // true
        print("{}\n", (1, 2) != (1, 2));     // false

        // Concatenation
        c := (1, 2) + (3, 4);
        print("{}\n", c.0);    // 1
        print("{}\n", c.1);    // 2
        print("{}\n", c.2);    // 3
        print("{}\n", c.3);    // 4

        // Repetition
        r := (1, 2) * 3;
        print("{}\n", r.0);    // 1
        print("{}\n", r.1);    // 2
        print("{}\n", r.2);    // 1
        print("{}\n", r.3);    // 2
        print("{}\n", r.4);    // 1
        print("{}\n", r.5);    // 2

        // Lexicographic comparison
        print("{}\n", (1, 2) < (1, 3));      // true
        print("{}\n", (1, 3) < (1, 2));      // false
        print("{}\n", (1, 2) < (1, 2));      // false
        print("{}\n", (1, 2) <= (1, 2));     // true
        print("{}\n", (2, 0) > (1, 9));      // true
        print("{}\n", (1, 2) >= (1, 2));     // true

        // Membership
        print("{}\n", 2 in (1, 2, 3));      // true
        print("{}\n", 5 in (1, 2, 3));      // false
    }

    // --- Directory imports ---
    {
        print("--- directory imports ---\n");
        print("{}\n", pkg.add(3, 4));         // 7
        print("{}\n", pkg.mul(5, 6));         // 30
        print("{}\n", pkg.hello());           // hello from testpkg
        print("{}\n", pkg.cwd_greet());       // cwd-import-ok
    }

    // --- Pipe operator ---
    {
        print("--- pipe operator ---\n");
        // Basic: a |> f(b) → f(a, b)
        print("{}\n", 3 |> pkg.add(4));           // 7
        print("{}\n", 5 |> pkg.mul(6));           // 30

        // Chaining: a |> f(b) |> g(c) → g(f(a, b), c)
        print("{}\n", 3 |> pkg.add(4) |> pkg.mul(2));  // 14

        // With non-namespaced functions
        print("{}\n", "hello" |> concat(" world"));     // hello world

        // Chained string ops
        print("{}\n", "piped" |> concat(" ok") |> concat("!"));  // piped ok!
    }

    // ── alloc_slice ──────────────────────────────────────────
    {
        items := alloc_slice(s64, 5);
        items[0] = 10;
        items[1] = 20;
        items[2] = 30;
        items[3] = 40;
        items[4] = 50;
        print("alloc len: {}\n", items.len);         // alloc len: 5
        print("alloc[0]: {}\n", items[0]);            // alloc[0]: 10
        print("alloc[4]: {}\n", items[4]);            // alloc[4]: 50

        // alloc_slice with u8
        bytes := alloc_slice(u8, 3);
        bytes[0] = 65;
        bytes[1] = 66;
        bytes[2] = 67;
        print("bytes len: {}\n", bytes.len);          // bytes len: 3
    }

    // ========================================================
    // ALLOCATORS
    // ========================================================
    print("--- allocators ---\n");

    // ── GPA ─────────────────────────────────────────────────
    {
        gpa := GPA.init();
        a : Allocator = xx gpa;
        p1 := a.alloc(64);
        p2 := a.alloc(128);
        print("gpa allocs: {}\n", gpa.alloc_count);         // gpa allocs: 2
        a.dealloc(p1);
        a.dealloc(p2);
        print("gpa final: {}\n", gpa.alloc_count);          // gpa final: 0
    }

    // ── Arena backed by GPA (multi-chunk) ───────────────────
    {
        gpa3 := GPA.init();
        arena := Arena.init(xx gpa3, 32);
        a : Allocator = xx arena;
        // First chunk fits 80 usable bytes
        a1 := a.alloc(40);
        a2 := a.alloc(40);
        // Counts: just the first chunk = 1. Arena.init returns the
        // state by value; the local IS the Arena struct, no parent
        // allocation for the state itself.
        print("arena chunks: {}\n", gpa3.alloc_count);        // arena chunks: 1
        // Overflow → new chunk
        a3 := a.alloc(16);
        print("arena overflow: {}\n", gpa3.alloc_count);      // arena overflow: 2
        // Verify memory works across chunks
        p1 : [*]u8 = xx a1;
        p3 : [*]u8 = xx a3;
        p1[0] = 42;
        p3[0] = 99;
        print("arena a1: {}\n", p1[0]);                       // arena a1: 42
        print("arena a3: {}\n", p3[0]);                       // arena a3: 99
        // Reset retains the first chunk
        arena.reset();
        print("arena reset idx: {}\n", arena.end_index);      // arena reset idx: 0
        print("arena reset gpa: {}\n", gpa3.alloc_count);     // arena reset gpa: 1
        // Deinit frees all chunks (caller's local is the state — no
        // dealloc of the struct itself).
        arena.deinit();
        print("arena deinit: {}\n", gpa3.alloc_count);        // arena deinit: 0
    }

    // ── BufAlloc from stack array ───────────────────────────
    {
        stack_buf : [128]u8 = ---;
        buf := BufAlloc.init(@stack_buf[0], 128);
        a : Allocator = xx buf;
        b1 := a.alloc(24);
        b2 := a.alloc(24);
        print("buf pos: {}\n", buf.pos);                    // buf pos: 48
        b3 := a.alloc(200);
        b3_i : s64 = xx b3;
        print("buf overflow: {}\n", b3_i);                  // buf overflow: 0
        buf.reset();
        print("buf reset: {}\n", buf.pos);                  // buf reset: 0
    }

    {
        if 1 == (1,) {
            print("1 == (1)\n");
        }

        if (1,) == (1) {
            print("(1) == 1\n");
        }

        if (1,) == 1 {
            print("1 == 1\n");
        }
    }

    // ========================================================
    // OPTIONALS
    // ========================================================
    print("--- optionals ---\n");

    // Basic optional creation and null
    {
        x: ?s32 = 42;
        y: ?s32 = null;
        print("opt x: {}\n", x);                           // opt x: 42
        print("opt y: {}\n", y);                            // opt y: null
    }

    // Force unwrap
    {
        x: ?s32 = 10;
        val := x!;
        print("unwrap: {}\n", val);                         // unwrap: 10
    }

    // Null coalescing
    {
        x: ?s32 = 42;
        y: ?s32 = null;
        a := x ?? 0;
        b := y ?? 99;
        print("coalesce a: {}\n", a);                       // coalesce a: 42
        print("coalesce b: {}\n", b);                       // coalesce b: 99

        // Chained ?? (right-associative): a ?? b ?? c
        z: ?s32 = null;
        c := x ?? y ?? 0;
        d := z ?? y ?? 99;
        e := z ?? z ?? 0;
        print("chained ?? c: {}\n", c);                     // chained ?? c: 42
        print("chained ?? d: {}\n", d);                     // chained ?? d: 99
        print("chained ?? e: {}\n", e);                     // chained ?? e: 0
    }

    // If-binding (safe unwrap)
    {
        x: ?s32 = 7;
        y: ?s32 = null;
        if val := x {
            print("if-bind x: {}\n", val);                  // if-bind x: 7
        }
        if val := y {
            print("if-bind y: should not print\n");
        } else {
            print("if-bind y: none\n");                     // if-bind y: none
        }
    }

    // Pattern matching on optionals
    {
        check :: (v: ?s32) -> s32 {
            return if v == {
                case .some: (val) { val; }
                case .none: { 0; }
            };
        }
        a: ?s32 = 55;
        b: ?s32 = null;
        print("match some: {}\n", check(a));                // match some: 55
        print("match none: {}\n", check(b));                // match none: 0
    }

    // Optional with implicit wrapping
    {
        opt_wrap :: (n: s32) -> ?s32 {
            if n > 0 {
                return n;
            }
            return null;
        }
        r1 := opt_wrap(5);
        r2 := opt_wrap(0);
        print("wrap pos: {}\n", r1);                        // wrap pos: 5
        print("wrap neg: {}\n", r2);                        // wrap neg: null
    }

    // Struct field defaults for ?T
    {
        n := OptNode.{ value = 10 };
        print("opt field default: {}\n", n.next);           // opt field default: null
        m := OptNode.{ value = 20, next = 42 };
        print("opt field set: {}\n", m.next);               // opt field set: 42
    }

    // ?T as function parameter
    {
        opt_process :: (val: ?s32) -> s32 {
            return val ?? 0;
        }
        a: ?s32 = 42;
        b: ?s32 = null;
        print("opt param a: {}\n", opt_process(a));         // opt param a: 42
        print("opt param b: {}\n", opt_process(b));         // opt param b: 0
        print("opt param 7: {}\n", opt_process(7));         // opt param 7: 7
    }

    // Assignment to optional variable (f32 → ?f32)
    {
        iw: ?f32 = null;
        w: f32 = 42.5;
        iw = w;
        print("opt reassign: {}\n", iw ?? 0.0);                // opt reassign: 42.5

        // Assignment of computed value to optional
        iw2: ?f32 = null;
        a: ?f32 = 10.0;
        if v := a { iw2 = v + 5.0; }
        print("opt compute assign: {}\n", iw2 ?? 0.0);         // opt compute assign: 15.0

        // Re-assign optional back to null
        iw2 = null;
        print("opt re-null: {}\n", iw2 ?? 99.0);               // opt re-null: 99.0
    }

    // Generic function with ?T return
    {
        first_pos :: ($T: Type, a: T, b: T) -> ?T {
            if a > 0 { return a; }
            if b > 0 { return b; }
            return null;
        }
        print("generic opt 1: {}\n", first_pos(s32, 5, 10));  // generic opt 1: 5
        print("generic opt 2: {}\n", first_pos(s32, 0, 7));   // generic opt 2: 7
        print("generic opt 3: {}\n", first_pos(s32, 0, 0));   // generic opt 3: null
    }

    // Optional chaining (?.)
    {
        p: ?OptNode = OptNode.{ value = 10, next = 20 };
        q: ?OptNode = null;
        print("chain some: {}\n", p?.value ?? 0);           // chain some: 10
        print("chain none: {}\n", q?.value ?? 0);           // chain none: 0
        print("chain print: {}\n", p?.next);                 // chain print: 20
        print("chain null: {}\n", q?.next);                  // chain null: null

        // Chained: obj.field?.field
        o1 := OptOuter.{ inner = OptInner.{ val = 99 } };
        o2 := OptOuter.{ inner = null };
        print("deep chain 1: {}\n", o1.inner?.val ?? 0);    // deep chain 1: 99
        print("deep chain 2: {}\n", o2.inner?.val ?? 0);    // deep chain 2: 0
    }

    // Flow-sensitive narrowing
    {
        x: ?s32 = 42;
        y: ?s32 = null;

        // if x != null → x is narrowed to s32
        if x != null {
            print("narrow x: {}\n", x);                        // narrow x: 42
        }

        // if y != null → not entered
        if y != null {
            print("should not print\n");
        } else {
            print("narrow y else: null\n");                    // narrow y else: null
        }

        // if x == null ... else → else-branch narrowed
        if x == null {
            print("should not print\n");
        } else {
            print("narrow else x: {}\n", x);                  // narrow else x: 42
        }
    }

    // Guard narrowing
    {
        guard_fn :: (v: ?s32) -> s32 {
            if v == null { return 0; }
            return v;
        }
        print("guard some: {}\n", guard_fn(42));               // guard some: 42
        print("guard none: {}\n", guard_fn(null));             // guard none: 0
    }

    // Compound narrowing: && chains
    {
        a: ?s32 = 10;
        b: ?s32 = 20;
        c: ?s32 = null;
        if a != null and b != null {
            print("and both: {} {}\n", a, b);                  // and both: 10 20
        }
        if a != null and c != null {
            print("should not print\n");
        } else {
            print("and one null\n");                           // and one null
        }
    }

    // Compound guard narrowing: || chains
    {
        guard2 :: (a: ?s32, b: ?s32) -> s32 {
            if a == null or b == null { return 0; }
            return a + b;
        }
        print("or guard: {}\n", guard2(3, 4));                 // or guard: 7
        print("or guard null: {}\n", guard2(3, null));         // or guard null: 0
    }

    // Nested if narrowing
    {
        a: ?s32 = 10;
        b: ?s32 = 20;
        if a != null {
            if b != null {
                print("nested narrow: {} {}\n", a, b);         // nested narrow: 10 20
            }
        }
    }

    // Guard narrowing used in loop
    {
        guard_loop :: (v: ?s32) -> s32 {
            if v == null { return 0; }
            sum := 0;
            i := 0;
            while i < v {
                sum = sum + 1;
                i = i + 1;
            }
            return sum;
        }
        print("guard loop: {}\n", guard_loop(3));              // guard loop: 3
    }

    // --- block-body lambdas ---
    {
        // block-body lambda with return type
        clamp := (x: s64, lo: s64, hi: s64) -> s64 {
            if x < lo { return lo; }
            if x > hi { return hi; }
            return x;
        };
        print("block-lambda: {}\n", clamp(50, 0, 100));   // block-lambda: 50
        print("block-lambda: {}\n", clamp(-10, 0, 100));  // block-lambda: 0
        print("block-lambda: {}\n", clamp(999, 0, 100));  // block-lambda: 100

        // block-body lambda without return type annotation
        greet := (name: string) {
            print("hello {}\n", name);
        };
        greet("block");  // hello block
    }

    // --- named params in function types ---
    {
        // Named params are documentation only — ignored for type identity
        apply_named :: (f: (x: s32, y: s32) -> s32, a: s32, b: s32) -> s32 {
            return f(a, b);
        }
        add :: (a: s32, b: s32) -> s32 { return a + b; }
        print("named-fn-type: {}\n", apply_named(add, 3, 4));  // named-fn-type: 7
    }

    // --- xx on function pointers ---
    {
        MyEnv :: struct { n: s32; }
        typed_fn :: (e: *MyEnv, x: s32) -> s32 {
            return x + e.n;
        }
        // xx cast: (*MyEnv, s32) -> s32  →  (*void, s32) -> s32
        f : (*void, s32) -> s32 = xx typed_fn;
        env := MyEnv.{ n = 100 };
        print("xx-fnptr: {}\n", f(xx @env, 42));  // xx-fnptr: 142
    }

    // --- closure type: construct and access fields ---
    {
        dummy_fn :: (env: *void, x: s32) -> s32 {
            return x * 2;
        }
        fn_ptr : *void = xx dummy_fn;
        null_env : *void = xx 0;
        c : Closure(s32) -> s32 = .{ fn_ptr = fn_ptr, env = null_env };
        print("closure-type: fn_ptr-nonnull={}\n", c.fn_ptr != null_env);
        print("closure-type: env-null={}\n", c.env == null_env);
    }

    // --- closure calling convention ---
    {
        Env :: struct { n: s32; }
        impl_fn :: (env: *void, x: s32) -> s32 {
            e : *Env = xx env;
            return x + e.n;
        }
        env := Env.{ n = 5 };
        fn_ptr : *void = xx impl_fn;
        env_ptr : *void = xx @env;
        c : Closure(s32) -> s32 = .{ fn_ptr = fn_ptr, env = env_ptr };
        print("closure-call: {}\n", c(10));
    }

    // --- auto-promotion: bare fn → Closure ---
    {
        double :: (x: s32) -> s32 { return x * 2; }
        apply :: (f: Closure(s32) -> s32, x: s32) -> s32 { return f(x); }
        print("auto-promote: {}\n", apply(double, 10));

        // Named function to Closure variable
        f : Closure(s32) -> s32 = double;
        print("auto-promote-var: {}\n", f(5));
    }

    // --- closure() intrinsic ---
    {
        // capture scalar
        n := 42;
        f := closure((x: s32) => x + n);
        print("closure-capture: {}\n", f(10));

        // capture by value is a snapshot
        m := 5;
        g := closure((x: s32) => x + m);
        m = 100;
        print("closure-snapshot: {}\n", g(10));

        // no captures (null env)
        h := closure((x: s32) => x * 2);
        print("closure-nocap: {}\n", h(7));

        // multiple captures
        a := 10;
        b := 20;
        multi := closure((x: s32) => x + a + b);
        print("closure-multi: {}\n", multi(3));

        // block-body closure with return
        offset := 50;
        clamp := closure((x: s64) -> s64 {
            if x < 0 { return 0; }
            if x > 100 { return 100; }
            return x + offset;
        });
        r1 : s64 = clamp(10);
        r2 : s64 = clamp(0 - 5);
        r3 : s64 = clamp(999);
        print("closure-block: {}\n", r1);
        print("closure-block: {}\n", r2);
        print("closure-block: {}\n", r3);

        // void closure
        tag := "LOG";
        logger := closure((msg: string) {
            print("[{}] {}\n", tag, msg);
        });
        logger("hello");

        // pass closure to higher-order function
        dbl :: (x: s32) -> s32 { return x * 2; }
        apply_cl :: (f2: Closure(s32) -> s32, x: s32) -> s32 { return f2(x); }
        factor : s32 = 3;
        print("closure-hof: {}\n", apply_cl(closure((x: s32) -> s32 => x * factor), 10));

        // auto-promoted bare fn passed alongside closures
        print("closure-hof-bare: {}\n", apply_cl(dbl, 10));

        // C5.A2: capture f32
        scale := 2.5;
        f_f32 := closure((x: f32) -> f32 => x * scale);
        print("closure-f32: {}\n", f_f32(4.0));

        // C5.A3: capture bool
        verbose := true;
        f_bool := closure((msg: string) {
            if verbose { print("closure-bool: {}\n", msg); }
        });
        f_bool("hello");

        // C5.B3: two params
        base : s32 = 100;
        f_2p := closure((x: s32, y: s32) -> s32 => x + y + base);
        print("closure-2p: {}\n", f_2p(3, 4));

        // C5.B4: three params
        bias : s32 = 1;
        f_3p := closure((a: s32, b: s32, c2: s32) -> s32 => a + b + c2 + bias);
        print("closure-3p: {}\n", f_3p(10, 20, 30));

        // C5.B5: mixed param types (string + s32)
        extra : s32 = 5;
        f_mix := closure((name: string, age: s32) {
            print("closure-mix: {} is {}\n", name, age + extra);
        });
        f_mix("Alice", 30);

        // C5.C3: return bool
        threshold : s32 = 100;
        f_rbool := closure((x: s32) -> bool { return x > threshold; });
        print("closure-rbool: {} {}\n", f_rbool(50), f_rbool(200));

        // C5.D3: reduce / fold
        reduce :: (arr: []s32, f3: Closure(s32, s32) -> s32, init: s32) -> s32 {
            acc := init;
            i : s64 = 0;
            while i < arr.len { acc = f3(acc, arr[i]); i += 1; }
            return acc;
        }
        r_nums : []s32 = .[1, 2, 3, 4, 5];
        r_bonus : s32 = 100;
        r_total := reduce(r_nums, closure((acc: s32, x: s32) -> s32 => acc + x), r_bonus);
        print("closure-reduce: {}\n", r_total);

        // C5.G1: factory function
        make_adder :: (n: s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => x + n);
        }
        add5 := make_adder(5);
        add10 := make_adder(10);
        print("closure-factory: {} {}\n", add5(100), add10(100));

        // C5.A5: capture struct
        origin := Point.{ x = 10, y = 20 };
        f_st := closure(() {
            print("closure-struct: {} {}\n", origin.x, origin.y);
        });
        f_st();

        // C5.H1: closure captures another closure
        inner_n := 10;
        inner_cl := closure((x: s64) -> s64 => x + inner_n);
        outer_cl := closure((x: s64) -> s64 => inner_cl(x) * 2);
        print("closure-compose: {}\n", outer_cl(5));

        // C5.M7: multiple closures from same scope capture independently
        shared : s32 = 10;
        cl_a := closure((x: s32) -> s32 => x + shared);
        cl_b := closure((x: s32) -> s32 => x * shared);
        print("closure-indep: {} {}\n", cl_a(5), cl_b(5));

        // C6: optional closures
        f_none : ?Closure(s64) -> s64 = null;
        if h := f_none {
            print("should not print: {}\n", h(1));
        } else {
            print("opt-closure: none\n");
        }

        opt_n := 10;
        f_some : ?Closure(s64) -> s64 = closure((x: s64) -> s64 => x + opt_n);
        if h := f_some {
            print("opt-closure: {}\n", h(5));
        } else {
            print("should not print\n");
        }

        // Struct with optional closure callback
        Btn :: struct { label: string; on_click: ?Closure(s64) -> void; }
        btn_x := 99;
        btn_cl := closure((id: s64) {
            print("opt-closure-btn: {} {}\n", id, btn_x);
        });
        btn1 := Btn.{ label = "OK", on_click = btn_cl };
        btn2 := Btn.{ label = "Cancel", on_click = null };
        if h := btn1.on_click { h(1); }
        if h := btn2.on_click { h(2); } else { print("opt-closure-btn: null\n"); }

        // C5.A6: capture pointer (shared mutable state)
        count_a6 : s32 = 0;
        p_a6 := @count_a6;
        inc_fn := closure(() { p_a6.* += 1; });
        inc_fn(); inc_fn(); inc_fn();
        print("closure-ptr: {}\n", count_a6);

        // C5.A9: capture enum value (as s32 tag)
        c_a9 : s32 = 2;  // simulate enum tag
        f_a9 := closure(() -> s32 => c_a9);
        print("closure-enum: {}\n", f_a9());

        // C5.C4: return string
        tag_c4 := "INFO";
        f_c4 := closure((msg: string) -> string => format("[{}] {}", tag_c4, msg));
        print("closure-rstr: {}\n", f_c4("ok"));

        // C5.C5: return struct
        off_c5 := Point.{ x = 10, y = 20 };
        f_c5 := closure((p: Point) -> Point => Point.{ x = p.x + off_c5.x, y = p.y + off_c5.y });
        res_c5 := f_c5(Point.{ x = 1, y = 2 });
        print("closure-rstruct: {} {}\n", res_c5.x, res_c5.y);

        // C5.G2: factory with multiple captures
        make_linear :: (m: s32, b: s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => m * x + b);
        }
        lin := make_linear(3, 7);
        print("closure-linear: {}\n", lin(10));

        // C5.G3: factory returning clamper
        make_clamper :: (lo: s32, hi: s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 {
                if x < lo { return lo; }
                if x > hi { return hi; }
                return x;
            });
        }
        clamp_fn := make_clamper(0, 255);
        cv1 : s32 = xx -10;
        cv2 : s32 = 100;
        cv3 : s32 = 999;
        print("closure-clamp: {} {} {}\n", clamp_fn(cv1), clamp_fn(cv2), clamp_fn(cv3));

        // C5.H2: compose
        compose :: (f_h2: Closure(s32) -> s32, g_h2: Closure(s32) -> s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => f_h2(g_h2(x)));
        }
        one_h2 : s32 = 1;
        two_h2 : s32 = 2;
        add1_h2 := closure((x: s32) -> s32 => x + one_h2);
        mul2_h2 := closure((x: s32) -> s32 => x * two_h2);
        composed := compose(mul2_h2, add1_h2);
        print("closure-compose2: {}\n", composed(5));

        // C5.H3: chain of closures
        ch_k1 : s32 = 1;
        ch_k2 : s32 = 2;
        ch_k10 : s32 = 10;
        ch_a := closure((x: s32) -> s32 => x + ch_k1);
        ch_b := closure((x: s32) -> s32 => ch_a(x) * ch_k2);
        ch_c := closure((x: s32) -> s32 => ch_b(x) + ch_k10);
        print("closure-chain: {}\n", ch_c(5));

        // C5.D1: map
        map_cl :: (arr: [*]s32, cnt: s64, f_map: Closure(s32) -> s32, result: [*]s32) {
            i := 0;
            while i < cnt { result[i] = f_map(arr[i]); i += 1; }
        }
        map_src : [5]s32 = .[1, 2, 3, 4, 5];
        map_dst : [5]s32 = .[0, 0, 0, 0, 0];
        factor_d1 : s32 = 3;
        map_cl(xx @map_src, 5, closure((x: s32) -> s32 => x * factor_d1), xx @map_dst);
        print("closure-map: {} {} {} {} {}\n", map_dst[0], map_dst[1], map_dst[2], map_dst[3], map_dst[4]);

        // C5.D2: filter
        filter_cl :: (arr: [*]s32, cnt: s64, pred: Closure(s32) -> bool, result: [*]s32) -> s64 {
            j := 0;
            i := 0;
            while i < cnt {
                if pred(arr[i]) { result[j] = arr[i]; j += 1; }
                i += 1;
            }
            return j;
        }
        min_val : s32 = 3;
        filt_dst : [5]s32 = .[0, 0, 0, 0, 0];
        kept := filter_cl(xx @map_src, 5, closure((x: s32) -> bool => x >= min_val), xx @filt_dst);
        print("closure-filter: {} [{} {} {}]\n", kept, filt_dst[0], filt_dst[1], filt_dst[2]);

        // C5.D4: sort comparator (bubble sort)
        sort_cl :: (arr: [*]s32, cnt: s64, less: Closure(s32, s32) -> bool) {
            i := 0;
            while i < cnt {
                j := 0;
                while j < cnt - 1 - i {
                    if less(arr[j + 1], arr[j]) {
                        tmp := arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = tmp;
                    }
                    j += 1;
                }
                i += 1;
            }
        }
        sort_arr : [5]s32 = .[5, 3, 1, 4, 2];
        descending := true;
        sort_cl(xx @sort_arr, 5, closure((a: s32, b: s32) -> bool {
            if descending { return a > b; }
            return a < b;
        }));
        print("closure-sort: {} {} {} {} {}\n", sort_arr[0], sort_arr[1], sort_arr[2], sort_arr[3], sort_arr[4]);

        // C5.D5: for_each with index
        for_each_cl :: (arr: [*]s32, cnt: s64, f_fe: Closure(s32, s64) -> void) {
            i : s64 = 0;
            while i < cnt { f_fe(arr[i], i); i += 1; }
        }
        fe_label := "item";
        fe_arr : [3]s32 = .[10, 20, 30];
        for_each_cl(xx @fe_arr, 3, closure((val: s32, idx: s64) {
            print("closure-fe: {} {}={}\n", fe_label, idx, val);
        }));

        // C5.D6: find
        find_cl :: (arr: [*]s32, cnt: s64, pred_f: Closure(s32) -> bool) -> s64 {
            i : s64 = 0;
            while i < cnt {
                if pred_f(arr[i]) { return i; }
                i += 1;
            }
            return -1;
        }
        target : s32 = 30;
        found_idx := find_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x == target));
        print("closure-find: {}\n", found_idx);

        // C5.D7: any
        any_cl :: (arr: [*]s32, cnt: s64, pred_a: Closure(s32) -> bool) -> bool {
            i : s64 = 0;
            while i < cnt {
                if pred_a(arr[i]) { return true; }
                i += 1;
            }
            return false;
        }
        has_big := any_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x > 100));
        has_20 := any_cl(xx @fe_arr, 3, closure((x: s32) -> bool => x == 20));
        print("closure-any: {} {}\n", has_big, has_20);

        // C5.E4: auto-promotion in struct field assignment
        Widget :: struct { transform: Closure(s32) -> s32; }
        negate_fn :: (x: s32) -> s32 { return 0 - x; }
        w_e4 := Widget.{ transform = negate_fn };
        print("closure-struct-field: {}\n", w_e4.transform(5));

        // C5.F1: single closure callback in struct
        Button :: struct {
            label: string;
            on_press: Closure(s32) -> void;
        }
        btn_x2 := 99;
        btn_cb := closure((id: s32) {
            print("closure-btn: {} {}\n", id, btn_x2);
        });
        btn3 := Button.{ label = "OK", on_press = btn_cb };
        btn3.on_press(1);

        // C5.J1: stateful counter via pointer capture
        state_j1 : s32 = 0;
        p_j1 := @state_j1;
        inc_j1 := closure(() -> s32 { p_j1.* += 1; return p_j1.*; });
        print("closure-counter: {} {} {}\n", inc_j1(), inc_j1(), inc_j1());

        // C5.J2: stateful accumulator
        state_j2 : s32 = 100;
        p_j2 := @state_j2;
        acc_j2 := closure((x: s32) -> s32 { p_j2.* += x; return p_j2.*; });
        print("closure-acc: {} {}\n", acc_j2(5), acc_j2(10));

        // C5.K2: block-body with local variables and loops
        base_k2 : s32 = 100;
        sum_fn := closure((items: [*]s32, cnt: s64) -> s32 {
            total : s32 = 0;
            i : s64 = 0;
            while i < cnt {
                total += items[i];
                i += 1;
            }
            return total + base_k2;
        });
        k2_arr : [5]s32 = .[1, 2, 3, 4, 5];
        print("closure-loop: {}\n", sum_fn(xx @k2_arr, 5));

        // C5.M3: reassigning a closure variable
        n_m3 : s32 = 1;
        f_m3 := closure((x: s32) -> s32 => x + n_m3);
        print("closure-reassign: {}\n", f_m3(10));
        m_m3 : s32 = 2;
        f_m3 = closure((x: s32) -> s32 => x * m_m3);
        print("closure-reassign: {}\n", f_m3(10));

        // C5.M6b: snapshot verified with struct capture
        pt_m6 := Point.{ x = 5, y = 10 };
        f_m6 := closure(() -> s32 => pt_m6.x + pt_m6.y);
        pt_m6 = Point.{ x = 99, y = 99 };
        print("closure-snapstruct: {}\n", f_m6());

        // C5.M2: closure capturing auto-promoted closure
        double_m2 :: (x: s32) -> s32 { return x * 2; }
        base_m2 : Closure(s32) -> s32 = double_m2;
        n_m2 : s32 = 1;
        f_m2 := closure((x: s32) -> s32 => base_m2(x) + n_m2);
        print("closure-cap-promoted: {}\n", f_m2(5));

        // C5.M5: immediately invoked closure (via temp var)
        n_m5 : s32 = 5;
        iife := closure((x: s32) -> s32 => x + n_m5);
        result_m5 := iife(10);
        print("closure-iife: {}\n", result_m5);

        // C5.F2: optional callback (none)
        Toggle :: struct { on_change: ?Closure(bool) -> void; }
        t_f2 := Toggle.{ on_change = null };
        if h := t_f2.on_change { h(true); } else { print("closure-toggle: none\n"); }

        // C5.F3: optional callback (some)
        t_f3_cb := closure((enabled: bool) { print("closure-toggle: {}\n", enabled); });
        t_f3 := Toggle.{ on_change = t_f3_cb };
        if h := t_f3.on_change { h(true); }

        // C5.F5: callback receiving caller context
        Panel :: struct {
            title: string;
            on_resize: Closure(string, s32, s32) -> void;
        }
        p_f5_cb := closure((title: string, w: s32, h: s32) {
            print("closure-panel: {} {}x{}\n", title, w, h);
        });
        p_f5 := Panel.{ title = "main", on_resize = p_f5_cb };
        p_f5.on_resize(p_f5.title, 800, 600);

        // C5.E6: protocol value passed through multiple function calls
        step3 :: (a: Allocator) -> *void { a.alloc(8); }
        step2 :: (a: Allocator) -> *void { step3(a); }
        step1 :: (a: Allocator) -> *void { step2(a); }
        gpa_e6 := GPA.init();
        a_e6 : Allocator = xx gpa_e6;
        ptr_e6 := step1(a_e6);
        print("closure-chain-call: {}\n", ptr_e6 != null);
        a_e6.dealloc(ptr_e6);

        // C5.I1: creating closures in a loop (each captures different value)
        // TEMPORARILY DISABLED — closure-in-loop causes infinite loop (index_gep element size issue?)
        // cl_arr : [5]Closure(s32) -> s32 = ---;
        // i_loop := 0;
        // while i_loop < 5 {
        //     val_loop : s32 = xx (i_loop * 10);
        //     cl_arr[i_loop] = closure((x: s32) -> s32 => x + val_loop);
        //     i_loop += 1;
        // }
        // I2: calling closures from array
        // tmp_cl := cl_arr[0]; print("closure-loop-0: {}\n", tmp_cl(1));
        // tmp_cl = cl_arr[1]; print("closure-loop-1: {}\n", tmp_cl(1));
        // tmp_cl = cl_arr[4]; print("closure-loop-4: {}\n", tmp_cl(1));

        // C5.M4: closure in conditional expression (via temp var)
        use_fast := true;
        k_fast : s32 = 2;
        k_slow : s32 = 10;
        f_fast := closure((x: s32) -> s32 => x * k_fast);
        f_slow := closure((x: s32) -> s32 => x + k_slow);
        f_cond : Closure(s32) -> s32 = if use_fast then f_fast else f_slow;
        print("closure-cond: {}\n", f_cond(5));

        // C5.F4: multiple callbacks on one struct
        Form :: struct {
            on_submit: ?Closure() -> void;
            on_cancel: ?Closure() -> void;
        }
        msg_f4 := "submitted";
        sub_cb := closure(() { print("closure-form: {}\n", msg_f4); });
        form_f4 := Form.{ on_submit = sub_cb, on_cancel = null };
        if h := form_f4.on_submit { h(); }
        if h := form_f4.on_cancel { h(); } else { print("closure-form: no cancel\n"); }

        // C5.L3: auto-promoted closure env is null (no free needed)
        double_l3 :: (x: s32) -> s32 { return x * 2; }
        f_l3 : Closure(s32) -> s32 = double_l3;
        print("closure-null-env: {}\n", f_l3.env == null);

        // C5.A7: capture slice (fat pointer like string)
        sl_a7 : [3]s32 = .[10, 20, 30];
        ptr_a7 : [*]s32 = xx @sl_a7;
        f_a7 := closure((i: s64) -> s32 => ptr_a7[i]);
        print("closure-slice: {} {} {}\n", f_a7(0), f_a7(1), f_a7(2));

        // C5.L1: arena bulk free (closures allocated on arena, freed in bulk)
        gpa_l1 := GPA.init();
        arena_l1 := Arena.init(xx gpa_l1, 4096);
        push Context.{ allocator = xx arena_l1 } {
            n_l1 : s32 = 5;
            f_l1 := closure((x: s32) -> s32 => x + n_l1);
            print("closure-arena: {}\n", f_l1(10));
        }
        arena_l1.deinit();

        // C5.L2: GPA manual free (verify env alloc/dealloc)
        gpa_l2 := GPA.init();
        a_l2 : Allocator = xx gpa_l2;
        n_l2 : s32 = 7;
        result_l2 : s32 = 0;
        push Context.{ allocator = a_l2 } {
            f_l2 := closure((x: s32) -> s32 => x + n_l2);
            result_l2 = f_l2(10);
            a_l2.dealloc(f_l2.env);
        }
        print("closure-gpa: {} allocs={}\n", result_l2, gpa_l2.alloc_count);

        // C5.A10: capture optional
        val_a10 : ?s32 = 42;
        f_a10 := closure(() -> s32 {
            if v := val_a10 { return v; }
            return 0;
        });
        print("closure-opt: {}\n", f_a10());

        // C5.C6: return optional
        limit_c6 : s32 = 100;
        f_c6 := closure((x: s32) -> ?s32 {
            if x > limit_c6 { return null; }
            return x;
        });
        r1_c6 := f_c6(50);
        r2_c6 := f_c6(200);
        if v := r1_c6 { print("closure-ropt: {}\n", v); }
        if v := r2_c6 { print("should-not-print\n"); } else { print("closure-ropt: none\n"); }

        // C5.M8: array of closures with mixed origins
        double_m8 :: (x: s32) -> s32 { return x * 2; }
        n_m8 : s32 = 10;
        fns_m8 : [3]Closure(s32) -> s32 = ---;
        fns_m8[0] = double_m8;                                // auto-promoted
        fns_m8[1] = closure((x: s32) -> s32 => x + n_m8);    // captured
        fns_m8[2] = closure((x: s32) -> s32 => x * x);       // no capture
        tmp_m8 := fns_m8[0]; print("closure-mixed: {}\n", tmp_m8(5));
        tmp_m8 = fns_m8[1]; print("closure-mixed: {}\n", tmp_m8(5));
        tmp_m8 = fns_m8[2]; print("closure-mixed: {}\n", tmp_m8(5));

        // C5.E1: independent closures from same factory (each has own env)
        mk_e1 :: (n: s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => x * n);
        }
        f1_e1 := mk_e1(2);
        f2_e1 := mk_e1(3);
        f3_e1 := mk_e1(4);
        print("closure-factory-indep: {} {} {}\n", f1_e1(10), f2_e1(10), f3_e1(10));

        // C5.E2: deep chain — closure capturing closure capturing closure
        v_e2 : s32 = 1;
        k2_e2 : s32 = 2;
        k100_e2 : s32 = 100;
        f0_e2 := closure((x: s32) -> s32 => x + v_e2);
        f1_e2 := closure((x: s32) -> s32 => f0_e2(x) * k2_e2);
        f2_e2 := closure((x: s32) -> s32 => f1_e2(x) + k100_e2);
        print("closure-deep-chain: {}\n", f2_e2(10));

        // C5.E3: many captures (stress env struct)
        c1_e3 : s32 = 1;
        c2_e3 : s32 = 2;
        c3_e3 : s32 = 3;
        c4_e3 : s32 = 4;
        c5_e3 : s32 = 5;
        c6_e3 : s32 = 6;
        c7_e3 : s32 = 7;
        c8_e3 : s32 = 8;
        big_env := closure(() -> s32 => c1_e3 + c2_e3 + c3_e3 + c4_e3 + c5_e3 + c6_e3 + c7_e3 + c8_e3);
        print("closure-8cap: {}\n", big_env());

        // C5.E5: closure with many parameters (4 params)
        multi_param := closure((a: s32, b: s32, c: s32, d: s32) -> s32 => a + b + c + d);
        a_e5 : s32 = 1; b_e5 : s32 = 2; c_e5 : s32 = 3; d_e5 : s32 = 4;
        print("closure-4param: {}\n", multi_param(a_e5, b_e5, c_e5, d_e5));

        // C5.E7: two closures sharing the same captured pointer
        shared : s32 = 0;
        shared_p := @shared;
        inc_shared := closure(() { shared_p.* += 1; });
        add5_shared := closure(() { shared_p.* += 5; });
        inc_shared();
        add5_shared();
        inc_shared();
        print("closure-shared-ptr: {}\n", shared);

        // C5.E8: closure with f64 arithmetic
        pi_e8 : f64 = 3.14159;
        area_fn := closure((r: f64) -> f64 => pi_e8 * r * r);
        a_e8 := area_fn(10.0);
        print("closure-f64: {}\n", a_e8 > 314.0);

        // C5.E9: zero-capture closure (env should be null, like auto-promoted)
        no_cap := closure((x: s32) -> s32 => x * x);
        print("closure-zerocap: {} {}\n", no_cap(7), no_cap.env == null);

        // C5.E10: closure capturing and calling struct method
        pt_e10 := Point.{ x = 3, y = 4 };
        p_e10 := @pt_e10;
        get_xy := closure(() -> s32 => p_e10.x + p_e10.y);
        print("closure-struct-method: {}\n", get_xy());

        // C5.E11: multiple closures from same factory with different captures
        fns_e11 : [3]Closure(s32) -> s32 = ---;
        i_e11 := 0;
        while i_e11 < 3 {
            multiplier : s32 = xx (i_e11 + 1);
            fns_e11[i_e11] = closure((x: s32) -> s32 => x * multiplier);
            i_e11 += 1;
        }
        t_e11 := fns_e11[0]; print("closure-multi-factory: {}\n", t_e11(10));
        t_e11 = fns_e11[1]; print("closure-multi-factory: {}\n", t_e11(10));
        t_e11 = fns_e11[2]; print("closure-multi-factory: {}\n", t_e11(10));

        // C5.E12: closure capturing bool
        flag_e12 := true;
        check_fn := closure((x: s32) -> bool {
            if flag_e12 { return x > 0; }
            return x < 0;
        });
        pos_e12 : s32 = 5;
        neg_e12 : s32 = xx -3;
        print("closure-bool-cap: {} {}\n", check_fn(pos_e12), check_fn(neg_e12));

        // C5.E13: closure as argument to another closure
        apply_fn := closure((f_app: Closure(s32) -> s32, val: s32) -> s32 => f_app(val));
        k_e13 : s32 = 100;
        inner_fn := closure((x: s32) -> s32 => x + k_e13);
        print("closure-as-arg: {}\n", apply_fn(inner_fn, 42));

        // C5.E14: closure capturing string and formatting
        prefix_e14 := "hello";
        greet_fn := closure((name: string) -> string => format("{} {}", prefix_e14, name));
        print("closure-strfmt: {}\n", greet_fn("world"));

        // C5.E15: reassigning shared pointer target between closure calls
        val_e15 : s32 = 10;
        p_e15 := @val_e15;
        read_fn := closure(() -> s32 => p_e15.*);
        print("closure-ptr-before: {}\n", read_fn());
        val_e15 = 42;
        print("closure-ptr-after: {}\n", read_fn());

        // C5.E16: closure returning negative value
        off_e16 : s32 = 100;
        neg_fn := closure((x: s32) -> s32 => x - off_e16);
        val_e16 : s32 = 30;
        print("closure-neg: {}\n", neg_fn(val_e16));

        // C5.E17: closure with protocol value capture (#inline protocol)
        gpa_e17 := GPA.init();
        a_e17 : Allocator = xx gpa_e17;
        alloc_fn := closure((size: s64) -> *void => a_e17.alloc(size));
        ptr_e17 := alloc_fn(32);
        print("closure-proto-cap: {}\n", ptr_e17 != null);
        a_e17.dealloc(ptr_e17);

        // C5.E18: chained factory — compose two factories
        make_scaler :: (factor: s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => x * factor);
        }
        make_offset :: (off: s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => x + off);
        }
        s_fn := make_scaler(3);
        o_fn := make_offset(7);
        // manually compose: scale then offset
        print("closure-chain-factory: {}\n", o_fn(s_fn(10)));

        // C5.E19: closure in while loop condition helper
        threshold : s32 = 50;
        above_fn := closure((x: s32) -> bool => x >= threshold);
        vals_e19 : [5]s32 = .[10, 30, 50, 70, 90];
        count_above : s32 = 0;
        idx_e19 : s64 = 0;
        while idx_e19 < 5 {
            if above_fn(vals_e19[idx_e19]) { count_above += 1; }
            idx_e19 += 1;
        }
        print("closure-while-cond: {}\n", count_above);

        // ---- Inferred closure parameter types ----

        // CI.1: inferred params from typed variable
        f_ci1 : Closure(s32, s32) -> s32 = closure((a, b) => a + b);
        a_ci1 : s32 = 3;
        b_ci1 : s32 = 4;
        print("closure-infer: {}\n", f_ci1(a_ci1, b_ci1));

        // CI.2: inferred params from function argument
        apply_ci :: (f: Closure(s32) -> s32, x: s32) -> s32 { return f(x); }
        k_ci : s32 = 10;
        v_ci : s32 = 5;
        print("closure-infer-arg: {}\n", apply_ci(closure((x) => x + k_ci), v_ci));

        // CI.3: inferred with block body
        h_ci : Closure(s32, s32) -> s32 = closure((a, b) { return a * b; });
        print("closure-infer-block: {}\n", h_ci(a_ci1, b_ci1));

        // CI.4: inferred with captures
        cap_ci : s32 = 100;
        f_ci4 : Closure(s32) -> s32 = closure((x) => x + cap_ci);
        print("closure-infer-cap: {}\n", f_ci4(v_ci));

        // CI.5: inferred in factory return
        mk_ci :: (n: s32) -> Closure(s32) -> s32 { return closure((x) => x * n); }
        f_ci5 := mk_ci(7);
        print("closure-infer-factory: {}\n", f_ci5(v_ci));

        // CI.6: inferred with higher-order (closure taking closure)
        compose_ci :: (f: Closure(s32) -> s32, g: Closure(s32) -> s32) -> Closure(s32) -> s32 {
            return closure((x: s32) -> s32 => f(g(x)));
        }
        one_ci : s32 = 1;
        two_ci : s32 = 2;
        c_ci := compose_ci(closure((x) => x + one_ci), closure((x) => x * two_ci));
        print("closure-infer-compose: {}\n", c_ci(v_ci));

        // CI.7: inferred void return
        msg_ci := "infer-void";
        cb_ci : Closure(s32) -> void = closure((x) { print("closure-{}: {}\n", msg_ci, x); });
        cb_ci(42);
    }

    // ========================================================
    // PROTOCOLS (Phase 1: static dispatch)
    // ========================================================
    print("=== Protocols ===\n");

    // P1.1: Basic protocol + impl, direct call on concrete type
    {
        sc := SimpleCounter.{ val = 0 };
        sc.inc();
        sc.inc();
        sc.inc();
        print("P1.1: {}\n", sc.get());
    }

    // P1.2: impl in separate scope (retroactive conformance)
    {
        p := Point.{ x = 10, y = 20 };
        print("P1.2: {}\n", p.sum());
    }

    // P2.1: #inline protocol — xx conversion + dynamic dispatch
    {
        acc := Accumulator.{ total = 0 };
        a : Adder = xx @acc;
        a.add(10);
        a.add(20);
        a.add(12);
        print("P2.1: {}\n", a.value());
    }

    // P2.2: pass protocol value to function
    {
        use_adder :: (a: Adder, n: s32) -> s32 {
            a.add(n);
            a.value();
        }
        acc := Accumulator.{ total = 100 };
        result := use_adder(xx @acc, 50);
        print("P2.2: {}\n", result);
    }

    // P2.3: different impls through same protocol type
    {
        acc := Accumulator.{ total = 0 };
        dbl := Doubler.{ val = 0 };
        a1 : Adder = xx @acc;
        a2 : Adder = xx @dbl;
        a1.add(5);
        a2.add(5);
        print("P2.3: {} {}\n", a1.value(), a2.value());
    }

    // P3.1: vtable-pointer protocol (default, no #inline)
    {
        sc := SimpleCounter.{ val = 0 };
        c : Counter = xx @sc;
        c.inc();
        c.inc();
        c.inc();
        c.inc();
        c.inc();
        print("P3.1: {}\n", c.get());
    }

    // P3.2: vtable protocol passed to function
    {
        use_counter :: (c: Counter) -> s32 {
            c.inc();
            c.inc();
            c.get();
        }
        sc := SimpleCounter.{ val = 10 };
        result := use_counter(xx @sc);
        print("P3.2: {}\n", result);
    }

    // P4.1: default method calls required method (static dispatch)
    {
        pr := Printer.{ count = 0 };
        pr.say_twice("hi ");
        print("\nP4.1: {}\n", pr.count);
    }

    // P4.2: default method via dynamic dispatch (vtable)
    {
        pr := Printer.{ count = 0 };
        r : Repeater = xx @pr;
        r.say_twice("yo ");
        print("\nP4.2: {}\n", pr.count);
    }

    // P4.3: chained default→default calls via vtable
    {
        ci := ChainImpl.{ val = 0 };
        ch : Chained = xx @ci;
        // double_wrap calls wrap twice, wrap calls base once each
        // base("hi") returns 2 (len), wrap adds 1 → 3, double_wrap = 3 + 3 = 6
        result := ch.double_wrap("hi");
        // base was called 2 times (once per wrap call)
        print("P4.3: {} {}\n", result, ci.val);
    }

    // P5.1: Self type in protocol — static dispatch
    {
        p1 := Point.{ x = 1, y = 2 };
        p2 := Point.{ x = 1, y = 2 };
        p3 := Point.{ x = 3, y = 4 };
        print("P5.1: {} {}\n", p1.eq(p2), p1.eq(p3));
    }

    // P5.2: Self in return position
    {
        p := Point.{ x = 10, y = 20 };
        p2 := p.clone();
        print("P5.2: {} {}\n", p2.x, p2.y);
    }

    // P5.5: impl for primitive type
    {
        x := 42;
        y := 42;
        z := 99;
        r1 := x.eq(y);
        r2 := x.eq(z);
        print("P5.5: {} {}\n", r1, r2);
    }

    // P5.3: Self with dynamic dispatch (erased to *void)
    {
        p1 := Point.{ x = 1, y = 2 };
        p2 := Point.{ x = 1, y = 2 };
        p3 := Point.{ x = 3, y = 4 };
        e : Eq = xx p1;
        print("P5.3: {} {}\n", e.eq(p2), e.eq(p3));
    }

    // P6.1: Single constraint — constrained generic function
    {
        p1 := Point.{ x = 1, y = 2 };
        p2 := Point.{ x = 1, y = 2 };
        p3 := Point.{ x = 3, y = 4 };
        print("P6.1: {} {}\n", are_equal(p1, p2), are_equal(p1, p3));
    }

    // P6.2: Constraint with primitive type
    {
        print("P6.2: {} {}\n", are_equal(42, 42), are_equal(42, 99));
    }

    // P6.3: Multiple constraints
    {
        p1 := Point.{ x = 1, y = 2 };
        p2 := Point.{ x = 1, y = 2 };
        p3 := Point.{ x = 3, y = 4 };
        print("P6.3: {} {}\n", eq_and_hash(p1, p2), eq_and_hash(p1, p3));
    }

    // P6.4: inline constraint syntax ($T/Protocol)
    {
        // sum_of_inline uses $T/Summable inline (not $T: Type/Summable)
        p1 := Point.{ x = 10, y = 20 };
        p2 := Point.{ x = 3, y = 7 };
        print("P6.4: {}\n", sum_of_inline(p1, p2));
    }

    // P6.5: Struct type param constraints ($T: Type/Summable)
    {
        box := SumBox(Point).{ val = Point.{ x = 5, y = 15 } };
        print("P6.5: {}\n", box.val.sum());
    }

    // P7.1: impl for generic struct
    {
        p := Pair(s32).{ a = 10, b = 20 };
        print("P7.1: {}\n", p.sum());
    }

    // P7.2: generic struct impl with different type arg
    {
        p1 := Pair(s32).{ a = 3, b = 7 };
        p2 := Pair(s64).{ a = 100, b = 200 };
        print("P7.2: {} {}\n", p1.sum(), p2.sum());
    }

    // P2.4: xx in function return position (tested in standalone test_return.sx)
    // Covered by: make_adder :: (acc: *Accumulator) -> Adder { xx acc; }

    // P2.6: protocol values in arrays
    {
        acc := Accumulator.{ total = 0 };
        dbl := Doubler.{ val = 0 };
        adders : [2]Adder = .[xx @acc, xx @dbl];
        i := 0;
        while i < 2 {
            adders[i].add(5);
            i += 1;
        }
        print("P2.6: {} {}\n", acc.total, dbl.val);
    }

    // P2.7: xx on inline struct literal (no intermediate variable)
    {
        use_adder :: (a: Adder) -> s32 { a.add(10); a.value(); }
        result := use_adder(xx Accumulator.{ total = 5 });
        print("P2.7: {}\n", result);
    }

    // P3.3: xx on inline struct literal with vtable protocol
    {
        use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); }
        result := use_counter(xx SimpleCounter.{ val = 100 });
        print("P3.3: {}\n", result);
    }

    // --- Auto type erasure (AE) ---
    print("=== Auto Type Erasure ===\n");

    // AE1: function argument — concrete passed where protocol expected (no xx)
    {
        use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); }
        sc := SimpleCounter.{ val = 10 };
        result := use_counter(sc);
        print("AE1: {}\n", result);
    }

    // AE2: variable assignment — concrete to protocol variable (no xx)
    {
        acc := Accumulator.{ total = 0 };
        a: Adder = acc;
        a.add(5);
        a.add(3);
        print("AE2: {}\n", a.value());
    }

    // AE3: struct literal passed directly (no xx)
    {
        use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); }
        result := use_counter(SimpleCounter.{ val = 100 });
        print("AE3: {}\n", result);
    }

    // AE4: explicit xx still works (not broken)
    {
        use_counter :: (c: Counter) -> s32 { c.inc(); c.get(); }
        result := use_counter(xx SimpleCounter.{ val = 50 });
        print("AE4: {}\n", result);
    }

    // AE5: pointer auto-erasure — *ConcreteType to protocol
    {
        use_adder :: (a: Adder) { a.add(10); }
        acc := Accumulator.{ total = 5 };
        p := @acc;
        use_adder(p);
        print("AE5: {}\n", acc.total);
    }

    // --- Struct Constants ---
    print("=== Struct Constants ===\n");
    {
        print("gravity: {}\n", Phys.GRAVITY);                   // gravity: 9.810000
        print("max speed: {}\n", Phys.MAX_SPEED);               // max speed: 100
        p := Phys.{ x = 0.0, y = Phys.GRAVITY };
        print("p.y: {}\n", p.y);                                // p.y: 9.810000
    }

    // --- Init Blocks (IB) ---
    print("=== Init Blocks ===\n");

    // IB1: basic init block with struct methods
    {
        b := Builder.{ total = 0, count = 0 } {
            self.add(10);
            self.add(20);
            self.add(30);
        };
        print("IB1: {} {}\n", b.total, b.count);
    }

    // IB2: nested init blocks (self shadows correctly)
    {
        b1 := Builder.{ total = 0, count = 0 } {
            self.add(100);
            b2 := Builder.{ total = 0, count = 0 } {
                self.add(42);
            };
            self.add(b2.total);
        };
        print("IB2: {} {}\n", b1.total, b1.count);
    }

    // IB3: empty init block
    {
        b := Builder.{ total = 5, count = 1 } {};
        print("IB3: {} {}\n", b.total, b.count);
    }

    // IB4: conditional inside init block
    {
        add_extra := true;
        b := Builder.{ total = 0, count = 0 } {
            self.add(10);
            if add_extra {
                self.add(90);
            }
        };
        print("IB4: {}\n", b.total);
    }

    // IB5: init block + auto type erasure combined
    {
        use_counter :: (c: Counter) -> s32 { c.inc(); c.inc(); c.get(); }
        result := use_counter(SimpleCounter.{ val = 0 } {
            self.val = 50;
        });
        print("IB5: {}\n", result);
    }

    // ============================================================
    // SECTION: Struct static method shorthand (.method(args) syntax)
    // ============================================================
    print("--- struct static method shorthand ---\n");

    // SM1: Basic shorthand — .create(args) resolves to Dims.create(args)
    {
        Dims :: struct {
            w: f32;
            h: f32;

            create :: (w: f32, h: f32) -> Dims {
                Dims.{ w = w, h = h };
            }

            square :: (size: f32) -> Dims {
                Dims.{ w = size, h = size };
            }
        }
        use_dims :: (d: Dims) { print("SM1: {} {}\n", d.w, d.h); }
        use_dims(.create(16.0, 8.0));
        use_dims(.square(5.0));
    }

    // SM2: Shorthand in variable declaration with explicit type
    {
        Pair :: struct {
            a: s64;
            b: s64;

            make :: (a: s64, b: s64) -> Pair {
                Pair.{ a = a, b = b };
            }
        }
        p : Pair = .make(10, 20);
        print("SM2: {} {}\n", p.a, p.b);
    }

    // ============================================================
    // OPTIONAL IF-ELSE COERCION
    // ============================================================
    {
        print("--- optional if-else coercion ---\n");
        OptF :: struct { width: ?f32; }
        x :f32: 10.0;

        // null in then branch
        f1 := OptF.{ width = if true then null else x };
        print("opt-if1: {}\n", f1.width ?? 99.0);

        // value in then branch, null in else
        f2 := OptF.{ width = if true then x else null };
        print("opt-if2: {}\n", f2.width ?? 99.0);

        // both branches are values
        f3 := OptF.{ width = if false then 5.0 else x };
        print("opt-if3: {}\n", f3.width ?? 99.0);

        // standalone optional variable
        val: ?f32 = if true then null else 42.0;
        print("opt-if4: {}\n", val ?? 0.0);

        val2: ?f32 = if false then null else 42.0;
        print("opt-if5: {}\n", val2 ?? 0.0);
    }

    // --- usize / isize ---
    {
        a : usize = 42;
        b : isize = 0 - 7;
        print("usize: {}\n", a);
        print("isize: {}\n", b);

        // arithmetic
        c : usize = a + 8;
        print("usize+8: {}\n", c);

        // coercion from s32
        x : s32 = 10;
        y : usize = xx x;
        print("s32->usize: {}\n", y);

        // coercion to s64
        z : s64 = xx a;
        print("usize->s64: {}\n", z);
    }

    // --- inline if (compile-time conditionals) ---
    print("=== inline if ===\n");
    {
        // POINTER_SIZE is 8 on desktop (64-bit)
        inline if POINTER_SIZE == 8 {
            print("64-bit\n");
        } else {
            print("32-bit\n");
        }

        // OS enum comparison
        inline if OS == .wasm {
            print("wasm\n");
        } else {
            print("not wasm\n");
        }

        // != comparison
        inline if OS != .unknown {
            print("known os\n");
        } else {
            print("unknown os\n");
        }

        // nested inline if
        inline if POINTER_SIZE != 4 {
            inline if OS != .wasm {
                print("desktop 64-bit\n");
            } else {
                print("wasm 64-bit??\n");
            }
        }

        // POINTER_SIZE in regular (non-inline) if expression
        ps := if POINTER_SIZE == 8 then "8" else "4";
        print("pointer size via if: {}\n", ps);
    }

    // ── Trailing commas ──────────────────────────────────────────
    print("=== Trailing Commas ===\n");
    {
        // Struct literal with trailing comma
        Vec4 :: struct { x: f64; y: f64; z: f64; w: f64; }
        v := Vec4.{
            x = 1.0,
            y = 2.0,
            z = 3.0,
            w = 4.0,
        };
        assert(v.x == 1.0);
        assert(v.w == 4.0);

        // Function call with trailing comma
        add :: (a: s64, b: s64) -> s64 { return a + b; }
        r := add(10, 20,);
        assert(r == 30);

        // Array literal with trailing comma
        arr := s64.[1, 2, 3,];
        assert(arr[2] == 3);

        print("trailing commas ok\n");
    }

    print("=== DONE ===\n");
}
