// str_abi_test — runtime contract for the str->24B {ptr,len,cap} 3-reg ABI // (Phase 3, str IS []u8), migrated from test/wcc/928_str_abi_run.c. byte-id // proves the two stages agree, NOT that the emitted code is correct (a shared // miscompile passes byte-id silently); these @test fns pin the *runtime* // contract — T1 (`ww test`) runs the asserts, T2 (test-lang-byteid) keeps // cs==ww. Covers the ABI dimensions that exercise the cap word and the AX/BX/CX // value / AX:DX:CX:R8 tagged+tuple register layout: str literal (cap=len), str // arg, str return, str struct field, the (i64,str)/(str,i64) tuple shapes, // deref-store `*p=s`, []str index write+read, the s[i] u8-stride byte read, and // str widened into a tagged-union variant. package str_abi_test; fn slen(s: str) i32 = { return s.len: i32; }; fn greet() str = { return "hello world"; }; type box = struct { s: str, n: i32 }; fn pairis() (i64, str) = { return (42i64, "hello"); }; fn pairsi() (str, i64) = { return ("hi", 7i64); }; fn setit(p: *str, v: str) void = { *p = v; }; type sv = (str | i64); fn wrapsv(s: str) sv = { return s; }; @test fn literal_len_cap() void = { // Literal: cap == len for a static literal (no spare storage); .cap on a // LOCAL str reads back the new third word. let s: str = "hello"; assert(s.len: i32 == 5); assert(s.cap: i32 == 5); }; @test fn arg_len() void = { // str passed as a 3-word arg (ptr,len,cap), len read in the callee; a // let-bound str and a bare literal arg. let s: str = "hello"; assert(slen(s) == 5); assert(slen("hi") == 2); }; @test fn return_str() void = { // callee returns a str in AX/BX/CX (no AX:DX shuffle — exactly like a // slice now). let g: str = greet(); assert(g.len: i32 == 11); }; @test fn struct_field_store_load() void = { // store a str into a 3-word field, read .len and .cap back (field-store // routes the base through DX to dodge CX=cap; the cap word is stored, so // b.s.cap == len). let b: box; b.s = "abcd"; b.n = 7i32; assert(b.s.len: i32 == 4); assert(b.n == 7); assert(b.s.cap: i32 == 4); }; @test fn tuple_int_str() void = { // (i64, str) return: AX=scalar, DX=ptr, CX=len, R8=cap; 32B receive slot. let n, s = pairis(); assert(n: i32 == 42); assert(s.len: i32 == 5); }; @test fn tuple_str_int() void = { // (str, i64) return: reversed order, registers keyed by element type not // position. let s, n = pairsi(); assert(s.len: i32 == 2); assert(n: i32 == 7); }; @test fn deref_store() void = { // `*p = s` writes all three words through the pointer (cap stashed across // the pointer eval). let s: str = "hello"; let d: str; setit(&d, s); assert(d.len: i32 == 5); }; @test fn index_write_read() void = { // []str index write + read: the str-element store pushes cap/len and // writes 3 words; the read loads them back. let xs: [2]str; xs[0] = "hi"; xs[1] = "abc"; assert(xs[0].len: i32 == 2); assert(xs[1].len: i32 == 3); }; @test fn str_index_read() void = { // `s[i]` strides by the u8 element size (1), routed through the type table // post-collapse; guards the N_INDEX str-element stride against a // slice-width (24B) miscompute. let s: str = "hello"; assert(s[0]: i32 == 104); assert(s[1]: i32 == 101); assert(s[4]: i32 == 111); }; @test fn tagged_union_str_store() void = { // str widened into a tagged-union variant: the payload store folds onto // the common slice arm (3-word ptr/len/cap + tag). Literal, str-variable, // a str returned from a fn into (str | i64), plus the i64 arm so the // variant-tag selection is checked both ways. let x: sv = "hello"; match (x) { case let s: str => { assert(s.len: i32 == 5); }; case let n: i64 => { assert(false); }; }; let a: str = "world"; let y: sv = a; match (y) { case let s: str => { assert(s.len: i32 == 5); }; case let n: i64 => { assert(false); }; }; let z: sv = wrapsv("abcd"); match (z) { case let s: str => { assert(s.len: i32 == 4); }; case let n: i64 => { assert(false); }; }; let w: sv = 42i64; match (w) { case let s: str => { assert(false); }; case let n: i64 => { assert(n: i32 == 42); }; }; };