// Dedicated protocol test suite // Tests: declaration, impl, inline/vtable dispatch, default methods, // Self type, generic constraints, generic struct impls, xx on literals #import "modules/std.sx"; Point :: struct { x, y: s32; } // --- P1: vtable protocol (default layout) --- Counter :: protocol { inc :: (); get :: () -> s32; } SimpleCounter :: struct { val: s32; } impl Counter for SimpleCounter { inc :: (self: *SimpleCounter) { self.val += 1; } get :: (self: *SimpleCounter) -> s32 { self.val; } } // --- P2: #inline protocol --- 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; } } // --- P3: Summable (for generic constraint tests) --- Summable :: protocol { sum :: () -> s32; } impl Summable for Point { sum :: (self: *Point) -> s32 { self.x + self.y; } } // --- P4: 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); } } // 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; } } // --- P5: 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; } } // --- P6: 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); } sum_of_inline :: (a: $T/Summable, b: T) -> s32 { a.sum() + b.sum(); } // --- P7: 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; } } SumBox :: struct ($T: Type/Summable) { val: T; } // ============================================================ main :: () { // === P1: static dispatch on concrete types === // P1.1: basic protocol + impl { sc := SimpleCounter.{ val = 0 }; sc.inc(); sc.inc(); sc.inc(); print("P1.1: {}\n", sc.get()); } // P1.2: retroactive conformance (impl for existing type) { p := Point.{ x = 10, y = 20 }; print("P1.2: {}\n", p.sum()); } // === P2: #inline protocol — dynamic dispatch === // P2.1: xx conversion + method 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 inline protocol 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()); } // 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: vtable protocol (default, no #inline) === // P3.1: xx + vtable dispatch { 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); } // 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); } // === P4: default methods === // P4.1: default method via 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; result := ch.double_wrap("hi"); print("P4.3: {} {}\n", result, ci.val); } // === P5: Self type === // P5.1: Self in parameter position (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.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)); } // P5.5: impl for primitive type { x := 42; y := 42; z := 99; print("P5.5: {} {}\n", x.eq(y), x.eq(z)); } // === P6: generic constraints === // P6.1: single constraint { 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) { 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 { box := SumBox(Point).{ val = Point.{ x = 5, y = 15 } }; print("P6.5: {}\n", box.val.sum()); } // === P7: generic struct impls === // P7.1: impl for generic struct { p := Pair(s32).{ a = 10, b = 20 }; print("P7.1: {}\n", p.sum()); } // P7.2: different type args { p1 := Pair(s32).{ a = 3, b = 7 }; p2 := Pair(s64).{ a = 100, b = 200 }; print("P7.2: {} {}\n", p1.sum(), p2.sum()); } print("=== DONE ===\n"); }