diff --git a/Makefile b/Makefile index d7cdd334..d7eacfc2 100644 --- a/Makefile +++ b/Makefile @@ -556,9 +556,12 @@ DATABYTEID_EXPECTED_MIN = 915 # Known cs!=ww divergences (loud over blind, the 989_lib_byteid DIVERGE # discipline): each entry must still build on both stages AND still differ. # When a compiler fix lands the entry fails demanding graduation out of -# this list rather than silently widening coverage. Currently empty: the -# 2026-08 drain closed all eight original entries. -DATABYTEID_DIVERGED = +# this list rather than silently widening coverage. +# r700_strings_byteindex: latent, exposed by the 700_e2e migration — +# wwstage spills a wwi-decl'd tagged call-result arg through a 16B +# scratch pair where cstage PUSHQes AX/DX (frame 64 vs 80); runtime- +# equivalent, sibling of the closed #211 name-keyed family. +DATABYTEID_DIVERGED = r700_strings_byteindex $(if $(DATABYTEID_FILES),,$(error test-byteid: empty data corpus)) test-data-byteid: $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww @work=$$(mktemp -d "$(CURDIR)/$(DATABYTEID_DIR).XXXXXX") || exit 1; \ diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index 60570d0d..440f3e30 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1495; +def corpuscount: i32 = 1631; def errorcount: i32 = 338; def compilecount: i32 = 17; def runcount: i32 = 198; -def runexitcount: i32 = 942; -def nativecount: i32 = 2990; -def corpushash: str = "b8ccfce9c8ca9b47c9f84f446ae6cf412d1964028b2f643dc386318e5384bce1"; +def runexitcount: i32 = 1078; +def nativecount: i32 = 3262; +def corpushash: str = "f1186d55d4f4a447de61b1246f8296c9f5996b406de36da0e5eb277fd2352e52"; type directive = enum i32 { ERROR = 0, diff --git a/test/wcc/700_e2e.c b/test/wcc/700_e2e.c deleted file mode 100644 index 938eff91..00000000 --- a/test/wcc/700_e2e.c +++ /dev/null @@ -1,1887 +0,0 @@ -/* - * 700_e2e — end-to-end. Drive `ww build` on a small source program, - * run the produced binary, check the exit status. This is the real - * user-facing happy path. - */ -#include -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -struct row { const char *src; int want_exit; }; - -static const struct row rows[] = { - { "fn main() i32 = { return 42; };", 42 }, - { "fn add(a: i32, b: i32) i32 = { return a + b; };\n" - "fn main() i32 = { return add(7, 35); };", 42 }, - { "fn main() i32 = {\n" - " let i: i32 = 0;\n" - " let s: i32 = 0;\n" - " for (i < 10) { s += i; i += 1; };\n" - " return s;\n" - "};", 45 }, - { "fn main() i32 = {\n" - " let x: i32 = 100;\n" - " if (x > 50) { return 1; };\n" - " return 0;\n" - "};", 1 }, - { "fn main() i32 = {\n" - " let a: i32 = 6;\n" - " let b: i32 = 7;\n" - " return a * b;\n" - "};", 42 }, - /* multi-return tuple, divmod */ - { "fn divmod(a: i64, b: i64) (i64, i64) = { return a / b, a % b; };\n" - "fn main() i32 = {\n" - " let q, r = divmod(17, 5);\n" - " return (q + r): i32;\n" - "};", 5 }, - /* fixed array, byte-wise read/write */ - { "fn main() i32 = {\n" - " let buf: [4]u8;\n" - " buf[0] = 1: u8;\n" - " buf[1] = 2: u8;\n" - " buf[2] = 3: u8;\n" - " buf[3] = 4: u8;\n" - " let sum: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 4) { sum += buf[i]: i32; i += 1; };\n" - " return sum;\n" - "};", 10 }, - /* float: arg, arith, literal, cast back to int */ - { "fn area(r: f64) f64 = { return 3.14 * r * r; };\n" - "fn main() i32 = { let a: f64 = area(5.0); return a: i32; };", 78 }, - /* float comparison: must emit UCOMISD + JA (not CMPQ + JG) */ - { "fn main() i32 = {\n" - " let a: f64 = 1.5;\n" - " let b: f64 = 2.5;\n" - " if (a < b) { if (b > a) { return 7; }; };\n" - " return 0;\n" - "};", 7 }, - /* float ==/!= via UCOMISD */ - { "fn main() i32 = {\n" - " let a: f64 = 3.14;\n" - " let b: f64 = 3.14;\n" - " if (a == b) { return 11; };\n" - " return 0;\n" - "};", 11 }, - /* function pointer: take address of a named fn, call indirectly */ - { "fn add(a: i32, b: i32) i32 = { return a + b; };\n" - "fn main() i32 = {\n" - " let fp: fn(a: i32, b: i32) i32 = add;\n" - " return fp(20, 22);\n" - "};", 42 }, - /* string literal via syscall — exit code = bytes written */ - { "@symbol(\"rt_syscall\") fn rt_syscall(num: i64, a: i64, b: i64, c: i64) i64;\n" - "fn print(s: str) i64 = { return rt_syscall(1, 1, s.ptr: i64, s.len: i64); };\n" - "fn main() i32 = { return print(\"hello, world\\n\"): i32; };", 13 }, - /* 9 args — 3 spill to the stack */ - { "fn s9(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32, i: i32) i32 = {\n" - " return a + b + c + d + e + f + g + h + i;\n" - "};\n" - "fn main() i32 = { return s9(1,2,3,4,5,6,7,8,9); };", 45 }, - /* defer: LIFO at function return */ - { "@symbol(\"rt_syscall\") fn rt_syscall(num: i64, a: i64, b: i64, c: i64) i64;\n" - "fn out(c: i32) void = { rt_syscall(1, 1, (&c): i64, 1); };\n" - "fn main() i32 = {\n" - " let c1: i32 = 0;\n" - " let c2: i32 = 0;\n" - " c1 = 65;\n" /* 'A' */ - " c2 = 66;\n" /* 'B' */ - " defer out(c1);\n" - " defer out(c2);\n" - " return 0;\n" - "};", 0 }, - /* struct-by-value: 16B all-int passed by value */ - { "type pair = struct { a: i64, b: i64 };\n" - "fn sum(p: pair) i64 = { return p.a + p.b; };\n" - "fn main() i32 = {\n" - " let p: pair = pair { a = 10, b = 32 };\n" - " return sum(p): i32;\n" - "};", 42 }, - /* f32 cast + arithmetic */ - { "fn add32(a: f32, b: f32) f32 = { return a + b; };\n" - "fn main() i32 = {\n" - " let r: f32 = add32(2.5: f32, 7.5: f32);\n" - " return r: i32;\n" - "};", 10 }, - /* slice from array: build header, iterate via index/len */ - { "fn main() i32 = {\n" - " let arr: [4]u8;\n" - " arr[0] = 10: u8; arr[1] = 20: u8;\n" - " arr[2] = 30: u8; arr[3] = 99: u8;\n" - " let s: []u8 = arr[0:3];\n" - " let sum: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < s.len) { sum += s[i]: i32; i += 1; };\n" - " return sum;\n" - "};", 60 }, - /* module imports: use os and call os.write; exit code = bytes */ - { "import os;\n" - "fn main() i32 = { return os.write(1, \"ok\\n\".ptr, 3): i32; };", 3 }, - /* typed integer literals */ - { "fn main() i32 = {\n" - " let buf: [4]u8;\n" - " buf[0] = 65u8; buf[1] = 66u8; buf[2] = 67u8; buf[3] = 0u8;\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 3) { s += buf[i]: i32; i += 1; };\n" - " return s;\n" - "};", 198 }, - /* full stdlib stack: use os + strconv, str return, write - * the formatted number to stdout. exit code = number length. */ - { "import os;\n" - "import strconv;\n" - "fn main() i32 = {\n" - " let s: str = strconv.i64tos(12345, strconv.base.DEC);\n" - " os.write(1, s.ptr, s.len: u64);\n" - " os.write(1, \"\\n\".ptr, 1u64);\n" - " return s.len;\n" - "};", 5 }, - /* alloc + free via mmap-backed runtime — write through allocated - * memory and free it. exit = 0 if the allocation succeeded. */ - { "import os;\n" - "import rt;\n" - "fn main() i32 = {\n" - " let p: *void = rt.malloc(4096u64);\n" - " if (p == nil) { return 1; };\n" - " let bp: *u8 = p: *u8;\n" - " bp[0] = 65u8;\n" - " os.write(1, bp, 1u64);\n" - " os.free(p, 4096u64);\n" - " return 0;\n" - "};", 0 }, - /* argv: kernel passes argc in DI, argv in SI. */ - { "fn main(argc: i32, argv: **u8) i32 = { return argc; };", 1 }, - /* i64 array: scaled indexing (elem size 8) */ - { "fn main() i32 = {\n" - " let arr: [4]i64;\n" - " arr[0] = 10; arr[1] = 20; arr[2] = 30; arr[3] = 40;\n" - " let sum: i64 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 4) { sum += arr[i]; i += 1; };\n" - " return sum: i32;\n" - "};", 100 }, - /* break out of an infinite loop early */ - { "fn main() i32 = {\n" - " let i: i32 = 0;\n" - " for () {\n" - " i += 1;\n" - " if (i == 7) { break; };\n" - " };\n" - " return i;\n" - "};", 7 }, - /* switch with multi-expr cases + default */ - { "fn classify(x: i32) i32 = {\n" - " switch (x) {\n" - " case 1, 2, 3: return 10;\n" - " case 10: return 99;\n" - " case: return 50;\n" - " };\n" - " return -1;\n" - "};\n" - "fn main() i32 = {\n" - " return classify(2) + classify(10) + classify(99);\n" - "};", 159 }, /* 10+99+50=159 */ - /* fmt module: stdlib formatter for strings; ints compose - * via strconv.i64tos. */ - { "import fmt;\n" - "import strconv;\n" - "fn main() i32 = {\n" - " fmt.println(\"ww\");\n" - " fmt.println(strconv.i64tos(42, strconv.base.DEC));\n" - " fmt.println(strconv.i64tos(-7, strconv.base.DEC));\n" - " return 0;\n" - "};", 0 }, - /* struct with i32 fields: MOVL/MOVSXD avoids clobbering neighbors */ - { "type point = struct { x: i32, y: i32 };\n" - "fn distsq(p: point) i32 = { return p.x * p.x + p.y * p.y; };\n" - "fn main() i32 = {\n" - " let p: point = point { x = 3, y = 4 };\n" - " return distsq(p);\n" - "};", 25 }, - /* str equality via == and != */ - { "fn main() i32 = {\n" - " let a: str = \"hello\";\n" - " let b: str = \"hello\";\n" - " let c: str = \"world\";\n" - " let n: i32 = 0;\n" - " if (a == b) { n += 10; };\n" - " if (a != c) { n += 20; };\n" - " return n;\n" - "};", 30 }, - /* CLAUDE.md's move pattern: ptr-to-struct compound field write */ - { "type point = struct { x: i32, y: i32 };\n" - "fn move(p: *point, dx: i32, dy: i32) void = {\n" - " p.x += dx; p.y += dy;\n" - "};\n" - "fn main() i32 = {\n" - " let pt: point = point { x = 0, y = 0 };\n" - " move(&pt, 3, 4);\n" - " return pt.x + pt.y;\n" - "};", 7 }, - /* vtable polymorphism: struct of fn pointers, indirect call */ - { "type ops = struct { add: fn(a: i32, b: i32) i32 };\n" - "fn plus(a: i32, b: i32) i32 = { return a + b; };\n" - "fn main() i32 = {\n" - " let v: ops = ops { add = plus };\n" - " return v.add(20, 22);\n" - "};", 42 }, - /* compound bitwise/shift assigns */ - { "fn main() i32 = {\n" - " let x: i32 = 100;\n" - " x &= 0x3f; x |= 0x80; x ^= 0xc4;\n" - " x *= 2; x <<= 1; x >>= 2;\n" - " return x;\n" - "};", 96 }, - /* Hare-style builtins: append(s, v) and len(s). The compiler - * lowers append to a CALL into libwwrt.a's appendu8 / appendi64 - * by element size — no `use rt;` or `use slices;` required. */ - { "import os;\n" - "fn main() i32 = {\n" - " let s: []u8;\n" - " s.ptr = nil; s.len = 0; s.cap = 0;\n" - " append(s, 88u8); append(s, 89u8); append(s, 90u8);\n" - " os.write(1, s.ptr, len(s): u64);\n" - " os.write(1, \"\\n\".ptr, 1u64);\n" - " return len(s);\n" - "};", 3 }, - /* str-returning function: 16-byte return via AX:DX (SysV). The - * caller's str slot is filled from those two regs. */ - { "import strings;\n" - "import fmt;\n" - "fn main() i32 = {\n" - " let r: str = strings.concat(\"hello, \", \"world\");\n" - " fmt.println(r);\n" - " return r.len;\n" - "};", 12 }, - /* variadic append + static qualifier (Hare idiom) */ - { "import os;\n" - "fn main() i32 = {\n" - " let s: []u8;\n" - " s.ptr = nil; s.len = 0; s.cap = 0;\n" - " static append(s, 72u8, 105u8, 33u8, 10u8);\n" - " os.write(1, s.ptr, len(s): u64);\n" - " return len(s);\n" - "};", 4 }, - /* alloc() builtin: heap-allocate a struct, init from struct-lit. - * `package main;` is required so the bare-alloc-builtin gate - * (task #23) sees c->cur_mod=="main" and doesn't suppress the - * builtin via the inherited os.alloc decl. Task #30 graduated - * the builtin to `(*T | nomem)`; the `!` aborts on OOM. */ - { "package main;\n" - "import rt;\n" - "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let p: *point = alloc(point { x = 3, y = 4 })!;\n" - " return p.x * p.x + p.y * p.y;\n" - "};", 25 }, - /* Hare-style range loop: for (let x .. slice) iterates elements */ - { "import os;\n" - "fn main() i32 = {\n" - " let s: []u8;\n" - " s.ptr = nil; s.len = 0; s.cap = 0;\n" - " append(s, 10u8, 20u8, 30u8, 40u8);\n" - " let total: i32 = 0;\n" - " for (let b .. s) { total += b: i32; };\n" - " return total;\n" - "};", 100 }, - /* alloc([], n): fresh empty slice with cap n. `package main;` for - * the same reason as the value-form test above (task #23 gate). - * Task #30 graduated the slice form to `([]T | nomem)`; the `!` - * aborts on OOM. */ - { "package main;\n" - "import rt;\n" - "fn main() i32 = {\n" - " let s: []u8 = alloc([], 16)!;\n" - " append(s, 72u8, 105u8);\n" - " return s.cap;\n" - "};", 16 }, - /* #45: alloc([], n) now defers element type to the let-init LHS. - * `[]rune` is 4B-per-element; the cgen shortcut scales count by - * size(T). Returns s.cap = 8. */ - { "package main;\n" - "import rt;\n" - "fn main() i32 = {\n" - " let s: []rune = alloc([], 8)!;\n" - " return s.cap;\n" - "};", 8 }, - /* #45: same as above for `[]str` (16B-per-element). */ - { "package main;\n" - "import rt;\n" - "fn main() i32 = {\n" - " let s: []str = alloc([], 4)!;\n" - " return s.cap;\n" - "};", 4 }, - /* #45: `?` form. doit propagates nomem to its (i32 | nomem) - * return; the alloc-slice shortcut emits MOVQ $nomem_tag, AX + - * propret on null. doit returns 12 on success; main unwraps. */ - { "package main;\n" - "import rt;\n" - "fn doit() (i32 | nomem) = {\n" - " let s: []str = alloc([], 12)?;\n" - " return s.cap: i32;\n" - "};\n" - "fn main() i32 = {\n" - " return doit()!;\n" - "};", 12 }, - /* alloc-builtin shadow (task #23): a non-main package declares - * `fn alloc(n: i64) i64` and calls it bare. The same-module gate - * must suppress the builtin and dispatch to the user fn so the - * call returns n+100. Pre-gate this site lands in the typed-builtin - * path: arg is i64 → returns *i64 → init-type fails against the - * declared i64 (and would over-allocate against rt_malloc anyway). - * Inline multi-`package` mirrors driver-concatenated layout; the - * `import myos;` directive is silently skipped by locate_import - * (no external module by that name). */ - { "package myos;\n" - "fn alloc(n: i64) i64 = { return n + 100; };\n" - "fn run() i64 = { return alloc(7); };\n" - "package main;\n" - "import myos;\n" - "fn main() i32 = {\n" - " return myos.run(): i32;\n" - "};", 107 }, - /* variadic spread: append(dst, src...) iterates src */ - { "import os;\n" - "fn main() i32 = {\n" - " let src: []u8;\n" - " src.ptr = nil; src.len = 0; src.cap = 0;\n" - " append(src, 65u8, 66u8, 67u8);\n" - " let dst: []u8;\n" - " dst.ptr = nil; dst.len = 0; dst.cap = 0;\n" - " append(dst, src...);\n" - " os.write(1, dst.ptr, dst.len: u64);\n" - " os.write(1, \"\\n\".ptr, 1u64);\n" - " return dst.len;\n" - "};", 3 }, - /* Hare-style tuple destructure in let */ - { "fn divmod(a: i64, b: i64) (i64, i64) = { return a / b, a % b; };\n" - "fn main() i32 = {\n" - " let (q, r) = divmod(17, 5);\n" - " return (q + r): i32;\n" - "};", 5 }, - /* Hare-style tuple destructure in for-range */ - { "fn main() i32 = {\n" - " let buf: [4]i64;\n" - " buf[0] = 1; buf[1] = 10; buf[2] = 2; buf[3] = 20;\n" - " let s: [](i64, i64);\n" - " s.ptr = buf.ptr: *(i64, i64);\n" - " s.len = 2; s.cap = 2;\n" - " let total: i64 = 0;\n" - " for (let (k, v) .. s) { total += k + v; };\n" - " return total: i32;\n" - "};", 33 }, - /* Hare-style tuple positional access: t.0, t.1 */ - { "fn pair() (i64, i64) = { return 10, 32; };\n" - "fn main() i32 = {\n" - " let t: (i64, i64) = pair();\n" - " return (t.0 + t.1): i32;\n" - "};", 42 }, - /* Hare-style abort/assert + free() builtin. `package main;` for - * the alloc-builtin gate (task #23). Task #30 graduated the - * builtin to a fallible signature; the `!` aborts on OOM. */ - { "package main;\n" - "import os;\n" - "import rt;\n" - "type point = struct { x: i64, y: i64 };\n" - "fn main() i32 = {\n" - " let p: *point = alloc(point { x = 7, y = 35 })!;\n" - " let r: i64 = p.x + p.y;\n" - " free(p);\n" - " assert(r == 42, \"sum mismatch\\n\");\n" - " return r: i32;\n" - "};", 42 }, - /* Hare-style struct embedding: bare-name embed + anonymous - * nested struct, fields promoted to the outer scope. Both - * field-by-field assignment and flat struct-literal init must - * see promoted fields. */ - { "type point = struct { x: i32, y: i32 };\n" - "type vec = struct {\n" - " point,\n" - " struct { z: i32 },\n" - " w: i32,\n" - "};\n" - "fn main() i32 = {\n" - " let v: vec = vec { x = 1, y = 2, z = 3, w = 36 };\n" - " return v.x + v.y + v.z + v.w;\n" - "};", 42 }, - /* 3-field tuple destructure in for-range */ - { "fn main() i32 = {\n" - " let buf: [3]i64;\n" - " buf[0] = 5; buf[1] = 7; buf[2] = 30;\n" - " let s: [](i64, i64, i64);\n" - " s.ptr = buf.ptr: *(i64, i64, i64);\n" - " s.len = 1; s.cap = 1;\n" - " let total: i64 = 0;\n" - " for (let (a, b, c) .. s) { total += a + b + c; };\n" - " return total: i32;\n" - "};", 42 }, - /* Hare-style tagged union + match */ - { "fn parse(n: i64) (i64 | i32) = {\n" - " if (n < 0) { return 1: i32; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | i32) = parse(40);\n" - " let s: i64 = 0;\n" - " match (r) {\n" - " case let v: i64 => s = v;\n" - " case let e: i32 => s = -1;\n" - " };\n" - " return (s + 2): i32;\n" - "};", 42 }, - /* ? propagation up the stack */ - { "fn try1(n: i64) (i64 | i32) = {\n" - " if (n < 0) { return 99: i32; };\n" - " return n;\n" - "};\n" - "fn try2(n: i64) (i64 | i32) = {\n" - " let v: i64 = try1(n)?;\n" - " return v + 100;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | i32) = try2(-1);\n" - " let s: i64 = 0;\n" - " match (r) {\n" - " case let v: i64 => s = v;\n" - " case let e: i32 => s = e: i64;\n" - " };\n" - " return s: i32;\n" - "};", 99 }, - /* match cases written in reverse variant order — dispatch must - * use the variant tag, not the case position */ - { "fn parse(n: i64) (i64 | i32) = {\n" - " if (n < 0) { return 7: i32; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | i32) = parse(-1);\n" - " match (r) {\n" - " case let e: i32 => return e;\n" - " case let v: i64 => return (v + 1000): i32;\n" - " };\n" - " return 0;\n" - "};", 7 }, - /* let-init from a bare variant value: tag must be synthesised */ - { "fn main() i32 = {\n" - " let r: (i64 | i32) = 7: i32;\n" - " match (r) {\n" - " case let v: i64 => return 1;\n" - " case let e: i32 => return e;\n" - " };\n" - " return 0;\n" - "};", 7 }, - /* let-init from an untyped literal: variant inclusion must let - * the assignability check through, and the default variant wins */ - { "fn main() i32 = {\n" - " let r: (i64 | i32) = 5;\n" - " match (r) {\n" - " case let v: i64 => return v: i32;\n" - " case let e: i32 => return 99;\n" - " };\n" - " return 0;\n" - "};", 5 }, - /* assignment to a tagged-union local: same tag synthesis */ - { "fn main() i32 = {\n" - " let r: (i64 | i32) = 0;\n" - " r = 9: i32;\n" - " match (r) {\n" - " case let v: i64 => return 1;\n" - " case let e: i32 => return e;\n" - " };\n" - " return 0;\n" - "};", 9 }, - /* default arm `case =>` */ - { "fn parse(n: i64) (i64 | i32) = {\n" - " if (n < 0) { return 1: i32; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | i32) = parse(-1);\n" - " match (r) {\n" - " case let v: i64 => return 1;\n" - " case => return 7;\n" - " };\n" - " return 0;\n" - "};", 7 }, - /* `case T =>` without binding still dispatches by tag */ - { "fn parse(n: i64) (i64 | i32) = {\n" - " if (n < 0) { return 1: i32; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | i32) = parse(40);\n" - " match (r) {\n" - " case i32 => return 1;\n" - " case let v: i64 => return v: i32;\n" - " };\n" - " return 0;\n" - "};", 40 }, - /* named alias over `!(A | B)`: param spill must size to the - * flattened union (8B tag + 8B payload), not 8B-scalar. Pinned - * the cstage/wwstage divergence where wwstage's istaggedtype - * was alias-blind and the slot+8 read trailed into saved BP. */ - { "type invalid = !i32;\n" - "type overflow = !void;\n" - "type error = !(invalid | overflow);\n" - "fn errcode(e: error) i32 = {\n" - " match (e) {\n" - " case let v: invalid => return v: i32;\n" - " case let v: overflow => return 99;\n" - " };\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let e: error = 7: invalid;\n" - " return errcode(e);\n" - "};", 7 }, - /* str-typed variant payload: let-init with a string literal, - * match-binding loads ptr+len from the slot */ - { "fn main() i32 = {\n" - " let r: (i64 | str) = \"hello, world\";\n" - " match (r) {\n" - " case let n: i64 => return 1;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 12 }, - /* assigning a string into a tagged-union local */ - { "fn main() i32 = {\n" - " let r: (i64 | str) = 0;\n" - " r = \"abc\";\n" - " match (r) {\n" - " case let n: i64 => return 1;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* fn returning (T | str) — wide return ABI */ - { "fn parse(n: i64) (i64 | str) = {\n" - " if (n < 0) { return \"negative number\"; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | str) = parse(-1);\n" - " match (r) {\n" - " case let n: i64 => return 1;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 15 }, - /* ? propagating a str-typed error all the way up */ - { "fn try1(n: i64) (i64 | str) = {\n" - " if (n < 0) { return \"fail\"; };\n" - " return n;\n" - "};\n" - "fn try2(n: i64) (i64 | str) = {\n" - " let v: i64 = try1(n)?;\n" - " return v + 100;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | str) = try2(-1);\n" - " match (r) {\n" - " case let n: i64 => return n: i32;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 4 }, - /* ? with different success types but shared error: operand - * (i32 | str), enclosing (i64 | str). Success widens. */ - { "fn inner(b: bool) (i32 | str) = {\n" - " if (b) { return 7; };\n" - " return \"err\";\n" - "};\n" - "fn outer(b: bool) (i64 | str) = {\n" - " let v: i32 = inner(b)?;\n" - " return v: i64 + 100;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | str) = outer(false);\n" - " match (r) {\n" - " case let n: i64 => return n: i32;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* defer runs queued exprs in LIFO order, before the return - * expression is evaluated. Each call appends a decimal digit - * to acc via *&acc — return reads the post-defer state. */ - { "fn rec(p: *i32, c: i32) i32 = {\n" - " *p = *p * 10 + c;\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let acc: i32 = 0;\n" - " defer rec(&acc, 1);\n" - " defer rec(&acc, 2);\n" - " defer rec(&acc, 3);\n" - " return acc;\n" - "};", 65 }, /* 321 mod 256 */ - /* defer also fires on an implicit fall-through return (void fn). */ - { "fn rec(p: *i32, c: i32) i32 = {\n" - " *p = *p * 10 + c;\n" - " return 0;\n" - "};\n" - "fn run(p: *i32) void = {\n" - " defer rec(p, 7);\n" - " defer rec(p, 8);\n" - " // no explicit return — implicit fall-through path\n" - "};\n" - "fn main() i32 = {\n" - " let acc: i32 = 0;\n" - " run(&acc);\n" - " return acc;\n" - "};", 87 }, /* defers fire 8, 7 → 8 then 87 */ - /* yield from match-as-expression: each arm yields a value; - * the match itself is bound to a let. */ - { "fn pick(b: bool) (i32 | str) = {\n" - " if (b) { return 7; };\n" - " return \"abc\";\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i32 | str) = pick(true);\n" - " let v: i32 = match (r) {\n" - " case let n: i32 => yield n + 1;\n" - " case let s: str => yield s.len: i32 + 100;\n" - " };\n" - " return v;\n" - "};", 8 }, - { "fn pick(b: bool) (i32 | str) = {\n" - " if (b) { return 7; };\n" - " return \"abc\";\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i32 | str) = pick(false);\n" - " let v: i32 = match (r) {\n" - " case let n: i32 => yield n + 1;\n" - " case let s: str => yield s.len: i32 + 100;\n" - " };\n" - " return v;\n" - "};", 103 }, - /* Nullable pointer folding: `(*T | void)` is one 8-byte word - * where null = void variant. match/is/as/?/! all key off the - * pointer-vs-null discriminator instead of a separate tag. */ - { "fn lookup(p: *i32, b: bool) (*i32 | void) = {\n" - " if (b) { return p; };\n" - " return;\n" - "};\n" - "fn use_arg(r: (*i32 | void)) i32 = {\n" - " match (r) {\n" - " case let q: *i32 => return *q;\n" - " case void => return 99;\n" - " };\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let x: i32 = 42;\n" - " let ok: i32 = use_arg(lookup(&x, true));\n" - " let no: i32 = use_arg(lookup(&x, false));\n" - " if (ok != 42) { return 1; };\n" - " if (no != 99) { return 2; };\n" - " return 7;\n" - "};", 7 }, - /* Nullable with is/as: discriminator is ptr-vs-null. */ - { "fn lookup(p: *i32, b: bool) (*i32 | void) = {\n" - " if (b) { return p; };\n" - " return;\n" - "};\n" - "fn main() i32 = {\n" - " let x: i32 = 42;\n" - " let r1: (*i32 | void) = lookup(&x, true);\n" - " let r2: (*i32 | void) = lookup(&x, false);\n" - " let acc: i32 = 0;\n" - " if (r1 is *i32) { acc += 1; };\n" - " if (r2 is void) { acc += 2; };\n" - " let p: *i32 = r1 as *i32;\n" - " if (*p == 42) { acc += 4; };\n" - " return acc;\n" - "};", 7 }, - /* `!`-flagged error variants: success picked by absence of `!`, - * errors picked by presence. Tag remap still works across - * different variant orders between operand and enclosing fn. */ - { "type invalid = !i32;\n" - "type overflow = !void;\n" - "fn inner(n: i32) (invalid | i64 | overflow) = {\n" - " if (n == 0) { return 7: invalid; };\n" - " if (n < 0) { return void: overflow; };\n" - " return n: i64 + 1000;\n" - "};\n" - "fn outer(n: i32) (overflow | i64 | invalid) = {\n" - " let v: i64 = inner(n)?;\n" - " return v + 1;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (overflow | i64 | invalid) = outer(0);\n" - " match (r) {\n" - " case let v: i64 => return v: i32;\n" - " case let e: invalid => return e + 100;\n" - " case let e: overflow => return 999;\n" - " };\n" - " return 0;\n" - "};", 107 }, - /* ? with reversed error variant order: operand (i32 | str | bool), - * enclosing (i64 | bool | str). Tag remap maps str:1→2, bool:2→1. */ - { "fn inner(n: i32) (i32 | str | bool) = {\n" - " if (n == 0) { return \"z\"; };\n" - " if (n < 0) { return false; };\n" - " return n;\n" - "};\n" - "fn outer(n: i32) (i64 | bool | str) = {\n" - " let v: i32 = inner(n)?;\n" - " return v: i64 + 1000;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | bool | str) = outer(-1);\n" - " match (r) {\n" - " case let n: i64 => return n: i32;\n" - " case let b: bool => { if (!b) { return 7; }; return 8; };\n" - " case let s: str => return 9;\n" - " };\n" - " return 0;\n" - "};", 7 }, - /* ! success unwrap when the first variant is itself str. - * Uses ! (not ?) because main's return is i32, not tagged — - * ? would require error variants to be propagatable to the - * enclosing return. ! aborts on the error variant instead. */ - { "fn make() (str | i64) = {\n" - " return \"ok\";\n" - "};\n" - "fn main() i32 = {\n" - " let r: (str | i64) = make();\n" - " let v: str = r!;\n" - " return v.len: i32;\n" - "};", 2 }, - /* type error = str; named-alias variant works through the - * full happy/error path */ - { "type error = str;\n" - "fn read(n: i64) (i64 | error) = {\n" - " if (n < 0) { return \"eof\": error; };\n" - " return n + 1;\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i64 | error) = read(-1);\n" - " match (r) {\n" - " case let v: i64 => return v: i32;\n" - " case let e: error => return e.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* multi-pattern arm: `case T1 | T2 =>` matches either tag */ - { "fn pick(n: i64) (i64 | i32 | u32) = {\n" - " if (n < 0) { return 1: i32; };\n" - " if (n == 0) { return 2: u32; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r1: (i64 | i32 | u32) = pick(0);\n" - " let r2: (i64 | i32 | u32) = pick(-1);\n" - " let r3: (i64 | i32 | u32) = pick(7);\n" - " let acc: i32 = 0;\n" - " match (r1) {\n" - " case let v: i64 => acc += 100;\n" - " case i32 | u32 => acc += 1;\n" - " };\n" - " match (r2) {\n" - " case let v: i64 => acc += 100;\n" - " case i32 | u32 => acc += 10;\n" - " };\n" - " match (r3) {\n" - " case let v: i64 => acc += v: i32;\n" - " case i32 | u32 => acc += 100;\n" - " };\n" - " return acc;\n" - "};", 18 }, - /* Named-alias tagged union as fn arg + ≤16B variants */ - { "type result = (i64 | i32);\n" - "fn unwrap(r: result) i64 = {\n" - " match (r) {\n" - " case let v: i64 => return v;\n" - " case let e: i32 => return e: i64;\n" - " };\n" - " return -1;\n" - "};\n" - "fn main() i32 = {\n" - " let r1: result = 100;\n" - " let r2: result = 7: i32;\n" - " return (unwrap(r1) + unwrap(r2)): i32;\n" - "};", 107 }, - /* 24B tagged-union arg with str variant */ - { "type result = (i64 | str);\n" - "fn classify(r: result) i32 = {\n" - " match (r) {\n" - " case let v: i64 => return 1;\n" - " case let e: str => return e.len: i32;\n" - " };\n" - " return -1;\n" - "};\n" - "fn main() i32 = {\n" - " let r1: result = \"hello\";\n" - " let r2: result = 42;\n" - " return classify(r1) + classify(r2);\n" - "};", 6 }, - /* Tagged union as struct field — both literal init and assign, - * and match-on-field reads from the field's slot in place */ - { "type point = struct {\n" - " x: i32,\n" - " err: (i64 | str),\n" - "};\n" - "fn main() i32 = {\n" - " let p: point = point { x = 1, err = 0 };\n" - " p.err = \"updated\";\n" - " match (p.err) {\n" - " case let v: i64 => return 0;\n" - " case let e: str => return e.len: i32;\n" - " };\n" - " return -1;\n" - "};", 7 }, - /* Pointer variant in a tagged union */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let p: point = point { x = 3, y = 4 };\n" - " let r: (*point | str) = &p;\n" - " match (r) {\n" - " case let pp: *point => return pp.x + pp.y;\n" - " case let e: str => return -1;\n" - " };\n" - " return 0;\n" - "};", 7 }, - /* Forwarding `return inner(n)` when both fns share a tagged- - * union return type — value passes through unwrapped */ - { "type result = (i64 | str);\n" - "fn inner(n: i64) result = {\n" - " if (n < 0) { return \"neg\"; };\n" - " return n + 1;\n" - "};\n" - "fn outer(n: i64) result = {\n" - " return inner(n);\n" - "};\n" - "fn main() i32 = {\n" - " let r: result = outer(-1);\n" - " match (r) {\n" - " case let v: i64 => return v: i32;\n" - " case let e: str => return e.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* match directly on a call expression (no intermediate let) */ - { "fn make(n: i64) (i64 | str) = {\n" - " if (n < 0) { return \"neg\"; };\n" - " return n + 1;\n" - "};\n" - "fn main() i32 = {\n" - " match (make(-1)) {\n" - " case let v: i64 => return v: i32;\n" - " case let e: str => return e.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* Struct variant of a tagged union at the call site. The arg is - * an N_STRUCTLIT, the param is (str|point). Widening at the call - * site must zero-fill the scratch slot, store each field at - * slot+8+field_off, then push the slot words high→low. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn classify(r: (str | point)) i32 = {\n" - " match (r) {\n" - " case let s: str => return 0 - s.len: i32;\n" - " case let p: point => return p.x + p.y;\n" - " };\n" - " return -1;\n" - "};\n" - "fn main() i32 = {\n" - " return classify(point { x = 10, y = 20 });\n" - "};", 30 }, - /* Struct variant passed as a typed local. Widening copies the - * struct words from the local into the scratch slot at +8. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn classify(r: (str | point)) i32 = {\n" - " match (r) {\n" - " case let s: str => return 0 - s.len: i32;\n" - " case let p: point => return p.x + p.y;\n" - " };\n" - " return -1;\n" - "};\n" - "fn main() i32 = {\n" - " let p: point = point { x = 11, y = 22 };\n" - " return classify(p);\n" - "};", 33 }, - /* let-init of a tagged-union local from a struct literal: the - * field stores go into slot+8+field_off in-place; tag patched - * last. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let r: (str | point) = point { x = 7, y = 35 };\n" - " match (r) {\n" - " case let s: str => return 0 - s.len: i32;\n" - " case let p: point => return p.x + p.y;\n" - " };\n" - " return -1;\n" - "};", 42 }, - /* Reassign a tagged-union local to a struct literal. Same path - * as let-init but writing into an already-allocated slot. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let r: (str | point) = \"init\";\n" - " r = point { x = 100, y = 23 };\n" - " match (r) {\n" - " case let s: str => return 0 - s.len: i32;\n" - " case let p: point => return p.x + p.y;\n" - " };\n" - " return -1;\n" - "};", 123 }, - /* Return a struct variant of the fn's tagged return type. The - * scratch-slot path materialises the struct payload then loads - * AX/DX/CX from it. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn make() (str | point) = {\n" - " return point { x = 12, y = 30 };\n" - "};\n" - "fn main() i32 = {\n" - " let r: (str | point) = make();\n" - " match (r) {\n" - " case let s: str => return 0 - s.len: i32;\n" - " case let p: point => return p.x + p.y;\n" - " };\n" - " return -1;\n" - "};", 42 }, - /* Widen a smaller tagged union to a wider one across slot sizes - * AND remapped variant indices. (i32 | rune) is 16B with i32 at - * tag 0; (str | i32 | rune) is 24B with i32 at tag 1. The widen - * path copies the slot words, zero-pads to 24B, then runs a - * CMPQ-chain switch to remap src tag 0 → dst tag 1. */ - { "fn classify(r: (str | i32 | rune)) i32 = {\n" - " match (r) {\n" - " case let s: str => return 1;\n" - " case let n: i32 => return n;\n" - " case let c: rune => return c: i32 + 100;\n" - " };\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let inner: (i32 | rune) = 42: i32;\n" - " return classify(inner);\n" - "};", 42 }, - /* Same shape but the rune variant of inner exercises the tag - * remap from src tag 1 → dst tag 2. The rune literal needs an - * explicit `: rune` cast — `'A'` is an untyped rune and the - * variant search picks the first variant that accepts it (i32, - * which also accepts untyped runes). 'A' = 65 + 100 = 165. */ - { "fn classify(r: (str | i32 | rune)) i32 = {\n" - " match (r) {\n" - " case let s: str => return 1;\n" - " case let n: i32 => return n;\n" - " case let c: rune => return c: i32 + 100;\n" - " };\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let inner: (i32 | rune) = 'A': rune;\n" - " return classify(inner);\n" - "};", 165 }, - /* let-init of a wider tagged union from a smaller-tagged local. */ - { "fn main() i32 = {\n" - " let inner: (i32 | rune) = 42: i32;\n" - " let r: (str | i32 | rune) = inner;\n" - " match (r) {\n" - " case let s: str => return 1;\n" - " case let n: i32 => return n;\n" - " case let c: rune => return c: i32 + 100;\n" - " };\n" - " return 0;\n" - "};", 42 }, - /* Spread variant in tagged-union type — `(...inner | T)`. The - * checker flattens the spread's variants into the enclosing - * union so `outer` has variants {i32, rune, str}. */ - { "type inner = (i32 | rune);\n" - "type outer = (...inner | str);\n" - "fn main() i32 = {\n" - " let r: outer = 42: i32;\n" - " match (r) {\n" - " case let n: i32 => return n;\n" - " case let c: rune => return c: i32;\n" - " case let s: str => return 0;\n" - " };\n" - " return -1;\n" - "};", 42 }, - /* Tagged-union element in a fixed array — scalar+str variants. - * Store via N_INDEX widening, read+match through cgexpr N_INDEX - * tagged-slot load. 10 + len("hi")=2 + 5 = 17. */ - { "fn main() i32 = {\n" - " let arr: [3](i32 | str);\n" - " arr[0] = 10;\n" - " arr[1] = \"hi\";\n" - " arr[2] = 5;\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 3) {\n" - " match (arr[i]) {\n" - " case let v: i32 => s += v;\n" - " case let t: str => s += t.len: i32;\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 17 }, - /* Tagged-union array with struct payload variant. Struct fields - * are written at slot+8+field_off via cg_widen_tagged_store; the - * read side just copies slot bytes into AX/DX/CX for match. - * 5 + (7+11) + 2 + 9 = 34. */ - { "type pair = struct { a: i32, b: i32 };\n" - "fn main() i32 = {\n" - " let arr: [4](i32 | pair | str);\n" - " arr[0] = 5;\n" - " arr[1] = pair { a = 7, b = 11 };\n" - " arr[2] = \"yo\";\n" - " arr[3] = 9;\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 4) {\n" - " match (arr[i]) {\n" - " case let v: i32 => s += v;\n" - " case let p: pair => s += p.a + p.b;\n" - " case let t: str => s += t.len: i32;\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 34 }, - /* Slicing an array of tagged elements — the slice load path - * uses the fallback (non-ident base) N_INDEX which loads slot - * bytes from a computed address. 1 + 2 + 3 + 4 = 10. */ - { "fn main() i32 = {\n" - " let buf: [4](i32 | str);\n" - " buf[0] = 1;\n" - " buf[1] = \"ww\";\n" - " buf[2] = 3;\n" - " buf[3] = 4;\n" - " let xs: [](i32 | str) = buf[0:4];\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 4) {\n" - " match (xs[i]) {\n" - " case let v: i32 => s += v;\n" - " case let t: str => s += t.len: i32;\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 10 }, - /* Passing arr[i] (tagged element) as a tagged arg — cgexpr leaves - * the slot in AX/DX/CX which the call-site shuffle pushes onto - * the arg stack. 5 + 30 (len 3 * 10) + 7 = 42. */ - { "fn weight(v: (i32 | str)) i32 = {\n" - " match (v) {\n" - " case let n: i32 => return n;\n" - " case let s: str => return s.len: i32 * 10;\n" - " };\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let arr: [3](i32 | str);\n" - " arr[0] = 5;\n" - " arr[1] = \"abc\";\n" - " arr[2] = 7;\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 3) {\n" - " s += weight(arr[i]);\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 42 }, - /* let-init of a tagged local from arr[i] — the let path routes - * through cg_widen_tagged_store which, for a tagged source via - * cgexpr, spills AX/DX/CX into the slot. "ww!".len == 3. */ - { "fn main() i32 = {\n" - " let arr: [3](i32 | str);\n" - " arr[0] = 11;\n" - " arr[1] = \"ww!\";\n" - " arr[2] = 7;\n" - " let r: (i32 | str) = arr[1];\n" - " match (r) {\n" - " case let n: i32 => return n;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* Tagged-subset store into a wider tagged-union array element: - * source slot is (i32|str), dest element is (i32|str|u64). The - * store path materialises the subset in scratch then copies slot - * bytes — tag remap is a no-op here (variant order matches). - * arr[0]=9:i32, arr[1]="hi":str → 9 + 2 = 11. */ - { "type inner = (i32 | str);\n" - "fn main() i32 = {\n" - " let arr: [2](i32 | str | u64);\n" - " let v: inner = 9;\n" - " arr[0] = v;\n" - " let w: inner = \"hi\";\n" - " arr[1] = w;\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 2) {\n" - " match (arr[i]) {\n" - " case let n: i32 => s += n;\n" - " case let t: str => s += t.len: i32;\n" - " case let u: u64 => s += 100;\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 11 }, - /* Returning arr[i] from a fn whose return type matches the - * element. cgexpr leaves slot in AX/DX/CX; the return path - * forwards as-is. arr[1] = "abc" → str variant → .len == 3. */ - { "fn pick(i: i32) (i32 | str) = {\n" - " let arr: [2](i32 | str);\n" - " arr[0] = 21;\n" - " arr[1] = \"abc\";\n" - " return arr[i];\n" - "};\n" - "fn main() i32 = {\n" - " let r: (i32 | str) = pick(1);\n" - " match (r) {\n" - " case let n: i32 => return n;\n" - " case let s: str => return s.len: i32;\n" - " };\n" - " return 0;\n" - "};", 3 }, - /* Nullable folded element `(*T | void)` — the slot is one 8B - * pointer word; null is the void variant. Stores route through - * the nullable branch of cg_widen_tagged_store (single MOVQ at - * +0). 100 (nil) + 1 (non-nil) + 100 (nil) = 201. */ - { "fn pickptr(b: bool) *i32 = {\n" - " let x: i32 = 42;\n" - " if (b) { return &x; };\n" - " return nil;\n" - "};\n" - "fn main() i32 = {\n" - " let arr: [3](*i32 | void);\n" - " arr[0] = nil;\n" - " arr[1] = pickptr(true);\n" - " arr[2] = pickptr(false);\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < 3) {\n" - " match (arr[i]) {\n" - " case let p: *i32 => s += 1;\n" - " case => s += 100;\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 201 }, - /* Plan 9-style sentinel error idiom: `def NAME: error = "lit"` - * inlines as the (ptr, len) pair at use sites. */ - { "type error = str;\n" - "def eEOF: error = \"eof\";\n" - "def eShortRead: error = \"short read\";\n" - "fn read(n: i64) (i64 | error) = {\n" - " if (n < 0) { return eEOF; };\n" - " if (n == 0) { return eShortRead; };\n" - " return n + 1;\n" - "};\n" - "fn main() i32 = {\n" - " let r0: (i64 | error) = read(0);\n" - " let r1: (i64 | error) = read(-1);\n" - " let r2: (i64 | error) = read(5);\n" - " let acc: i32 = 0;\n" - " match (r0) {\n" - " case let v: i64 => acc += 100;\n" - " case let e: error => acc += e.len: i32;\n" - " };\n" - " match (r1) {\n" - " case let v: i64 => acc += 100;\n" - " case let e: error => acc += e.len: i32;\n" - " };\n" - " match (r2) {\n" - " case let v: i64 => acc += v: i32;\n" - " case let e: error => acc += 100;\n" - " };\n" - " return acc;\n" - "};", 19 }, - /* End-to-end stdlib usage: pull in lib/os and exercise the - * fallible API tryread/trywrite returning (i64 | oserror) over - * a real syscall. oserror carries -errno; on a bad fd we expect - * -EBADF (-9). */ - { "import os;\n" - "fn main() i32 = {\n" - " let buf: [3]u8;\n" - " buf[0] = 88: u8;\n" - " let ok: (i64 | os.oserror) = os.trywrite(1, buf.ptr, 1u64);\n" - " let bad: (i64 | os.oserror) = os.trywrite(999: i32, buf.ptr, 1u64);\n" - " let acc: i32 = 0;\n" - " match (ok) {\n" - " case let n: i64 => acc += n: i32;\n" - " case let e: os.oserror => acc += -100;\n" - " };\n" - " match (bad) {\n" - " case let n: i64 => acc += -100;\n" - " case let e: os.oserror => acc += (- (e: i64)): i32;\n" - " };\n" - " return acc;\n" - "};", 10 }, /* 1 byte written + 9 (EBADF) */ - /* strconv.stoi64: fallible signed decimal, graduated to - * (i64 | invalid | overflow). invalid carries the offending - * index; overflow is the void variant. */ - { "import strconv;\n" - "type r_t = (i64 | strconv.invalid | strconv.overflow);\n" - "fn main() i32 = {\n" - " let r1: r_t = strconv.stoi64(\"42\", strconv.base.DEC);\n" - " let r2: r_t = strconv.stoi64(\"-7\", strconv.base.DEC);\n" - " let r3: r_t = strconv.stoi64(\"abc\", strconv.base.DEC);\n" - " let acc: i32 = 0;\n" - " match (r1) {\n" - " case let v: i64 => acc += v: i32;\n" - " case let e: strconv.invalid => acc += -100;\n" - " case let e: strconv.overflow => acc += -200;\n" - " };\n" - " match (r2) {\n" - " case let v: i64 => acc += v: i32;\n" - " case let e: strconv.invalid => acc += -100;\n" - " case let e: strconv.overflow => acc += -200;\n" - " };\n" - " match (r3) {\n" - " case let v: i64 => acc += -100;\n" - " case let e: strconv.invalid => acc += e: i32;\n" - " case let e: strconv.overflow => acc += -200;\n" - " };\n" - " return acc;\n" - "};", 35 }, /* 42 + (-7) + 0 (invalid at index 0 in \"abc\") */ - /* strconv.stou64: success path; a leading '-' is rejected with - * overflow per Hare (ref/hare/strconv/stou.ha:72-74 — parseint - * accepts the sign, stou64 then rejects sign==true as overflow). - * Updated from the prior ad-hoc parse, which mis-reported it as - * invalid(index 0) (strconv-int fold-1 fidelity fix). */ - { "import strconv;\n" - "type r_t = (u64 | strconv.invalid | strconv.overflow);\n" - "fn main() i32 = {\n" - " let r1: r_t = strconv.stou64(\"123\", strconv.base.DEC);\n" - " let r2: r_t = strconv.stou64(\"-1\", strconv.base.DEC);\n" - " let acc: i32 = 0;\n" - " match (r1) {\n" - " case let v: u64 => acc += v: i32;\n" - " case let e: strconv.invalid => acc += -100;\n" - " case let e: strconv.overflow => acc += -200;\n" - " };\n" - " match (r2) {\n" - " case let v: u64 => acc += 100;\n" - " case let e: strconv.invalid => acc += 200;\n" - " case let e: strconv.overflow => acc += 7;\n" - " };\n" - " return acc;\n" - "};", 130 }, /* 123 + 7: \"-1\" is overflow (not invalid/success) */ - /* strings.byteindex with (str | rune) needle: returns (i32 | void). */ - { "import strings;\n" - "fn pick(r: (i32 | void), miss: i32) i32 = {\n" - " match (r) {\n" - " case let i: i32 => return i;\n" - " case void => return miss;\n" - " };\n" - " return 0;\n" - "};\n" - "fn main() i32 = {\n" - " let s: str = \"hello, world\";\n" - " let i1: i32 = pick(strings.byteindex(s, ','), -1);\n" - " let i2: i32 = pick(strings.byteindex(s, 'z'), -1);\n" - " let i3: i32 = pick(strings.byteindex(s, \"world\"), -1);\n" - " let i4: i32 = pick(strings.byteindex(s, \"nope\"), -1);\n" - " return i1 + i2 + i3 + i4;\n" - "};", 10 }, /* 5 + (-1) + 7 + (-1) */ - /* bytes.index: substring search over []u8, (i32 | void). */ - { "import bytes;\n" - "fn main() i32 = {\n" - " let buf: [12]u8;\n" - " buf[0] = 104u8; buf[1] = 101u8; buf[2] = 108u8; buf[3] = 108u8;\n" - " buf[4] = 111u8; buf[5] = 44u8; buf[6] = 32u8; buf[7] = 119u8;\n" - " buf[8] = 111u8; buf[9] = 114u8; buf[10] = 108u8; buf[11] = 100u8;\n" - " let needle: [3]u8;\n" - " needle[0] = 119u8; needle[1] = 111u8; needle[2] = 114u8;\n" - " let r: (i32 | void) = bytes.index(buf[0:12], needle[0:3]);\n" - " match (r) {\n" - " case let i: i32 => return i;\n" - " case void => return -1;\n" - " };\n" - " return 0;\n" - "};", 7 }, - /* errors named-void tags — dispatch through a (T | tag | tag) - * union, one variant per error condition. Replaces the old - * errors.equal sentinel-string comparison. */ - { "import errors;\n" - "fn parse(n: i64) (i64 | errors.invalid | errors.noentry) = {\n" - " if (n < 0) { let e: errors.invalid; return e; };\n" - " if (n == 0) { let e: errors.noentry; return e; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let r1: (i64 | errors.invalid | errors.noentry) = parse(-1);\n" - " let r2: (i64 | errors.invalid | errors.noentry) = parse(0);\n" - " let acc: i32 = 0;\n" - " match (r1) {\n" - " case let v: i64 => acc += -100;\n" - " case let e: errors.invalid => acc += 1;\n" - " case let e: errors.noentry => acc += -100;\n" - " };\n" - " match (r2) {\n" - " case let v: i64 => acc += -100;\n" - " case let e: errors.invalid => acc += -100;\n" - " case let e: errors.noentry => acc += 10;\n" - " };\n" - " return acc;\n" - "};", 11 }, - /* errors remaining named-void tags — pin the rest of the surface - * (noaccess / exists / unsupported) so each is callable as both a - * return variant and a match arm. One row per tag would bloat the - * table; fold them into one (T | A | B | C) dispatch. */ - { "import errors;\n" - "fn classify(n: i32) (i32 | errors.noaccess | errors.exists | errors.unsupported) = {\n" - " if (n == 1) { let e: errors.noaccess; return e; };\n" - " if (n == 2) { let e: errors.exists; return e; };\n" - " if (n == 3) { let e: errors.unsupported; return e; };\n" - " return n;\n" - "};\n" - "fn dispatch(r: (i32 | errors.noaccess | errors.exists | errors.unsupported)) i32 = {\n" - " match (r) {\n" - " case let v: i32 => return v;\n" - " case let e: errors.noaccess => return 10;\n" - " case let e: errors.exists => return 20;\n" - " case let e: errors.unsupported => return 30;\n" - " };\n" - " return -1;\n" - "};\n" - "fn main() i32 = {\n" - " return dispatch(classify(1)) + dispatch(classify(2)) + dispatch(classify(3));\n" - "};", 60 }, - /* bufio.scanline: drain '\\n'-terminated lines from a memio.fixed - * source through a bufio.scanner. The trailing "baz" fragment has - * no newline; under the EOF_DISCARD default it's dropped and the - * call returns io.eof. Also pins the cross-module type ref - * (scanner stores *io.stream) end-to-end through `use`. */ - { "import bufio;\n" - "import io;\n" - "import memio;\n" - "fn main() i32 = {\n" - " let raw: [11]u8;\n" - " raw[0] = 102u8; raw[1] = 111u8; raw[2] = 111u8; raw[3] = 10u8;\n" - " raw[4] = 98u8; raw[5] = 97u8; raw[6] = 114u8; raw[7] = 10u8;\n" - " raw[8] = 98u8; raw[9] = 97u8; raw[10] = 122u8;\n" - " let mst: memio.stream = memio.fixed(raw[0:11]);\n" - " let m: io.stream = &mst.vt;\n" - " let buf: [16]u8;\n" - " let sc: bufio.scanner = bufio.newscannerbuf(m, buf[0:16]);\n" - " let acc: i32 = 0;\n" - " let l1: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);\n" - " match (l1) {\n" - " case let s: str => acc += s.len;\n" - " case io.eof => acc += -100;\n" - " case let _e: io.error => acc += -1000;\n" - " case bufio.overflow => acc += -10000;\n" - " };\n" - " let l2: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);\n" - " match (l2) {\n" - " case let s: str => acc += s.len;\n" - " case io.eof => acc += -100;\n" - " case let _e: io.error => acc += -1000;\n" - " case bufio.overflow => acc += -10000;\n" - " };\n" - " let l3: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc);\n" - " match (l3) {\n" - " case let s: str => acc += -100;\n" - " case io.eof => acc += 7;\n" - " case let _e: io.error => acc += -1000;\n" - " case bufio.overflow => acc += -10000;\n" - " };\n" - " return acc;\n" - "};", 13 }, /* 3 + 3 + 7 (eof arm) */ - /* `(scalar, str)` tuple return: AX:DX:CX convention extends the - * tagged-union ABI. AX = scalar, DX = str.ptr, CX = str.len. - * Receive sites destructure off the same regs regardless of - * positional order. Without the fix, len was lost (only AX:DX - * returned), every receive shape gave garbage. */ - { "fn split() (i64, str) = { return 42, \"hello\"; };\n" - "fn main() i32 = {\n" - " let n, s = split();\n" - " return (n: i32) + (s.len: i32);\n" - "};", 47 }, - { "fn split() (str, i64) = { return \"hello\", 42; };\n" - "fn main() i32 = {\n" - " let s, n = split();\n" - " return (n: i32) + (s.len: i32);\n" - "};", 47 }, - { "fn split() (i64, str) = { return 42, \"hello\"; };\n" - "fn main() i32 = {\n" - " let t: (i64, str) = split();\n" - " return (t.0: i32) + (t.1.len: i32);\n" - "};", 47 }, - /* Hare-style paren tuple-destructure with str element */ - { "fn split() (i64, str) = { return 42, \"hello\"; };\n" - "fn main() i32 = {\n" - " let (n, s) = split();\n" - " return (n: i32) + (s.len: i32);\n" - "};", 47 }, - /* Chained field write through a pointer field: `r.sym.flag = v` - * where `r.sym: *T`. The cgen must evaluate the inner pointer, - * then store at *(ptr + field.offset). Without the fix, the - * single-level N_IDENT-base path doesn't fire (base is itself - * an N_DOT) and the assignment silently emits no instructions. - * Compound op + 1-byte field + 3-level chain all exercised. */ - { "type inner = struct { tag: u8, pad: u8, flag: i32 };\n" - "type outer = struct { sym: *inner };\n" - "fn main() i32 = {\n" - " let i: inner = inner { tag = 0u8, pad = 0u8, flag = 10 };\n" - " let r: outer = outer { sym = &i };\n" - " r.sym.flag += 32;\n" - " r.sym.tag = 5u8;\n" - " return r.sym.flag + (r.sym.tag: i32);\n" - "};", 47 }, - { "type leaf = struct { v: i32 };\n" - "type mid = struct { l: *leaf };\n" - "type top = struct { m: *mid };\n" - "fn main() i32 = {\n" - " let lf: leaf = leaf { v = 0 };\n" - " let md: mid = mid { l = &lf };\n" - " let tp: top = top { m = &md };\n" - " tp.m.l.v = 99;\n" - " return tp.m.l.v;\n" - "};", 99 }, - /* `def NAME: str = \"lit\"` field access. The Sdef has no stack - * slot, so .len/.ptr must inline the literal length / strlit - * address; without the fix, .len reads BP+8 (return-address slot) - * as garbage. */ - { "def MSG: str = \"hello world\";\n" - "fn main() i32 = { return MSG.len: i32; };", 11 }, - { "import os;\n" - "def GREETING: str = \"hi\\n\";\n" - "fn main() i32 = {\n" - " os.write(1, GREETING.ptr, GREETING.len: u64);\n" - " return GREETING.len: i32;\n" - "};", 3 }, - /* Hare-style `is` / `as`: type test returns bool, type assertion - * unwraps to the variant's value (success path only — abort path - * exit(1) is exercised manually). Covers i64/i32 scalar variants - * and str (16B variant via .len pseudo-field). */ - { "fn classify(n: i64) (i64 | i32) = {\n" - " if (n < 0) { return 7: i32; };\n" - " return n;\n" - "};\n" - "fn main() i32 = {\n" - " let ok: (i64 | i32) = classify(40);\n" - " let bad: (i64 | i32) = classify(-1);\n" - " let s: i32 = 0;\n" - " if (ok is i64) { s += 1; };\n" - " if (bad is i32) { s += 1; };\n" - " if (ok is i32) { s += 100; };\n" - " if (bad is i64) { s += 100; };\n" - " let v: i64 = ok as i64;\n" - " let e: i32 = bad as i32;\n" - " return (v: i32) + s + e;\n" - "};", 49 }, - /* `as` on a 16B str variant — unwrap loads (ptr, len). */ - { "fn fail() (i64 | str) = { return \"bad\"; };\n" - "fn main() i32 = {\n" - " let r: (i64 | str) = fail();\n" - " let e: str = r as str;\n" - " return e.len: i32;\n" - "};", 3 }, - /* enum: auto-increment, explicit value, sibling-ref */ - { "type color = enum { RED, GREEN, BLUE };\n" - "fn main() i32 = { return color.BLUE as i32; };", 2 }, - { "type mode = enum u8 { R = 1, W = 2, RW = R | W };\n" - "fn main() i32 = {\n" - " let m: mode = mode.RW;\n" - " return m as i32;\n" - "};", 3 }, - /* enum: bitwise op between two members yields the same enum type */ - { "type mode = enum u8 { R = 1, W = 2 };\n" - "fn main() i32 = {\n" - " let m: mode = mode.R | mode.W;\n" - " return m as i32;\n" - "};", 3 }, - /* enum: pkg-qualified access — `pkg.dir.SOUTH` resolves through - * SK_USE and folds to the member literal. */ - { "package pkg;\n" - "type dir = enum { NORTH, SOUTH, EAST, WEST };\n" - "package main;\n" - "import pkg;\n" - "fn main() i32 = { return pkg.dir.SOUTH as i32; };", 1 }, - /* f64 compound assigns on local: += -= *= /= each modify in place - * (ADDSD/SUBSD/MULSD/DIVSD load-modify-store, not a plain MOVSD that - * would overwrite). 1.5 + 0.5 = 2.0 → 2.0 - 1.0 = 1.0 → 1.0 * 4.0 = - * 4.0 → 4.0 / 2.0 = 2.0 → return 2. */ - { "fn main() i32 = {\n" - " let a: f64 = 1.5;\n" - " a += 0.5;\n" - " a -= 1.0;\n" - " a *= 4.0;\n" - " a /= 2.0;\n" - " return a: i32;\n" - "};", 2 }, - /* f64 compound on a top-level global: LEAQ name(SB), then MOVSD - * load → ADDSD → MOVSD store. 10.0 + 5.0 = 15.0 → 15.0 * 2.0 = - * 30.0 → 30.0 - 20.0 = 10.0 → 10.0 / 5.0 = 2.0. */ - { "let G: f64 = 10.0;\n" - "fn main() i32 = {\n" - " G += 5.0;\n" - " G *= 2.0;\n" - " G -= 20.0;\n" - " G /= 5.0;\n" - " return G: i32;\n" - "};", 2 }, - /* Top-level `[N]u8` array: zero-init DATAW slot + LEAQ name(SB) - * addressing for index and address-of. `buf[i] = c` narrows to - * MOVB; reading back roundtrips through MOVZBQ. */ - { "let buf: [4]u8;\n" - "fn main() i32 = {\n" - " buf[0] = 7u8;\n" - " buf[1] = 35u8;\n" - " return (buf[0] + buf[1]): i32;\n" - "};", 42 }, - /* `&arr[i]` for a top-level array: TK_AMP must compute the - * address, not the value. Then `*p = c` for *u8 stores 1 byte. - * Drives Hare's static-buffer pattern (strconv.*tos). */ - { "let buf: [4]u8;\n" - "fn main() i32 = {\n" - " let p: *u8 = &buf[0];\n" - " *p = 41u8;\n" - " let q: *u8 = &buf[1];\n" - " *q = 1u8;\n" - " return (buf[0] + buf[1]): i32;\n" - "};", 42 }, - /* Cross-module enum member access: `pkg.Enum.MEMBER`. Inner - * N_DOT resolves through SK_USE → SK_TYPE; outer N_DOT folds to - * the member's integer literal. Validates the strconv.base.DEC - * shape that the *tos / sto* signatures now use. */ - { "package pkg;\n" - "export type base = enum i32 { DEC = 10, HEX = 16 };\n" - "package main;\n" - "import pkg;\n" - "fn pick(b: pkg.base) i32 = { return b as i32; };\n" - "fn main() i32 = {\n" - " let a: i32 = pick(pkg.base.DEC);\n" - " let b: i32 = pick(pkg.base.HEX);\n" - " return a + b + 16;\n" - "};", 42 }, - /* Sum-typed parameter (str | rune): match-dispatch on a tagged - * union arg widened from a concrete variant at the call site. - * Mirrors lib/strings.byteindex's needle parameter. */ - { "fn pick(n: (str | rune)) i32 = {\n" - " match (n) {\n" - " case let s: str => return s.len + 100;\n" - " case let r: rune => return r: i32;\n" - " };\n" - "};\n" - "fn main() i32 = {\n" - " let a: i32 = pick(\"hi\");\n" - " let b: i32 = pick('?');\n" - " return a + b - 123;\n" - "};", 42 }, /* (2+100) + 63 - 123 = 42 */ - /* Sum-typed (u8 | []u8): 32B slot exceeds the old 24B cap on - * tagged_arg_size. Param fills 4 reg words; the callee must - * read slot+24 (cap) for the slice variant to round-trip. */ - { "import bytes;\n" - "fn main() i32 = {\n" - " let buf: [4]u8;\n" - " buf[0] = 1u8; buf[1] = 2u8; buf[2] = 3u8; buf[3] = 4u8;\n" - " let needle: [2]u8;\n" - " needle[0] = 3u8; needle[1] = 4u8;\n" - " let r1: (i32 | void) = bytes.index(buf[0:4], 3u8);\n" - " let r2: (i32 | void) = bytes.index(buf[0:4], needle[0:2]);\n" - " let a: i32 = 99;\n" - " let b: i32 = 99;\n" - " match (r1) {\n" - " case let i: i32 => a = i;\n" - " case void => a = -1;\n" - " };\n" - " match (r2) {\n" - " case let i: i32 => b = i;\n" - " case void => b = -1;\n" - " };\n" - " return a * 10 + b + 18;\n" /* 2*10 + 2 + 18 = 40, off-by-2 → 42 */ - "};", 40 }, - /* Slice-payload tagged return ([]u8 | E), slot 32B. The 4-reg - * return ABI (AX=tag, DX=ptr, CX=len, R8=cap) lets the callee - * forward all 4 words. Before the bump, slice.len was dropped - * because only 3 regs were used. */ - { "type rterr = !str;\n" - "fn build(n: i32) ([]u8 | rterr) = {\n" - " if (n < 0) { return \"bad\": rterr; };\n" - " let buf: [4]u8;\n" - " buf[0] = 10u8; buf[1] = 20u8; buf[2] = 30u8; buf[3] = 40u8;\n" - " return buf[0:n];\n" - "};\n" - "fn main() i32 = {\n" - " let r: ([]u8 | rterr) = build(3);\n" - " match (r) {\n" - " case let xs: []u8 => {\n" - " if (xs.len != 3) { return 100; };\n" - " return (xs[0] + xs[1] + xs[2]): i32;\n" - " };\n" - " case let e: rterr => return -1;\n" - " };\n" - " return 0;\n" - "};", 60 }, /* 10 + 20 + 30 = 60 */ - /* `[N]TaggedAlias` array: each element is a 24B tagged slot, - * and `arr[i] = literal: TaggedAlias` widens through the - * cgwidentaggedstore path. Validates the cast-peel for - * `expr: TaggedAlias` (which is a widening, not a re-interpret) - * and the alias-resolving element-size lookup. */ - { "type formattable = (i64 | str | bool);\n" - "fn main() i32 = {\n" - " let args: [3]formattable;\n" - " args[0] = 1i64: formattable;\n" - " args[1] = \"hi\": formattable;\n" - " args[2] = true: formattable;\n" - " let s: i32 = 0;\n" - " let i: i32 = 0;\n" - " for (i < args.len) {\n" - " match (args[i]) {\n" - " case let n: i64 => s += n: i32;\n" - " case let v: str => s += v.len;\n" - " case let b: bool => { if (b) { s += 39; }; };\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};", 42 }, /* 1 + 2 + 39 = 42 */ - /* Hare-style variadic gather: `args: T...` declares an N-arg - * variadic; the call-site materialises N values into a fresh - * `[N]T` and synthesises a {ptr,len,cap} slice for the param. - * Plain element type (i64): no widening, MOVQ-per-element. */ - { "fn sum(args: i64...) i64 = {\n" - " let s: i64 = 0i64;\n" - " let i: i32 = 0;\n" - " for (i < args.len) { s += args[i]; i += 1; };\n" - " return s;\n" - "};\n" - "fn main() i32 = {\n" - " return sum(1i64, 2i64, 3i64, 7i64, 9i64, 20i64): i32;\n" - "};", 42 }, - /* Variadic with zero args: empty-slice descriptor {nil,0,0}. - * Confirms the gather path doesn't crash on N=0. */ - { "fn sum(args: i64...) i64 = {\n" - " let s: i64 = 0i64;\n" - " let i: i32 = 0;\n" - " for (i < args.len) { s += args[i]; i += 1; };\n" - " return s;\n" - "};\n" - "fn main() i32 = {\n" - " let a: i64 = sum();\n" - " let b: i64 = sum(42i64);\n" - " return (a + b): i32;\n" - "};", 42 }, - /* Variadic with tagged-union element type: each gathered arg - * widens to the variant's slot shape (tag@+0, payload@+8). The - * runtime match-dispatch reads (i64=1)+(str.len=2)+(bool=39)=42. */ - { "type formattable = (i64 | str | bool);\n" - "fn sumtag(args: formattable...) i64 = {\n" - " let s: i64 = 0i64;\n" - " let i: i32 = 0;\n" - " for (i < args.len) {\n" - " match (args[i]) {\n" - " case let n: i64 => s += n;\n" - " case let v: str => s += v.len: i64;\n" - " case let b: bool => { if (b) { s += 39i64; }; };\n" - " };\n" - " i += 1;\n" - " };\n" - " return s;\n" - "};\n" - "fn main() i32 = { return sumtag(1i64, \"hi\", true): i32; };", 42 }, - /* Variadic forwarding: `wrap(args...)` passes the local slice - * directly to `sum`, no re-gather. Mirrors Hare's wrapper shape - * (`fn println(args: formattable...) = fprintln(os.stdout, args...)`). */ - { "fn sum(args: i64...) i64 = {\n" - " let s: i64 = 0i64;\n" - " let i: i32 = 0;\n" - " for (i < args.len) { s += args[i]; i += 1; };\n" - " return s;\n" - "};\n" - "fn wrap(prefix: i64, args: i64...) i64 = {\n" - " return prefix + sum(args...);\n" - "};\n" - "fn main() i32 = {\n" - " return wrap(2i64, 1i64, 2i64, 3i64, 4i64, 5i64, 7i64, 18i64): i32;\n" - "};", 42 }, - /* lib/fmt user-side: `fmt.println(args: formattable...)` gathers - * mixed-type args at the call site. End-to-end exercises the - * lib/fmt graduation: the wrapper-chain `println → fprintln → - * fprint` over an io.handle file arm is itself variadic-forwarding, - * so this validates both gather (at main) and `args...` forward - * (inside lib/fmt). println returns Hare's `(size | io.error)` - * (#94 fold-eFinal); the size arm carries bytes printed - * (`hello 7\n` = 8). */ - { "import fmt;\n" - "import io;\n" - "fn main() i32 = {\n" - " match (fmt.println(\"hello\", 7i64)) {\n" - " case let n: size => return n: i32;\n" - " case let _e: io.error => return -1;\n" - " };\n" - "};", 8 }, - /* short-circuit `&&`: RHS skipped when LHS is false. Without - * short-circuit the `p.x` deref on a nil pointer segfaults. - * Pinned the cgen bug surfaced by lib/getopt's argv guards - * (`argslen > 0 && !streq(argsptr[0], "--")`) on a nil argsptr. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let p: *point = nil;\n" - " if (p != nil && p.x > 0) { return 1; };\n" - " return 42;\n" - "};", 42 }, - /* short-circuit `||`: RHS skipped when LHS is true. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let p: *point = nil;\n" - " if (p == nil || p.x > 0) { return 42; };\n" - " return 1;\n" - "};", 42 }, - /* `&&` LHS true: RHS evaluated, expression yields its boolean. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let pt: point = point { x = 5, y = 10 };\n" - " let p: *point = &pt;\n" - " if (p != nil && p.x > 0) { return 42; };\n" - " return 1;\n" - "};", 42 }, - /* `||` LHS false: RHS evaluated, expression yields its boolean. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let pt: point = point { x = 7, y = 0 };\n" - " let p: *point = &pt;\n" - " if (p == nil || p.x > 0) { return 42; };\n" - " return 1;\n" - "};", 42 }, - /* mixed `&&` / `||` precedence — `&&` binds tighter than `||`, - * so `(p != nil && p.x > 0) || p == nil`. With short-circuit at - * each level: AND skips `p.x` (LHS false), OR keeps the true. */ - { "type point = struct { x: i32, y: i32 };\n" - "fn main() i32 = {\n" - " let p: *point = nil;\n" - " if (p != nil && p.x > 0 || p == nil) { return 42; };\n" - " return 1;\n" - "};", 42 }, - /* short-circuit must still yield a clean boolean in the - * expression context (not just inside `if`). `true && false` - * stored into a bool and re-checked. */ - { "fn main() i32 = {\n" - " let a: bool = (1 > 0) && (2 < 1);\n" - " let b: bool = (1 < 0) || (2 > 1);\n" - " let n: i32 = 0;\n" - " if (!a) { n += 10; };\n" - " if (b) { n += 32; };\n" - " return n;\n" - "};", 42 }, - { NULL, 0 } -}; - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - /* Resolve to absolute path: tests chdir into /tmp/... */ - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwe2e_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) { - fprintf(stderr, "row %d: mkdir %s: %s\n", - i, tmpdir, strerror(errno)); - fail++; - continue; - } - - /* Source, output, and the caller-owned output `.sepwork` all live - * inside this invocation-owned directory. */ - char src[128], outbin[128], sepdir[160], rmcmd[192]; - snprintf(src, sizeof src, "%s/wwe2e_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwe2e_%d_%d", tmpdir, getpid(), i); - snprintf(sepdir, sizeof sepdir, "%s.sepwork", outbin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", sepdir); - int row_failed = 0; - char cmd[1024]; - int got; - - FILE *f = fopen(src, "wb"); - if (!f) { - fprintf(stderr, "row %d: fopen %s: %s\n", - i, src, strerror(errno)); - row_failed = 1; - goto cleanup; - } - wwtest_fputs(rows[i].src, f); - if (ferror(f)) { - fprintf(stderr, "row %d: write %s failed\n", i, src); - row_failed = 1; - } - if (fclose(f) != 0) { - fprintf(stderr, "row %d: close %s: %s\n", - i, src, strerror(errno)); - row_failed = 1; - } - if (row_failed) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - row_failed = 1; - goto cleanup; - } - - got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row %d: exit %d, want %d\n src: %s\n", - i, got, rows[i].want_exit, rows[i].src); - row_failed = 1; - } - -cleanup: - { - int cleanup_failed = 0; - if (runwait(rmcmd) != 0) { - fprintf(stderr, "row %d: remove %s failed\n", i, sepdir); - cleanup_failed = 1; - } - if (unlink(src) != 0 && errno != ENOENT) { - fprintf(stderr, "row %d: unlink %s: %s\n", - i, src, strerror(errno)); - cleanup_failed = 1; - } - if (unlink(outbin) != 0 && errno != ENOENT) { - fprintf(stderr, "row %d: unlink %s: %s\n", - i, outbin, strerror(errno)); - cleanup_failed = 1; - } - if (rmdir(tmpdir) != 0) { - fprintf(stderr, "row %d: rmdir %s: %s\n", - i, tmpdir, strerror(errno)); - cleanup_failed = 1; - } - if (!row_failed && cleanup_failed) row_failed = 1; - } - if (row_failed) fail++; - } - if (fail) { fprintf(stderr, "%d/%d e2e tests failed\n", fail, n); return 1; } - printf("e2e: %d/%d ok\n", n, n); - return 0; -} diff --git a/test/wcc/data/r700_add_call/case.ww b/test/wcc/data/r700_add_call/case.ww new file mode 100644 index 00000000..15cb22b3 --- /dev/null +++ b/test/wcc/data/r700_add_call/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 1. +package main; +fn add(a: i32, b: i32) i32 = { return a + b; }; +fn main() i32 = { return add(7, 35); }; diff --git a/test/wcc/data/r700_alias_union_arg/case.ww b/test/wcc/data/r700_alias_union_arg/case.ww new file mode 100644 index 00000000..25fc7b13 --- /dev/null +++ b/test/wcc/data/r700_alias_union_arg/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 107 +// Migrated from 700_e2e row 73. +package main; +type result = (i64 | i32); +fn unwrap(r: result) i64 = { + match (r) { + case let v: i64 => return v; + case let e: i32 => return e: i64; + }; + return -1; +}; +fn main() i32 = { + let r1: result = 100; + let r2: result = 7: i32; + return (unwrap(r1) + unwrap(r2)): i32; +}; diff --git a/test/wcc/data/r700_alloc_free_assert/case.ww b/test/wcc/data/r700_alloc_free_assert/case.ww new file mode 100644 index 00000000..fe539156 --- /dev/null +++ b/test/wcc/data/r700_alloc_free_assert/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 45. +package main; +import os; +import rt; +type point = struct { x: i64, y: i64 }; +fn main() i32 = { + let p: *point = alloc(point { x = 7, y = 35 })!; + let r: i64 = p.x + p.y; + free(p); + assert(r == 42, "sum mismatch\n"); + return r: i32; +}; diff --git a/test/wcc/data/r700_alloc_shadow_myos/case.ww b/test/wcc/data/r700_alloc_shadow_myos/case.ww new file mode 100644 index 00000000..4ceba569 --- /dev/null +++ b/test/wcc/data/r700_alloc_shadow_myos/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 107 +// Migrated from 700_e2e row 40. +package myos; +fn alloc(n: i64) i64 = { return n + 100; }; +fn run() i64 = { return alloc(7); }; +package main; +import myos; +fn main() i32 = { + return myos.run(): i32; +}; diff --git a/test/wcc/data/r700_alloc_slice_cap/case.ww b/test/wcc/data/r700_alloc_slice_cap/case.ww new file mode 100644 index 00000000..d1125086 --- /dev/null +++ b/test/wcc/data/r700_alloc_slice_cap/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 16 +// Migrated from 700_e2e row 36. +package main; +import rt; +fn main() i32 = { + let s: []u8 = alloc([], 16)!; + append(s, 72u8, 105u8); + return s.cap; +}; diff --git a/test/wcc/data/r700_alloc_slice_prop/case.ww b/test/wcc/data/r700_alloc_slice_prop/case.ww new file mode 100644 index 00000000..f1f7966f --- /dev/null +++ b/test/wcc/data/r700_alloc_slice_prop/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 12 +// Migrated from 700_e2e row 39. +package main; +import rt; +fn doit() (i32 | nomem) = { + let s: []str = alloc([], 12)?; + return s.cap: i32; +}; +fn main() i32 = { + return doit()!; +}; diff --git a/test/wcc/data/r700_alloc_slice_rune/case.ww b/test/wcc/data/r700_alloc_slice_rune/case.ww new file mode 100644 index 00000000..3671f9af --- /dev/null +++ b/test/wcc/data/r700_alloc_slice_rune/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 8 +// Migrated from 700_e2e row 37. +package main; +import rt; +fn main() i32 = { + let s: []rune = alloc([], 8)!; + return s.cap; +}; diff --git a/test/wcc/data/r700_alloc_slice_str/case.ww b/test/wcc/data/r700_alloc_slice_str/case.ww new file mode 100644 index 00000000..62696b7f --- /dev/null +++ b/test/wcc/data/r700_alloc_slice_str/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 4 +// Migrated from 700_e2e row 38. +package main; +import rt; +fn main() i32 = { + let s: []str = alloc([], 4)!; + return s.cap; +}; diff --git a/test/wcc/data/r700_alloc_struct/case.ww b/test/wcc/data/r700_alloc_struct/case.ww new file mode 100644 index 00000000..a0dfa1ab --- /dev/null +++ b/test/wcc/data/r700_alloc_struct/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 25 +// Migrated from 700_e2e row 34. +package main; +import rt; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let p: *point = alloc(point { x = 3, y = 4 })!; + return p.x * p.x + p.y * p.y; +}; diff --git a/test/wcc/data/r700_andand_rhs/case.ww b/test/wcc/data/r700_andand_rhs/case.ww new file mode 100644 index 00000000..aeb13d79 --- /dev/null +++ b/test/wcc/data/r700_andand_rhs/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 135. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let pt: point = point { x = 5, y = 10 }; + let p: *point = &pt; + if (p != nil && p.x > 0) { return 42; }; + return 1; +}; diff --git a/test/wcc/data/r700_andand_short/case.ww b/test/wcc/data/r700_andand_short/case.ww new file mode 100644 index 00000000..3c40fb91 --- /dev/null +++ b/test/wcc/data/r700_andand_short/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 133. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let p: *point = nil; + if (p != nil && p.x > 0) { return 1; }; + return 42; +}; diff --git a/test/wcc/data/r700_andor_precedence/case.ww b/test/wcc/data/r700_andor_precedence/case.ww new file mode 100644 index 00000000..ffa44303 --- /dev/null +++ b/test/wcc/data/r700_andor_precedence/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 137. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let p: *point = nil; + if (p != nil && p.x > 0 || p == nil) { return 42; }; + return 1; +}; diff --git a/test/wcc/data/r700_append_len/case.ww b/test/wcc/data/r700_append_len/case.ww new file mode 100644 index 00000000..bda905ed --- /dev/null +++ b/test/wcc/data/r700_append_len/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 31. +package main; +import os; +fn main() i32 = { + let s: []u8; + s.ptr = nil; s.len = 0; s.cap = 0; + append(s, 88u8); append(s, 89u8); append(s, 90u8); + os.write(1, s.ptr, len(s): u64); + os.write(1, "\n".ptr, 1u64); + return len(s); +}; diff --git a/test/wcc/data/r700_append_spread/case.ww b/test/wcc/data/r700_append_spread/case.ww new file mode 100644 index 00000000..1c5f00a7 --- /dev/null +++ b/test/wcc/data/r700_append_spread/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 41. +package main; +import os; +fn main() i32 = { + let src: []u8; + src.ptr = nil; src.len = 0; src.cap = 0; + append(src, 65u8, 66u8, 67u8); + let dst: []u8; + dst.ptr = nil; dst.len = 0; dst.cap = 0; + append(dst, src...); + os.write(1, dst.ptr, dst.len: u64); + os.write(1, "\n".ptr, 1u64); + return dst.len; +}; diff --git a/test/wcc/data/r700_argc/case.ww b/test/wcc/data/r700_argc/case.ww new file mode 100644 index 00000000..682fed5b --- /dev/null +++ b/test/wcc/data/r700_argc/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 1 +// Migrated from 700_e2e row 21. +package main; +fn main(argc: i32, argv: **u8) i32 = { return argc; }; diff --git a/test/wcc/data/r700_args9_spill/case.ww b/test/wcc/data/r700_args9_spill/case.ww new file mode 100644 index 00000000..2c78aa7e --- /dev/null +++ b/test/wcc/data/r700_args9_spill/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 45 +// Migrated from 700_e2e row 12. +package main; +fn s9(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32, i: i32) i32 = { + return a + b + c + d + e + f + g + h + i; +}; +fn main() i32 = { return s9(1,2,3,4,5,6,7,8,9); }; diff --git a/test/wcc/data/r700_arr_i64_index/case.ww b/test/wcc/data/r700_arr_i64_index/case.ww new file mode 100644 index 00000000..912b600a --- /dev/null +++ b/test/wcc/data/r700_arr_i64_index/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 100 +// Migrated from 700_e2e row 22. +package main; +fn main() i32 = { + let arr: [4]i64; + arr[0] = 10; arr[1] = 20; arr[2] = 30; arr[3] = 40; + let sum: i64 = 0; + let i: i32 = 0; + for (i < 4) { sum += arr[i]; i += 1; }; + return sum: i32; +}; diff --git a/test/wcc/data/r700_arr_u8_rw/case.ww b/test/wcc/data/r700_arr_u8_rw/case.ww new file mode 100644 index 00000000..97e82ae0 --- /dev/null +++ b/test/wcc/data/r700_arr_u8_rw/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 10 +// Migrated from 700_e2e row 6. +package main; +fn main() i32 = { + let buf: [4]u8; + buf[0] = 1: u8; + buf[1] = 2: u8; + buf[2] = 3: u8; + buf[3] = 4: u8; + let sum: i32 = 0; + let i: i32 = 0; + for (i < 4) { sum += buf[i]: i32; i += 1; }; + return sum; +}; diff --git a/test/wcc/data/r700_as_str_variant/case.ww b/test/wcc/data/r700_as_str_variant/case.ww new file mode 100644 index 00000000..bd93bb26 --- /dev/null +++ b/test/wcc/data/r700_as_str_variant/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 114. +package main; +fn fail() (i64 | str) = { return "bad"; }; +fn main() i32 = { + let r: (i64 | str) = fail(); + let e: str = r as str; + return e.len: i32; +}; diff --git a/test/wcc/data/r700_bang_alias_param/case.ww b/test/wcc/data/r700_bang_alias_param/case.ww new file mode 100644 index 00000000..6c89e8f5 --- /dev/null +++ b/test/wcc/data/r700_bang_alias_param/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 56. +package main; +type invalid = !i32; +type overflow = !void; +type error = !(invalid | overflow); +fn errcode(e: error) i32 = { + match (e) { + case let v: invalid => return v: i32; + case let v: overflow => return 99; + }; + return 0; +}; +fn main() i32 = { + let e: error = 7: invalid; + return errcode(e); +}; diff --git a/test/wcc/data/r700_bang_unwrap_str/case.ww b/test/wcc/data/r700_bang_unwrap_str/case.ww new file mode 100644 index 00000000..b0595c7d --- /dev/null +++ b/test/wcc/data/r700_bang_unwrap_str/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 2 +// Migrated from 700_e2e row 70. +package main; +fn make() (str | i64) = { + return "ok"; +}; +fn main() i32 = { + let r: (str | i64) = make(); + let v: str = r!; + return v.len: i32; +}; diff --git a/test/wcc/data/r700_bang_variants_remap/case.ww b/test/wcc/data/r700_bang_variants_remap/case.ww new file mode 100644 index 00000000..9ba1010b --- /dev/null +++ b/test/wcc/data/r700_bang_variants_remap/case.ww @@ -0,0 +1,23 @@ +//ww:run-exit 107 +// Migrated from 700_e2e row 68. +package main; +type invalid = !i32; +type overflow = !void; +fn inner(n: i32) (invalid | i64 | overflow) = { + if (n == 0) { return 7: invalid; }; + if (n < 0) { return void: overflow; }; + return n: i64 + 1000; +}; +fn outer(n: i32) (overflow | i64 | invalid) = { + let v: i64 = inner(n)?; + return v + 1; +}; +fn main() i32 = { + let r: (overflow | i64 | invalid) = outer(0); + match (r) { + case let v: i64 => return v: i32; + case let e: invalid => return e + 100; + case let e: overflow => return 999; + }; + return 0; +}; diff --git a/test/wcc/data/r700_bufio_scanline_discard/case.ww b/test/wcc/data/r700_bufio_scanline_discard/case.ww new file mode 100644 index 00000000..34f8f4f1 --- /dev/null +++ b/test/wcc/data/r700_bufio_scanline_discard/case.ww @@ -0,0 +1,39 @@ +//ww:run-exit 13 +// Migrated from 700_e2e row 104. +package main; +import bufio; +import io; +import memio; +fn main() i32 = { + let raw: [11]u8; + raw[0] = 102u8; raw[1] = 111u8; raw[2] = 111u8; raw[3] = 10u8; + raw[4] = 98u8; raw[5] = 97u8; raw[6] = 114u8; raw[7] = 10u8; + raw[8] = 98u8; raw[9] = 97u8; raw[10] = 122u8; + let mst: memio.stream = memio.fixed(raw[0:11]); + let m: io.stream = &mst.vt; + let buf: [16]u8; + let sc: bufio.scanner = bufio.newscannerbuf(m, buf[0:16]); + let acc: i32 = 0; + let l1: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc); + match (l1) { + case let s: str => acc += s.len; + case io.eof => acc += -100; + case let _e: io.error => acc += -1000; + case bufio.overflow => acc += -10000; + }; + let l2: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc); + match (l2) { + case let s: str => acc += s.len; + case io.eof => acc += -100; + case let _e: io.error => acc += -1000; + case bufio.overflow => acc += -10000; + }; + let l3: (str | io.eof | io.error | bufio.overflow) = bufio.scanline(&sc); + match (l3) { + case let s: str => acc += -100; + case io.eof => acc += 7; + case let _e: io.error => acc += -1000; + case bufio.overflow => acc += -10000; + }; + return acc; +}; diff --git a/test/wcc/data/r700_bytes_index/case.ww b/test/wcc/data/r700_bytes_index/case.ww new file mode 100644 index 00000000..2120619a --- /dev/null +++ b/test/wcc/data/r700_bytes_index/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 101. +package main; +import bytes; +fn main() i32 = { + let buf: [12]u8; + buf[0] = 104u8; buf[1] = 101u8; buf[2] = 108u8; buf[3] = 108u8; + buf[4] = 111u8; buf[5] = 44u8; buf[6] = 32u8; buf[7] = 119u8; + buf[8] = 111u8; buf[9] = 114u8; buf[10] = 108u8; buf[11] = 100u8; + let needle: [3]u8; + needle[0] = 119u8; needle[1] = 111u8; needle[2] = 114u8; + let r: (i32 | void) = bytes.index(buf[0:12], needle[0:3]); + match (r) { + case let i: i32 => return i; + case void => return -1; + }; + return 0; +}; diff --git a/test/wcc/data/r700_chain3_ptrfield/case.ww b/test/wcc/data/r700_chain3_ptrfield/case.ww new file mode 100644 index 00000000..3301f57f --- /dev/null +++ b/test/wcc/data/r700_chain3_ptrfield/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 99 +// Migrated from 700_e2e row 110. +package main; +type leaf = struct { v: i32 }; +type mid = struct { l: *leaf }; +type top = struct { m: *mid }; +fn main() i32 = { + let lf: leaf = leaf { v = 0 }; + let md: mid = mid { l = &lf }; + let tp: top = top { m = &md }; + tp.m.l.v = 99; + return tp.m.l.v; +}; diff --git a/test/wcc/data/r700_chain_ptrfield_write/case.ww b/test/wcc/data/r700_chain_ptrfield_write/case.ww new file mode 100644 index 00000000..7c422fc3 --- /dev/null +++ b/test/wcc/data/r700_chain_ptrfield_write/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 47 +// Migrated from 700_e2e row 109. +package main; +type inner = struct { tag: u8, pad: u8, flag: i32 }; +type outer = struct { sym: *inner }; +fn main() i32 = { + let i: inner = inner { tag = 0u8, pad = 0u8, flag = 10 }; + let r: outer = outer { sym = &i }; + r.sym.flag += 32; + r.sym.tag = 5u8; + return r.sym.flag + (r.sym.tag: i32); +}; diff --git a/test/wcc/data/r700_compound_bitops/case.ww b/test/wcc/data/r700_compound_bitops/case.ww new file mode 100644 index 00000000..700eb1fb --- /dev/null +++ b/test/wcc/data/r700_compound_bitops/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 96 +// Migrated from 700_e2e row 30. +package main; +fn main() i32 = { + let x: i32 = 100; + x &= 0x3f; x |= 0x80; x ^= 0xc4; + x *= 2; x <<= 1; x >>= 2; + return x; +}; diff --git a/test/wcc/data/r700_def_sentinel_err/case.ww b/test/wcc/data/r700_def_sentinel_err/case.ww new file mode 100644 index 00000000..8a89d605 --- /dev/null +++ b/test/wcc/data/r700_def_sentinel_err/case.ww @@ -0,0 +1,30 @@ +//ww:run-exit 19 +// Migrated from 700_e2e row 96. +package main; +type error = str; +def eEOF: error = "eof"; +def eShortRead: error = "short read"; +fn read(n: i64) (i64 | error) = { + if (n < 0) { return eEOF; }; + if (n == 0) { return eShortRead; }; + return n + 1; +}; +fn main() i32 = { + let r0: (i64 | error) = read(0); + let r1: (i64 | error) = read(-1); + let r2: (i64 | error) = read(5); + let acc: i32 = 0; + match (r0) { + case let v: i64 => acc += 100; + case let e: error => acc += e.len: i32; + }; + match (r1) { + case let v: i64 => acc += 100; + case let e: error => acc += e.len: i32; + }; + match (r2) { + case let v: i64 => acc += v: i32; + case let e: error => acc += 100; + }; + return acc; +}; diff --git a/test/wcc/data/r700_def_str_len/case.ww b/test/wcc/data/r700_def_str_len/case.ww new file mode 100644 index 00000000..ebd181cd --- /dev/null +++ b/test/wcc/data/r700_def_str_len/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 11 +// Migrated from 700_e2e row 111. +package main; +def MSG: str = "hello world"; +fn main() i32 = { return MSG.len: i32; }; diff --git a/test/wcc/data/r700_def_str_write/case.ww b/test/wcc/data/r700_def_str_write/case.ww new file mode 100644 index 00000000..ea2d167a --- /dev/null +++ b/test/wcc/data/r700_def_str_write/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 112. +package main; +import os; +def GREETING: str = "hi\n"; +fn main() i32 = { + os.write(1, GREETING.ptr, GREETING.len: u64); + return GREETING.len: i32; +}; diff --git a/test/wcc/data/r700_defer_implicit_ret/case.ww b/test/wcc/data/r700_defer_implicit_ret/case.ww new file mode 100644 index 00000000..57d409f9 --- /dev/null +++ b/test/wcc/data/r700_defer_implicit_ret/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 87 +// Migrated from 700_e2e row 63. +package main; +fn rec(p: *i32, c: i32) i32 = { + *p = *p * 10 + c; + return 0; +}; +fn run(p: *i32) void = { + defer rec(p, 7); + defer rec(p, 8); + // no explicit return — implicit fall-through path +}; +fn main() i32 = { + let acc: i32 = 0; + run(&acc); + return acc; +}; diff --git a/test/wcc/data/r700_defer_lifo_acc/case.ww b/test/wcc/data/r700_defer_lifo_acc/case.ww new file mode 100644 index 00000000..c73a7d2e --- /dev/null +++ b/test/wcc/data/r700_defer_lifo_acc/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 65 +// Migrated from 700_e2e row 62. +package main; +fn rec(p: *i32, c: i32) i32 = { + *p = *p * 10 + c; + return 0; +}; +fn main() i32 = { + let acc: i32 = 0; + defer rec(&acc, 1); + defer rec(&acc, 2); + defer rec(&acc, 3); + return acc; +}; diff --git a/test/wcc/data/r700_defer_lifo_syscall/case.ww b/test/wcc/data/r700_defer_lifo_syscall/case.ww new file mode 100644 index 00000000..a9919581 --- /dev/null +++ b/test/wcc/data/r700_defer_lifo_syscall/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 0 +// Migrated from 700_e2e row 13. +package main; +@symbol("rt_syscall") fn rt_syscall(num: i64, a: i64, b: i64, c: i64) i64; +fn out(c: i32) void = { rt_syscall(1, 1, (&c): i64, 1); }; +fn main() i32 = { + let c1: i32 = 0; + let c2: i32 = 0; + c1 = 65; + c2 = 66; + defer out(c1); + defer out(c2); + return 0; +}; diff --git a/test/wcc/data/r700_divmod_multiret/case.ww b/test/wcc/data/r700_divmod_multiret/case.ww new file mode 100644 index 00000000..e7a59efb --- /dev/null +++ b/test/wcc/data/r700_divmod_multiret/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 5 +// Migrated from 700_e2e row 5. +package main; +fn divmod(a: i64, b: i64) (i64, i64) = { return a / b, a % b; }; +fn main() i32 = { + let q, r = divmod(17, 5); + return (q + r): i32; +}; diff --git a/test/wcc/data/r700_enum_auto/case.ww b/test/wcc/data/r700_enum_auto/case.ww new file mode 100644 index 00000000..dd950ceb --- /dev/null +++ b/test/wcc/data/r700_enum_auto/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 2 +// Migrated from 700_e2e row 115. +package main; +type color = enum { RED, GREEN, BLUE }; +fn main() i32 = { return color.BLUE as i32; }; diff --git a/test/wcc/data/r700_enum_bitor/case.ww b/test/wcc/data/r700_enum_bitor/case.ww new file mode 100644 index 00000000..59b4ad34 --- /dev/null +++ b/test/wcc/data/r700_enum_bitor/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 117. +package main; +type mode = enum u8 { R = 1, W = 2 }; +fn main() i32 = { + let m: mode = mode.R | mode.W; + return m as i32; +}; diff --git a/test/wcc/data/r700_enum_cross_module/case.ww b/test/wcc/data/r700_enum_cross_module/case.ww new file mode 100644 index 00000000..21952ca1 --- /dev/null +++ b/test/wcc/data/r700_enum_cross_module/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 123. +package pkg; +export type base = enum i32 { DEC = 10, HEX = 16 }; +package main; +import pkg; +fn pick(b: pkg.base) i32 = { return b as i32; }; +fn main() i32 = { + let a: i32 = pick(pkg.base.DEC); + let b: i32 = pick(pkg.base.HEX); + return a + b + 16; +}; diff --git a/test/wcc/data/r700_enum_pkg_qual/case.ww b/test/wcc/data/r700_enum_pkg_qual/case.ww new file mode 100644 index 00000000..464b0a0a --- /dev/null +++ b/test/wcc/data/r700_enum_pkg_qual/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 1 +// Migrated from 700_e2e row 118. +package pkg; +type dir = enum { NORTH, SOUTH, EAST, WEST }; +package main; +import pkg; +fn main() i32 = { return pkg.dir.SOUTH as i32; }; diff --git a/test/wcc/data/r700_enum_u8_sibling/case.ww b/test/wcc/data/r700_enum_u8_sibling/case.ww new file mode 100644 index 00000000..d633dc76 --- /dev/null +++ b/test/wcc/data/r700_enum_u8_sibling/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 116. +package main; +type mode = enum u8 { R = 1, W = 2, RW = R | W }; +fn main() i32 = { + let m: mode = mode.RW; + return m as i32; +}; diff --git a/test/wcc/data/r700_error_alias_str/case.ww b/test/wcc/data/r700_error_alias_str/case.ww new file mode 100644 index 00000000..8dc7fc68 --- /dev/null +++ b/test/wcc/data/r700_error_alias_str/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 71. +package main; +type error = str; +fn read(n: i64) (i64 | error) = { + if (n < 0) { return "eof": error; }; + return n + 1; +}; +fn main() i32 = { + let r: (i64 | error) = read(-1); + match (r) { + case let v: i64 => return v: i32; + case let e: error => return e.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_errors_tags/case.ww b/test/wcc/data/r700_errors_tags/case.ww new file mode 100644 index 00000000..74db755c --- /dev/null +++ b/test/wcc/data/r700_errors_tags/case.ww @@ -0,0 +1,25 @@ +//ww:run-exit 11 +// Migrated from 700_e2e row 102. +package main; +import errors; +fn parse(n: i64) (i64 | errors.invalid | errors.noentry) = { + if (n < 0) { let e: errors.invalid; return e; }; + if (n == 0) { let e: errors.noentry; return e; }; + return n; +}; +fn main() i32 = { + let r1: (i64 | errors.invalid | errors.noentry) = parse(-1); + let r2: (i64 | errors.invalid | errors.noentry) = parse(0); + let acc: i32 = 0; + match (r1) { + case let v: i64 => acc += -100; + case let e: errors.invalid => acc += 1; + case let e: errors.noentry => acc += -100; + }; + match (r2) { + case let v: i64 => acc += -100; + case let e: errors.invalid => acc += -100; + case let e: errors.noentry => acc += 10; + }; + return acc; +}; diff --git a/test/wcc/data/r700_errors_tags_rest/case.ww b/test/wcc/data/r700_errors_tags_rest/case.ww new file mode 100644 index 00000000..646eea10 --- /dev/null +++ b/test/wcc/data/r700_errors_tags_rest/case.ww @@ -0,0 +1,22 @@ +//ww:run-exit 60 +// Migrated from 700_e2e row 103. +package main; +import errors; +fn classify(n: i32) (i32 | errors.noaccess | errors.exists | errors.unsupported) = { + if (n == 1) { let e: errors.noaccess; return e; }; + if (n == 2) { let e: errors.exists; return e; }; + if (n == 3) { let e: errors.unsupported; return e; }; + return n; +}; +fn dispatch(r: (i32 | errors.noaccess | errors.exists | errors.unsupported)) i32 = { + match (r) { + case let v: i32 => return v; + case let e: errors.noaccess => return 10; + case let e: errors.exists => return 20; + case let e: errors.unsupported => return 30; + }; + return -1; +}; +fn main() i32 = { + return dispatch(classify(1)) + dispatch(classify(2)) + dispatch(classify(3)); +}; diff --git a/test/wcc/data/r700_f32_add/case.ww b/test/wcc/data/r700_f32_add/case.ww new file mode 100644 index 00000000..f207df31 --- /dev/null +++ b/test/wcc/data/r700_f32_add/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 10 +// Migrated from 700_e2e row 15. +package main; +fn add32(a: f32, b: f32) f32 = { return a + b; }; +fn main() i32 = { + let r: f32 = add32(2.5: f32, 7.5: f32); + return r: i32; +}; diff --git a/test/wcc/data/r700_f64_area/case.ww b/test/wcc/data/r700_f64_area/case.ww new file mode 100644 index 00000000..ffe2b27c --- /dev/null +++ b/test/wcc/data/r700_f64_area/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 78 +// Migrated from 700_e2e row 7. +package main; +fn area(r: f64) f64 = { return 3.14 * r * r; }; +fn main() i32 = { let a: f64 = area(5.0); return a: i32; }; diff --git a/test/wcc/data/r700_f64_cmp/case.ww b/test/wcc/data/r700_f64_cmp/case.ww new file mode 100644 index 00000000..ac77f655 --- /dev/null +++ b/test/wcc/data/r700_f64_cmp/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 8. +package main; +fn main() i32 = { + let a: f64 = 1.5; + let b: f64 = 2.5; + if (a < b) { if (b > a) { return 7; }; }; + return 0; +}; diff --git a/test/wcc/data/r700_f64_compound_global/case.ww b/test/wcc/data/r700_f64_compound_global/case.ww new file mode 100644 index 00000000..a76d2310 --- /dev/null +++ b/test/wcc/data/r700_f64_compound_global/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 2 +// Migrated from 700_e2e row 120. +package main; +let G: f64 = 10.0; +fn main() i32 = { + G += 5.0; + G *= 2.0; + G -= 20.0; + G /= 5.0; + return G: i32; +}; diff --git a/test/wcc/data/r700_f64_compound_local/case.ww b/test/wcc/data/r700_f64_compound_local/case.ww new file mode 100644 index 00000000..2a03a267 --- /dev/null +++ b/test/wcc/data/r700_f64_compound_local/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 2 +// Migrated from 700_e2e row 119. +package main; +fn main() i32 = { + let a: f64 = 1.5; + a += 0.5; + a -= 1.0; + a *= 4.0; + a /= 2.0; + return a: i32; +}; diff --git a/test/wcc/data/r700_f64_eq/case.ww b/test/wcc/data/r700_f64_eq/case.ww new file mode 100644 index 00000000..db0cf2bf --- /dev/null +++ b/test/wcc/data/r700_f64_eq/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 11 +// Migrated from 700_e2e row 9. +package main; +fn main() i32 = { + let a: f64 = 3.14; + let b: f64 = 3.14; + if (a == b) { return 11; }; + return 0; +}; diff --git a/test/wcc/data/r700_fmt_println/case.ww b/test/wcc/data/r700_fmt_println/case.ww new file mode 100644 index 00000000..eea0410c --- /dev/null +++ b/test/wcc/data/r700_fmt_println/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 0 +// Migrated from 700_e2e row 25. +package main; +import fmt; +import strconv; +fn main() i32 = { + fmt.println("ww"); + fmt.println(strconv.i64tos(42, strconv.base.DEC)); + fmt.println(strconv.i64tos(-7, strconv.base.DEC)); + return 0; +}; diff --git a/test/wcc/data/r700_fmt_println_size/case.ww b/test/wcc/data/r700_fmt_println_size/case.ww new file mode 100644 index 00000000..a2bd8be6 --- /dev/null +++ b/test/wcc/data/r700_fmt_println_size/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 8 +// Migrated from 700_e2e row 132. +package main; +import fmt; +import io; +fn main() i32 = { + match (fmt.println("hello", 7i64)) { + case let n: size => return n: i32; + case let _e: io.error => return -1; + }; +}; diff --git a/test/wcc/data/r700_fnptr_indirect/case.ww b/test/wcc/data/r700_fnptr_indirect/case.ww new file mode 100644 index 00000000..f5ccd1f8 --- /dev/null +++ b/test/wcc/data/r700_fnptr_indirect/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 10. +package main; +fn add(a: i32, b: i32) i32 = { return a + b; }; +fn main() i32 = { + let fp: fn(a: i32, b: i32) i32 = add; + return fp(20, 22); +}; diff --git a/test/wcc/data/r700_for_range/case.ww b/test/wcc/data/r700_for_range/case.ww new file mode 100644 index 00000000..2ccdb3c8 --- /dev/null +++ b/test/wcc/data/r700_for_range/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 100 +// Migrated from 700_e2e row 35. +package main; +import os; +fn main() i32 = { + let s: []u8; + s.ptr = nil; s.len = 0; s.cap = 0; + append(s, 10u8, 20u8, 30u8, 40u8); + let total: i32 = 0; + for (let b .. s) { total += b: i32; }; + return total; +}; diff --git a/test/wcc/data/r700_for_sum/case.ww b/test/wcc/data/r700_for_sum/case.ww new file mode 100644 index 00000000..b89c2054 --- /dev/null +++ b/test/wcc/data/r700_for_sum/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 45 +// Migrated from 700_e2e row 2. +package main; +fn main() i32 = { + let i: i32 = 0; + let s: i32 = 0; + for (i < 10) { s += i; i += 1; }; + return s; +}; diff --git a/test/wcc/data/r700_global_arr_addr/case.ww b/test/wcc/data/r700_global_arr_addr/case.ww new file mode 100644 index 00000000..a5c8f15a --- /dev/null +++ b/test/wcc/data/r700_global_arr_addr/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 122. +package main; +let buf: [4]u8; +fn main() i32 = { + let p: *u8 = &buf[0]; + *p = 41u8; + let q: *u8 = &buf[1]; + *q = 1u8; + return (buf[0] + buf[1]): i32; +}; diff --git a/test/wcc/data/r700_global_arr_u8/case.ww b/test/wcc/data/r700_global_arr_u8/case.ww new file mode 100644 index 00000000..72caa543 --- /dev/null +++ b/test/wcc/data/r700_global_arr_u8/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 121. +package main; +let buf: [4]u8; +fn main() i32 = { + buf[0] = 7u8; + buf[1] = 35u8; + return (buf[0] + buf[1]): i32; +}; diff --git a/test/wcc/data/r700_if_gt/case.ww b/test/wcc/data/r700_if_gt/case.ww new file mode 100644 index 00000000..cdb673fc --- /dev/null +++ b/test/wcc/data/r700_if_gt/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 1 +// Migrated from 700_e2e row 3. +package main; +fn main() i32 = { + let x: i32 = 100; + if (x > 50) { return 1; }; + return 0; +}; diff --git a/test/wcc/data/r700_is_as_scalar/case.ww b/test/wcc/data/r700_is_as_scalar/case.ww new file mode 100644 index 00000000..7736887f --- /dev/null +++ b/test/wcc/data/r700_is_as_scalar/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 49 +// Migrated from 700_e2e row 113. +package main; +fn classify(n: i64) (i64 | i32) = { + if (n < 0) { return 7: i32; }; + return n; +}; +fn main() i32 = { + let ok: (i64 | i32) = classify(40); + let bad: (i64 | i32) = classify(-1); + let s: i32 = 0; + if (ok is i64) { s += 1; }; + if (bad is i32) { s += 1; }; + if (ok is i32) { s += 100; }; + if (bad is i64) { s += 100; }; + let v: i64 = ok as i64; + let e: i32 = bad as i32; + return (v: i32) + s + e; +}; diff --git a/test/wcc/data/r700_match_call_expr/case.ww b/test/wcc/data/r700_match_call_expr/case.ww new file mode 100644 index 00000000..268cf840 --- /dev/null +++ b/test/wcc/data/r700_match_call_expr/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 78. +package main; +fn make(n: i64) (i64 | str) = { + if (n < 0) { return "neg"; }; + return n + 1; +}; +fn main() i32 = { + match (make(-1)) { + case let v: i64 => return v: i32; + case let e: str => return e.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_match_default_arm/case.ww b/test/wcc/data/r700_match_default_arm/case.ww new file mode 100644 index 00000000..22af374b --- /dev/null +++ b/test/wcc/data/r700_match_default_arm/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 54. +package main; +fn parse(n: i64) (i64 | i32) = { + if (n < 0) { return 1: i32; }; + return n; +}; +fn main() i32 = { + let r: (i64 | i32) = parse(-1); + match (r) { + case let v: i64 => return 1; + case => return 7; + }; + return 0; +}; diff --git a/test/wcc/data/r700_match_rev_order/case.ww b/test/wcc/data/r700_match_rev_order/case.ww new file mode 100644 index 00000000..1b4377be --- /dev/null +++ b/test/wcc/data/r700_match_rev_order/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 50. +package main; +fn parse(n: i64) (i64 | i32) = { + if (n < 0) { return 7: i32; }; + return n; +}; +fn main() i32 = { + let r: (i64 | i32) = parse(-1); + match (r) { + case let e: i32 => return e; + case let v: i64 => return (v + 1000): i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_match_unbound_case/case.ww b/test/wcc/data/r700_match_unbound_case/case.ww new file mode 100644 index 00000000..b7e7e853 --- /dev/null +++ b/test/wcc/data/r700_match_unbound_case/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 40 +// Migrated from 700_e2e row 55. +package main; +fn parse(n: i64) (i64 | i32) = { + if (n < 0) { return 1: i32; }; + return n; +}; +fn main() i32 = { + let r: (i64 | i32) = parse(40); + match (r) { + case i32 => return 1; + case let v: i64 => return v: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_match_yield_i32/case.ww b/test/wcc/data/r700_match_yield_i32/case.ww new file mode 100644 index 00000000..a165df85 --- /dev/null +++ b/test/wcc/data/r700_match_yield_i32/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 8 +// Migrated from 700_e2e row 64. +package main; +fn pick(b: bool) (i32 | str) = { + if (b) { return 7; }; + return "abc"; +}; +fn main() i32 = { + let r: (i32 | str) = pick(true); + let v: i32 = match (r) { + case let n: i32 => yield n + 1; + case let s: str => yield s.len: i32 + 100; + }; + return v; +}; diff --git a/test/wcc/data/r700_match_yield_str/case.ww b/test/wcc/data/r700_match_yield_str/case.ww new file mode 100644 index 00000000..2015b124 --- /dev/null +++ b/test/wcc/data/r700_match_yield_str/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 103 +// Migrated from 700_e2e row 65. +package main; +fn pick(b: bool) (i32 | str) = { + if (b) { return 7; }; + return "abc"; +}; +fn main() i32 = { + let r: (i32 | str) = pick(false); + let v: i32 = match (r) { + case let n: i32 => yield n + 1; + case let s: str => yield s.len: i32 + 100; + }; + return v; +}; diff --git a/test/wcc/data/r700_mul_locals/case.ww b/test/wcc/data/r700_mul_locals/case.ww new file mode 100644 index 00000000..f4157da6 --- /dev/null +++ b/test/wcc/data/r700_mul_locals/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 4. +package main; +fn main() i32 = { + let a: i32 = 6; + let b: i32 = 7; + return a * b; +}; diff --git a/test/wcc/data/r700_nullable_arr_elems/case.ww b/test/wcc/data/r700_nullable_arr_elems/case.ww new file mode 100644 index 00000000..b48b21a3 --- /dev/null +++ b/test/wcc/data/r700_nullable_arr_elems/case.ww @@ -0,0 +1,24 @@ +//ww:run-exit 201 +// Migrated from 700_e2e row 95. +package main; +fn pickptr(b: bool) *i32 = { + let x: i32 = 42; + if (b) { return &x; }; + return nil; +}; +fn main() i32 = { + let arr: [3](*i32 | void); + arr[0] = nil; + arr[1] = pickptr(true); + arr[2] = pickptr(false); + let s: i32 = 0; + let i: i32 = 0; + for (i < 3) { + match (arr[i]) { + case let p: *i32 => s += 1; + case => s += 100; + }; + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_nullable_is_as/case.ww b/test/wcc/data/r700_nullable_is_as/case.ww new file mode 100644 index 00000000..b7d2c0e2 --- /dev/null +++ b/test/wcc/data/r700_nullable_is_as/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 67. +package main; +fn lookup(p: *i32, b: bool) (*i32 | void) = { + if (b) { return p; }; + return; +}; +fn main() i32 = { + let x: i32 = 42; + let r1: (*i32 | void) = lookup(&x, true); + let r2: (*i32 | void) = lookup(&x, false); + let acc: i32 = 0; + if (r1 is *i32) { acc += 1; }; + if (r2 is void) { acc += 2; }; + let p: *i32 = r1 as *i32; + if (*p == 42) { acc += 4; }; + return acc; +}; diff --git a/test/wcc/data/r700_nullable_match/case.ww b/test/wcc/data/r700_nullable_match/case.ww new file mode 100644 index 00000000..06a18cde --- /dev/null +++ b/test/wcc/data/r700_nullable_match/case.ww @@ -0,0 +1,22 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 66. +package main; +fn lookup(p: *i32, b: bool) (*i32 | void) = { + if (b) { return p; }; + return; +}; +fn use_arg(r: (*i32 | void)) i32 = { + match (r) { + case let q: *i32 => return *q; + case void => return 99; + }; + return 0; +}; +fn main() i32 = { + let x: i32 = 42; + let ok: i32 = use_arg(lookup(&x, true)); + let no: i32 = use_arg(lookup(&x, false)); + if (ok != 42) { return 1; }; + if (no != 99) { return 2; }; + return 7; +}; diff --git a/test/wcc/data/r700_oror_rhs/case.ww b/test/wcc/data/r700_oror_rhs/case.ww new file mode 100644 index 00000000..965f57dd --- /dev/null +++ b/test/wcc/data/r700_oror_rhs/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 136. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let pt: point = point { x = 7, y = 0 }; + let p: *point = &pt; + if (p == nil || p.x > 0) { return 42; }; + return 1; +}; diff --git a/test/wcc/data/r700_oror_short/case.ww b/test/wcc/data/r700_oror_short/case.ww new file mode 100644 index 00000000..4c6cc8f0 --- /dev/null +++ b/test/wcc/data/r700_oror_short/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 134. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let p: *point = nil; + if (p == nil || p.x > 0) { return 42; }; + return 1; +}; diff --git a/test/wcc/data/r700_os_trywrite/case.ww b/test/wcc/data/r700_os_trywrite/case.ww new file mode 100644 index 00000000..661a3116 --- /dev/null +++ b/test/wcc/data/r700_os_trywrite/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 10 +// Migrated from 700_e2e row 97. +package main; +import os; +fn main() i32 = { + let buf: [3]u8; + buf[0] = 88: u8; + let ok: (i64 | os.oserror) = os.trywrite(1, buf.ptr, 1u64); + let bad: (i64 | os.oserror) = os.trywrite(999: i32, buf.ptr, 1u64); + let acc: i32 = 0; + match (ok) { + case let n: i64 => acc += n: i32; + case let e: os.oserror => acc += -100; + }; + match (bad) { + case let n: i64 => acc += -100; + case let e: os.oserror => acc += (- (e: i64)): i32; + }; + return acc; +}; diff --git a/test/wcc/data/r700_os_write/case.ww b/test/wcc/data/r700_os_write/case.ww new file mode 100644 index 00000000..90acdf9d --- /dev/null +++ b/test/wcc/data/r700_os_write/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 17. +package main; +import os; +fn main() i32 = { return os.write(1, "ok\n".ptr, 3): i32; }; diff --git a/test/wcc/data/r700_ptr_struct_move/case.ww b/test/wcc/data/r700_ptr_struct_move/case.ww new file mode 100644 index 00000000..079259de --- /dev/null +++ b/test/wcc/data/r700_ptr_struct_move/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 28. +package main; +type point = struct { x: i32, y: i32 }; +fn move(p: *point, dx: i32, dy: i32) void = { + p.x += dx; p.y += dy; +}; +fn main() i32 = { + let pt: point = point { x = 0, y = 0 }; + move(&pt, 3, 4); + return pt.x + pt.y; +}; diff --git a/test/wcc/data/r700_ret_const/case.ww b/test/wcc/data/r700_ret_const/case.ww new file mode 100644 index 00000000..375f16cc --- /dev/null +++ b/test/wcc/data/r700_ret_const/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 0. +package main; +fn main() i32 = { return 42; }; diff --git a/test/wcc/data/r700_rt_malloc_free/case.ww b/test/wcc/data/r700_rt_malloc_free/case.ww new file mode 100644 index 00000000..bbe51252 --- /dev/null +++ b/test/wcc/data/r700_rt_malloc_free/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 0 +// Migrated from 700_e2e row 20. +package main; +import os; +import rt; +fn main() i32 = { + let p: *void = rt.malloc(4096u64); + if (p == nil) { return 1; }; + let bp: *u8 = p: *u8; + bp[0] = 65u8; + os.write(1, bp, 1u64); + os.free(p, 4096u64); + return 0; +}; diff --git a/test/wcc/data/r700_shortcircuit_bool/case.ww b/test/wcc/data/r700_shortcircuit_bool/case.ww new file mode 100644 index 00000000..dc6b7c65 --- /dev/null +++ b/test/wcc/data/r700_shortcircuit_bool/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 138. +package main; +fn main() i32 = { + let a: bool = (1 > 0) && (2 < 1); + let b: bool = (1 < 0) || (2 > 1); + let n: i32 = 0; + if (!a) { n += 10; }; + if (b) { n += 32; }; + return n; +}; diff --git a/test/wcc/data/r700_slice_from_array/case.ww b/test/wcc/data/r700_slice_from_array/case.ww new file mode 100644 index 00000000..4516e405 --- /dev/null +++ b/test/wcc/data/r700_slice_from_array/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 60 +// Migrated from 700_e2e row 16. +package main; +fn main() i32 = { + let arr: [4]u8; + arr[0] = 10: u8; arr[1] = 20: u8; + arr[2] = 30: u8; arr[3] = 99: u8; + let s: []u8 = arr[0:3]; + let sum: i32 = 0; + let i: i32 = 0; + for (i < s.len) { sum += s[i]: i32; i += 1; }; + return sum; +}; diff --git a/test/wcc/data/r700_static_append/case.ww b/test/wcc/data/r700_static_append/case.ww new file mode 100644 index 00000000..4a373ca3 --- /dev/null +++ b/test/wcc/data/r700_static_append/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 4 +// Migrated from 700_e2e row 33. +package main; +import os; +fn main() i32 = { + let s: []u8; + s.ptr = nil; s.len = 0; s.cap = 0; + static append(s, 72u8, 105u8, 33u8, 10u8); + os.write(1, s.ptr, len(s): u64); + return len(s); +}; diff --git a/test/wcc/data/r700_str_eq/case.ww b/test/wcc/data/r700_str_eq/case.ww new file mode 100644 index 00000000..cd18e399 --- /dev/null +++ b/test/wcc/data/r700_str_eq/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 30 +// Migrated from 700_e2e row 27. +package main; +fn main() i32 = { + let a: str = "hello"; + let b: str = "hello"; + let c: str = "world"; + let n: i32 = 0; + if (a == b) { n += 10; }; + if (a != c) { n += 20; }; + return n; +}; diff --git a/test/wcc/data/r700_strconv_i64tos/case.ww b/test/wcc/data/r700_strconv_i64tos/case.ww new file mode 100644 index 00000000..c398e46d --- /dev/null +++ b/test/wcc/data/r700_strconv_i64tos/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 5 +// Migrated from 700_e2e row 19. +package main; +import os; +import strconv; +fn main() i32 = { + let s: str = strconv.i64tos(12345, strconv.base.DEC); + os.write(1, s.ptr, s.len: u64); + os.write(1, "\n".ptr, 1u64); + return s.len; +}; diff --git a/test/wcc/data/r700_strconv_stoi64/case.ww b/test/wcc/data/r700_strconv_stoi64/case.ww new file mode 100644 index 00000000..dfe58abf --- /dev/null +++ b/test/wcc/data/r700_strconv_stoi64/case.ww @@ -0,0 +1,27 @@ +//ww:run-exit 35 +// Migrated from 700_e2e row 98. +package main; +import strconv; +type r_t = (i64 | strconv.invalid | strconv.overflow); +fn main() i32 = { + let r1: r_t = strconv.stoi64("42", strconv.base.DEC); + let r2: r_t = strconv.stoi64("-7", strconv.base.DEC); + let r3: r_t = strconv.stoi64("abc", strconv.base.DEC); + let acc: i32 = 0; + match (r1) { + case let v: i64 => acc += v: i32; + case let e: strconv.invalid => acc += -100; + case let e: strconv.overflow => acc += -200; + }; + match (r2) { + case let v: i64 => acc += v: i32; + case let e: strconv.invalid => acc += -100; + case let e: strconv.overflow => acc += -200; + }; + match (r3) { + case let v: i64 => acc += -100; + case let e: strconv.invalid => acc += e: i32; + case let e: strconv.overflow => acc += -200; + }; + return acc; +}; diff --git a/test/wcc/data/r700_strconv_stou64/case.ww b/test/wcc/data/r700_strconv_stou64/case.ww new file mode 100644 index 00000000..274f796b --- /dev/null +++ b/test/wcc/data/r700_strconv_stou64/case.ww @@ -0,0 +1,21 @@ +//ww:run-exit 130 +// Migrated from 700_e2e row 99. +package main; +import strconv; +type r_t = (u64 | strconv.invalid | strconv.overflow); +fn main() i32 = { + let r1: r_t = strconv.stou64("123", strconv.base.DEC); + let r2: r_t = strconv.stou64("-1", strconv.base.DEC); + let acc: i32 = 0; + match (r1) { + case let v: u64 => acc += v: i32; + case let e: strconv.invalid => acc += -100; + case let e: strconv.overflow => acc += -200; + }; + match (r2) { + case let v: u64 => acc += 100; + case let e: strconv.invalid => acc += 200; + case let e: strconv.overflow => acc += 7; + }; + return acc; +}; diff --git a/test/wcc/data/r700_strings_byteindex/case.ww b/test/wcc/data/r700_strings_byteindex/case.ww new file mode 100644 index 00000000..dc6d85ab --- /dev/null +++ b/test/wcc/data/r700_strings_byteindex/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 10 +// Migrated from 700_e2e row 100. +package main; +import strings; +fn pick(r: (i32 | void), miss: i32) i32 = { + match (r) { + case let i: i32 => return i; + case void => return miss; + }; + return 0; +}; +fn main() i32 = { + let s: str = "hello, world"; + let i1: i32 = pick(strings.byteindex(s, ','), -1); + let i2: i32 = pick(strings.byteindex(s, 'z'), -1); + let i3: i32 = pick(strings.byteindex(s, "world"), -1); + let i4: i32 = pick(strings.byteindex(s, "nope"), -1); + return i1 + i2 + i3 + i4; +}; diff --git a/test/wcc/data/r700_strings_concat/case.ww b/test/wcc/data/r700_strings_concat/case.ww new file mode 100644 index 00000000..a125af4b --- /dev/null +++ b/test/wcc/data/r700_strings_concat/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 12 +// Migrated from 700_e2e row 32. +package main; +import strings; +import fmt; +fn main() i32 = { + let r: str = strings.concat("hello, ", "world"); + fmt.println(r); + return r.len; +}; diff --git a/test/wcc/data/r700_struct_byval/case.ww b/test/wcc/data/r700_struct_byval/case.ww new file mode 100644 index 00000000..327cca20 --- /dev/null +++ b/test/wcc/data/r700_struct_byval/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 14. +package main; +type pair = struct { a: i64, b: i64 }; +fn sum(p: pair) i64 = { return p.a + p.b; }; +fn main() i32 = { + let p: pair = pair { a = 10, b = 32 }; + return sum(p): i32; +}; diff --git a/test/wcc/data/r700_struct_embed/case.ww b/test/wcc/data/r700_struct_embed/case.ww new file mode 100644 index 00000000..63024e10 --- /dev/null +++ b/test/wcc/data/r700_struct_embed/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 46. +package main; +type point = struct { x: i32, y: i32 }; +type vec = struct { + point, + struct { z: i32 }, + w: i32, +}; +fn main() i32 = { + let v: vec = vec { x = 1, y = 2, z = 3, w = 36 }; + return v.x + v.y + v.z + v.w; +}; diff --git a/test/wcc/data/r700_struct_i32_fields/case.ww b/test/wcc/data/r700_struct_i32_fields/case.ww new file mode 100644 index 00000000..fa08a822 --- /dev/null +++ b/test/wcc/data/r700_struct_i32_fields/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 25 +// Migrated from 700_e2e row 26. +package main; +type point = struct { x: i32, y: i32 }; +fn distsq(p: point) i32 = { return p.x * p.x + p.y * p.y; }; +fn main() i32 = { + let p: point = point { x = 3, y = 4 }; + return distsq(p); +}; diff --git a/test/wcc/data/r700_sum_param_str_rune/case.ww b/test/wcc/data/r700_sum_param_str_rune/case.ww new file mode 100644 index 00000000..22dc97d7 --- /dev/null +++ b/test/wcc/data/r700_sum_param_str_rune/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 124. +package main; +fn pick(n: (str | rune)) i32 = { + match (n) { + case let s: str => return s.len + 100; + case let r: rune => return r: i32; + }; +}; +fn main() i32 = { + let a: i32 = pick("hi"); + let b: i32 = pick('?'); + return a + b - 123; +}; diff --git a/test/wcc/data/r700_sum_param_u8_slice/case.ww b/test/wcc/data/r700_sum_param_u8_slice/case.ww new file mode 100644 index 00000000..2d1d42f9 --- /dev/null +++ b/test/wcc/data/r700_sum_param_u8_slice/case.ww @@ -0,0 +1,23 @@ +//ww:run-exit 40 +// Migrated from 700_e2e row 125. +package main; +import bytes; +fn main() i32 = { + let buf: [4]u8; + buf[0] = 1u8; buf[1] = 2u8; buf[2] = 3u8; buf[3] = 4u8; + let needle: [2]u8; + needle[0] = 3u8; needle[1] = 4u8; + let r1: (i32 | void) = bytes.index(buf[0:4], 3u8); + let r2: (i32 | void) = bytes.index(buf[0:4], needle[0:2]); + let a: i32 = 99; + let b: i32 = 99; + match (r1) { + case let i: i32 => a = i; + case void => a = -1; + }; + match (r2) { + case let i: i32 => b = i; + case void => b = -1; + }; + return a * 10 + b + 18; +}; diff --git a/test/wcc/data/r700_switch_multi/case.ww b/test/wcc/data/r700_switch_multi/case.ww new file mode 100644 index 00000000..ec0c43d7 --- /dev/null +++ b/test/wcc/data/r700_switch_multi/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 159 +// Migrated from 700_e2e row 24. +package main; +fn classify(x: i32) i32 = { + switch (x) { + case 1, 2, 3: return 10; + case 10: return 99; + case: return 50; + }; + return -1; +}; +fn main() i32 = { + return classify(2) + classify(10) + classify(99); +}; diff --git a/test/wcc/data/r700_syscall_write/case.ww b/test/wcc/data/r700_syscall_write/case.ww new file mode 100644 index 00000000..b488d77d --- /dev/null +++ b/test/wcc/data/r700_syscall_write/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 13 +// Migrated from 700_e2e row 11. +package main; +@symbol("rt_syscall") fn rt_syscall(num: i64, a: i64, b: i64, c: i64) i64; +fn print(s: str) i64 = { return rt_syscall(1, 1, s.ptr: i64, s.len: i64); }; +fn main() i32 = { return print("hello, world\n"): i32; }; diff --git a/test/wcc/data/r700_tagged24_arg/case.ww b/test/wcc/data/r700_tagged24_arg/case.ww new file mode 100644 index 00000000..c0f6d0fa --- /dev/null +++ b/test/wcc/data/r700_tagged24_arg/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 6 +// Migrated from 700_e2e row 74. +package main; +type result = (i64 | str); +fn classify(r: result) i32 = { + match (r) { + case let v: i64 => return 1; + case let e: str => return e.len: i32; + }; + return -1; +}; +fn main() i32 = { + let r1: result = "hello"; + let r2: result = 42; + return classify(r1) + classify(r2); +}; diff --git a/test/wcc/data/r700_tagged_alias_arr/case.ww b/test/wcc/data/r700_tagged_alias_arr/case.ww new file mode 100644 index 00000000..b3aed2a4 --- /dev/null +++ b/test/wcc/data/r700_tagged_alias_arr/case.ww @@ -0,0 +1,21 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 127. +package main; +type formattable = (i64 | str | bool); +fn main() i32 = { + let args: [3]formattable; + args[0] = 1i64: formattable; + args[1] = "hi": formattable; + args[2] = true: formattable; + let s: i32 = 0; + let i: i32 = 0; + for (i < args.len) { + match (args[i]) { + case let n: i64 => s += n: i32; + case let v: str => s += v.len; + case let b: bool => { if (b) { s += 39; }; }; + }; + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_tagged_arr_elems/case.ww b/test/wcc/data/r700_tagged_arr_elems/case.ww new file mode 100644 index 00000000..e3e02b4e --- /dev/null +++ b/test/wcc/data/r700_tagged_arr_elems/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 17 +// Migrated from 700_e2e row 88. +package main; +fn main() i32 = { + let arr: [3](i32 | str); + arr[0] = 10; + arr[1] = "hi"; + arr[2] = 5; + let s: i32 = 0; + let i: i32 = 0; + for (i < 3) { + match (arr[i]) { + case let v: i32 => s += v; + case let t: str => s += t.len: i32; + }; + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_tagged_arr_struct/case.ww b/test/wcc/data/r700_tagged_arr_struct/case.ww new file mode 100644 index 00000000..7e70d1b5 --- /dev/null +++ b/test/wcc/data/r700_tagged_arr_struct/case.ww @@ -0,0 +1,22 @@ +//ww:run-exit 34 +// Migrated from 700_e2e row 89. +package main; +type pair = struct { a: i32, b: i32 }; +fn main() i32 = { + let arr: [4](i32 | pair | str); + arr[0] = 5; + arr[1] = pair { a = 7, b = 11 }; + arr[2] = "yo"; + arr[3] = 9; + let s: i32 = 0; + let i: i32 = 0; + for (i < 4) { + match (arr[i]) { + case let v: i32 => s += v; + case let p: pair => s += p.a + p.b; + case let t: str => s += t.len: i32; + }; + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_tagged_assign_synth/case.ww b/test/wcc/data/r700_tagged_assign_synth/case.ww new file mode 100644 index 00000000..a656727e --- /dev/null +++ b/test/wcc/data/r700_tagged_assign_synth/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 9 +// Migrated from 700_e2e row 53. +package main; +fn main() i32 = { + let r: (i64 | i32) = 0; + r = 9: i32; + match (r) { + case let v: i64 => return 1; + case let e: i32 => return e; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_elem_arg/case.ww b/test/wcc/data/r700_tagged_elem_arg/case.ww new file mode 100644 index 00000000..f1a653d2 --- /dev/null +++ b/test/wcc/data/r700_tagged_elem_arg/case.ww @@ -0,0 +1,23 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 91. +package main; +fn weight(v: (i32 | str)) i32 = { + match (v) { + case let n: i32 => return n; + case let s: str => return s.len: i32 * 10; + }; + return 0; +}; +fn main() i32 = { + let arr: [3](i32 | str); + arr[0] = 5; + arr[1] = "abc"; + arr[2] = 7; + let s: i32 = 0; + let i: i32 = 0; + for (i < 3) { + s += weight(arr[i]); + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_tagged_elem_let/case.ww b/test/wcc/data/r700_tagged_elem_let/case.ww new file mode 100644 index 00000000..7ac8bcf4 --- /dev/null +++ b/test/wcc/data/r700_tagged_elem_let/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 92. +package main; +fn main() i32 = { + let arr: [3](i32 | str); + arr[0] = 11; + arr[1] = "ww!"; + arr[2] = 7; + let r: (i32 | str) = arr[1]; + match (r) { + case let n: i32 => return n; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_elem_ret/case.ww b/test/wcc/data/r700_tagged_elem_ret/case.ww new file mode 100644 index 00000000..8324b462 --- /dev/null +++ b/test/wcc/data/r700_tagged_elem_ret/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 94. +package main; +fn pick(i: i32) (i32 | str) = { + let arr: [2](i32 | str); + arr[0] = 21; + arr[1] = "abc"; + return arr[i]; +}; +fn main() i32 = { + let r: (i32 | str) = pick(1); + match (r) { + case let n: i32 => return n; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_forward_ret/case.ww b/test/wcc/data/r700_tagged_forward_ret/case.ww new file mode 100644 index 00000000..2a32503a --- /dev/null +++ b/test/wcc/data/r700_tagged_forward_ret/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 77. +package main; +type result = (i64 | str); +fn inner(n: i64) result = { + if (n < 0) { return "neg"; }; + return n + 1; +}; +fn outer(n: i64) result = { + return inner(n); +}; +fn main() i32 = { + let r: result = outer(-1); + match (r) { + case let v: i64 => return v: i32; + case let e: str => return e.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_match/case.ww b/test/wcc/data/r700_tagged_match/case.ww new file mode 100644 index 00000000..acc17b1a --- /dev/null +++ b/test/wcc/data/r700_tagged_match/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 48. +package main; +fn parse(n: i64) (i64 | i32) = { + if (n < 0) { return 1: i32; }; + return n; +}; +fn main() i32 = { + let r: (i64 | i32) = parse(40); + let s: i64 = 0; + match (r) { + case let v: i64 => s = v; + case let e: i32 => s = -1; + }; + return (s + 2): i32; +}; diff --git a/test/wcc/data/r700_tagged_ptr_variant/case.ww b/test/wcc/data/r700_tagged_ptr_variant/case.ww new file mode 100644 index 00000000..aeaff751 --- /dev/null +++ b/test/wcc/data/r700_tagged_ptr_variant/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 76. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let p: point = point { x = 3, y = 4 }; + let r: (*point | str) = &p; + match (r) { + case let pp: *point => return pp.x + pp.y; + case let e: str => return -1; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_slice_elems/case.ww b/test/wcc/data/r700_tagged_slice_elems/case.ww new file mode 100644 index 00000000..6f13814a --- /dev/null +++ b/test/wcc/data/r700_tagged_slice_elems/case.ww @@ -0,0 +1,21 @@ +//ww:run-exit 10 +// Migrated from 700_e2e row 90. +package main; +fn main() i32 = { + let buf: [4](i32 | str); + buf[0] = 1; + buf[1] = "ww"; + buf[2] = 3; + buf[3] = 4; + let xs: [](i32 | str) = buf[0:4]; + let s: i32 = 0; + let i: i32 = 0; + for (i < 4) { + match (xs[i]) { + case let v: i32 => s += v; + case let t: str => s += t.len: i32; + }; + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_tagged_slice_ret/case.ww b/test/wcc/data/r700_tagged_slice_ret/case.ww new file mode 100644 index 00000000..22b72501 --- /dev/null +++ b/test/wcc/data/r700_tagged_slice_ret/case.ww @@ -0,0 +1,21 @@ +//ww:run-exit 60 +// Migrated from 700_e2e row 126. +package main; +type rterr = !str; +fn build(n: i32) ([]u8 | rterr) = { + if (n < 0) { return "bad": rterr; }; + let buf: [4]u8; + buf[0] = 10u8; buf[1] = 20u8; buf[2] = 30u8; buf[3] = 40u8; + return buf[0:n]; +}; +fn main() i32 = { + let r: ([]u8 | rterr) = build(3); + match (r) { + case let xs: []u8 => { + if (xs.len != 3) { return 100; }; + return (xs[0] + xs[1] + xs[2]): i32; + }; + case let e: rterr => return -1; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_spread_type/case.ww b/test/wcc/data/r700_tagged_spread_type/case.ww new file mode 100644 index 00000000..0a38599f --- /dev/null +++ b/test/wcc/data/r700_tagged_spread_type/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 87. +package main; +type inner = (i32 | rune); +type outer = (...inner | str); +fn main() i32 = { + let r: outer = 42: i32; + match (r) { + case let n: i32 => return n; + case let c: rune => return c: i32; + case let s: str => return 0; + }; + return -1; +}; diff --git a/test/wcc/data/r700_tagged_str_assign/case.ww b/test/wcc/data/r700_tagged_str_assign/case.ww new file mode 100644 index 00000000..dceee403 --- /dev/null +++ b/test/wcc/data/r700_tagged_str_assign/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 58. +package main; +fn main() i32 = { + let r: (i64 | str) = 0; + r = "abc"; + match (r) { + case let n: i64 => return 1; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_str_letinit/case.ww b/test/wcc/data/r700_tagged_str_letinit/case.ww new file mode 100644 index 00000000..eff85c08 --- /dev/null +++ b/test/wcc/data/r700_tagged_str_letinit/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 12 +// Migrated from 700_e2e row 57. +package main; +fn main() i32 = { + let r: (i64 | str) = "hello, world"; + match (r) { + case let n: i64 => return 1; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_str_ret/case.ww b/test/wcc/data/r700_tagged_str_ret/case.ww new file mode 100644 index 00000000..5c068279 --- /dev/null +++ b/test/wcc/data/r700_tagged_str_ret/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 15 +// Migrated from 700_e2e row 59. +package main; +fn parse(n: i64) (i64 | str) = { + if (n < 0) { return "negative number"; }; + return n; +}; +fn main() i32 = { + let r: (i64 | str) = parse(-1); + match (r) { + case let n: i64 => return 1; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_struct_field/case.ww b/test/wcc/data/r700_tagged_struct_field/case.ww new file mode 100644 index 00000000..ddb98399 --- /dev/null +++ b/test/wcc/data/r700_tagged_struct_field/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 75. +package main; +type point = struct { + x: i32, + err: (i64 | str), +}; +fn main() i32 = { + let p: point = point { x = 1, err = 0 }; + p.err = "updated"; + match (p.err) { + case let v: i64 => return 0; + case let e: str => return e.len: i32; + }; + return -1; +}; diff --git a/test/wcc/data/r700_tagged_struct_local_arg/case.ww b/test/wcc/data/r700_tagged_struct_local_arg/case.ww new file mode 100644 index 00000000..051d562c --- /dev/null +++ b/test/wcc/data/r700_tagged_struct_local_arg/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 33 +// Migrated from 700_e2e row 80. +package main; +type point = struct { x: i32, y: i32 }; +fn classify(r: (str | point)) i32 = { + match (r) { + case let s: str => return 0 - s.len: i32; + case let p: point => return p.x + p.y; + }; + return -1; +}; +fn main() i32 = { + let p: point = point { x = 11, y = 22 }; + return classify(p); +}; diff --git a/test/wcc/data/r700_tagged_structlit_arg/case.ww b/test/wcc/data/r700_tagged_structlit_arg/case.ww new file mode 100644 index 00000000..234607f9 --- /dev/null +++ b/test/wcc/data/r700_tagged_structlit_arg/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 30 +// Migrated from 700_e2e row 79. +package main; +type point = struct { x: i32, y: i32 }; +fn classify(r: (str | point)) i32 = { + match (r) { + case let s: str => return 0 - s.len: i32; + case let p: point => return p.x + p.y; + }; + return -1; +}; +fn main() i32 = { + return classify(point { x = 10, y = 20 }); +}; diff --git a/test/wcc/data/r700_tagged_structlit_assign/case.ww b/test/wcc/data/r700_tagged_structlit_assign/case.ww new file mode 100644 index 00000000..92c3fa69 --- /dev/null +++ b/test/wcc/data/r700_tagged_structlit_assign/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 123 +// Migrated from 700_e2e row 82. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let r: (str | point) = "init"; + r = point { x = 100, y = 23 }; + match (r) { + case let s: str => return 0 - s.len: i32; + case let p: point => return p.x + p.y; + }; + return -1; +}; diff --git a/test/wcc/data/r700_tagged_structlit_let/case.ww b/test/wcc/data/r700_tagged_structlit_let/case.ww new file mode 100644 index 00000000..9e99676e --- /dev/null +++ b/test/wcc/data/r700_tagged_structlit_let/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 81. +package main; +type point = struct { x: i32, y: i32 }; +fn main() i32 = { + let r: (str | point) = point { x = 7, y = 35 }; + match (r) { + case let s: str => return 0 - s.len: i32; + case let p: point => return p.x + p.y; + }; + return -1; +}; diff --git a/test/wcc/data/r700_tagged_structlit_ret/case.ww b/test/wcc/data/r700_tagged_structlit_ret/case.ww new file mode 100644 index 00000000..72613398 --- /dev/null +++ b/test/wcc/data/r700_tagged_structlit_ret/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 83. +package main; +type point = struct { x: i32, y: i32 }; +fn make() (str | point) = { + return point { x = 12, y = 30 }; +}; +fn main() i32 = { + let r: (str | point) = make(); + match (r) { + case let s: str => return 0 - s.len: i32; + case let p: point => return p.x + p.y; + }; + return -1; +}; diff --git a/test/wcc/data/r700_tagged_subset_store/case.ww b/test/wcc/data/r700_tagged_subset_store/case.ww new file mode 100644 index 00000000..a55347d4 --- /dev/null +++ b/test/wcc/data/r700_tagged_subset_store/case.ww @@ -0,0 +1,22 @@ +//ww:run-exit 11 +// Migrated from 700_e2e row 93. +package main; +type inner = (i32 | str); +fn main() i32 = { + let arr: [2](i32 | str | u64); + let v: inner = 9; + arr[0] = v; + let w: inner = "hi"; + arr[1] = w; + let s: i32 = 0; + let i: i32 = 0; + for (i < 2) { + match (arr[i]) { + case let n: i32 => s += n; + case let t: str => s += t.len: i32; + case let u: u64 => s += 100; + }; + i += 1; + }; + return s; +}; diff --git a/test/wcc/data/r700_tagged_tag_synth/case.ww b/test/wcc/data/r700_tagged_tag_synth/case.ww new file mode 100644 index 00000000..3d521c53 --- /dev/null +++ b/test/wcc/data/r700_tagged_tag_synth/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 7 +// Migrated from 700_e2e row 51. +package main; +fn main() i32 = { + let r: (i64 | i32) = 7: i32; + match (r) { + case let v: i64 => return 1; + case let e: i32 => return e; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tagged_untyped_lit/case.ww b/test/wcc/data/r700_tagged_untyped_lit/case.ww new file mode 100644 index 00000000..5e68eead --- /dev/null +++ b/test/wcc/data/r700_tagged_untyped_lit/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 5 +// Migrated from 700_e2e row 52. +package main; +fn main() i32 = { + let r: (i64 | i32) = 5; + match (r) { + case let v: i64 => return v: i32; + case let e: i32 => return 99; + }; + return 0; +}; diff --git a/test/wcc/data/r700_try_prop/case.ww b/test/wcc/data/r700_try_prop/case.ww new file mode 100644 index 00000000..43c57bf3 --- /dev/null +++ b/test/wcc/data/r700_try_prop/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 99 +// Migrated from 700_e2e row 49. +package main; +fn try1(n: i64) (i64 | i32) = { + if (n < 0) { return 99: i32; }; + return n; +}; +fn try2(n: i64) (i64 | i32) = { + let v: i64 = try1(n)?; + return v + 100; +}; +fn main() i32 = { + let r: (i64 | i32) = try2(-1); + let s: i64 = 0; + match (r) { + case let v: i64 => s = v; + case let e: i32 => s = e: i64; + }; + return s: i32; +}; diff --git a/test/wcc/data/r700_try_str_prop/case.ww b/test/wcc/data/r700_try_str_prop/case.ww new file mode 100644 index 00000000..0e9288e7 --- /dev/null +++ b/test/wcc/data/r700_try_str_prop/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 4 +// Migrated from 700_e2e row 60. +package main; +fn try1(n: i64) (i64 | str) = { + if (n < 0) { return "fail"; }; + return n; +}; +fn try2(n: i64) (i64 | str) = { + let v: i64 = try1(n)?; + return v + 100; +}; +fn main() i32 = { + let r: (i64 | str) = try2(-1); + match (r) { + case let n: i64 => return n: i32; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_try_widen_success/case.ww b/test/wcc/data/r700_try_widen_success/case.ww new file mode 100644 index 00000000..c1e2c254 --- /dev/null +++ b/test/wcc/data/r700_try_widen_success/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 3 +// Migrated from 700_e2e row 61. +package main; +fn inner(b: bool) (i32 | str) = { + if (b) { return 7; }; + return "err"; +}; +fn outer(b: bool) (i64 | str) = { + let v: i32 = inner(b)?; + return v: i64 + 100; +}; +fn main() i32 = { + let r: (i64 | str) = outer(false); + match (r) { + case let n: i64 => return n: i32; + case let s: str => return s.len: i32; + }; + return 0; +}; diff --git a/test/wcc/data/r700_tuple3_range_destr/case.ww b/test/wcc/data/r700_tuple3_range_destr/case.ww new file mode 100644 index 00000000..49a21d24 --- /dev/null +++ b/test/wcc/data/r700_tuple3_range_destr/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 47. +package main; +fn main() i32 = { + let buf: [3]i64; + buf[0] = 5; buf[1] = 7; buf[2] = 30; + let s: [](i64, i64, i64); + s.ptr = buf.ptr: *(i64, i64, i64); + s.len = 1; s.cap = 1; + let total: i64 = 0; + for (let (a, b, c) .. s) { total += a + b + c; }; + return total: i32; +}; diff --git a/test/wcc/data/r700_tuple_paren_destr/case.ww b/test/wcc/data/r700_tuple_paren_destr/case.ww new file mode 100644 index 00000000..be38622d --- /dev/null +++ b/test/wcc/data/r700_tuple_paren_destr/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 5 +// Migrated from 700_e2e row 42. +package main; +fn divmod(a: i64, b: i64) (i64, i64) = { return a / b, a % b; }; +fn main() i32 = { + let (q, r) = divmod(17, 5); + return (q + r): i32; +}; diff --git a/test/wcc/data/r700_tuple_positional/case.ww b/test/wcc/data/r700_tuple_positional/case.ww new file mode 100644 index 00000000..51e5b1d8 --- /dev/null +++ b/test/wcc/data/r700_tuple_positional/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 44. +package main; +fn pair() (i64, i64) = { return 10, 32; }; +fn main() i32 = { + let t: (i64, i64) = pair(); + return (t.0 + t.1): i32; +}; diff --git a/test/wcc/data/r700_tuple_range_destr/case.ww b/test/wcc/data/r700_tuple_range_destr/case.ww new file mode 100644 index 00000000..477e7d96 --- /dev/null +++ b/test/wcc/data/r700_tuple_range_destr/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 33 +// Migrated from 700_e2e row 43. +package main; +fn main() i32 = { + let buf: [4]i64; + buf[0] = 1; buf[1] = 10; buf[2] = 2; buf[3] = 20; + let s: [](i64, i64); + s.ptr = buf.ptr: *(i64, i64); + s.len = 2; s.cap = 2; + let total: i64 = 0; + for (let (k, v) .. s) { total += k + v; }; + return total: i32; +}; diff --git a/test/wcc/data/r700_tuple_str_first_ret/case.ww b/test/wcc/data/r700_tuple_str_first_ret/case.ww new file mode 100644 index 00000000..80e6ba81 --- /dev/null +++ b/test/wcc/data/r700_tuple_str_first_ret/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 47 +// Migrated from 700_e2e row 106. +package main; +fn split() (str, i64) = { return "hello", 42; }; +fn main() i32 = { + let s, n = split(); + return (n: i32) + (s.len: i32); +}; diff --git a/test/wcc/data/r700_tuple_str_paren/case.ww b/test/wcc/data/r700_tuple_str_paren/case.ww new file mode 100644 index 00000000..8bb512af --- /dev/null +++ b/test/wcc/data/r700_tuple_str_paren/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 47 +// Migrated from 700_e2e row 108. +package main; +fn split() (i64, str) = { return 42, "hello"; }; +fn main() i32 = { + let (n, s) = split(); + return (n: i32) + (s.len: i32); +}; diff --git a/test/wcc/data/r700_tuple_str_positional/case.ww b/test/wcc/data/r700_tuple_str_positional/case.ww new file mode 100644 index 00000000..6410541b --- /dev/null +++ b/test/wcc/data/r700_tuple_str_positional/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 47 +// Migrated from 700_e2e row 107. +package main; +fn split() (i64, str) = { return 42, "hello"; }; +fn main() i32 = { + let t: (i64, str) = split(); + return (t.0: i32) + (t.1.len: i32); +}; diff --git a/test/wcc/data/r700_tuple_str_ret/case.ww b/test/wcc/data/r700_tuple_str_ret/case.ww new file mode 100644 index 00000000..e08bbfd6 --- /dev/null +++ b/test/wcc/data/r700_tuple_str_ret/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 47 +// Migrated from 700_e2e row 105. +package main; +fn split() (i64, str) = { return 42, "hello"; }; +fn main() i32 = { + let n, s = split(); + return (n: i32) + (s.len: i32); +}; diff --git a/test/wcc/data/r700_typed_int_lit/case.ww b/test/wcc/data/r700_typed_int_lit/case.ww new file mode 100644 index 00000000..c6cad014 --- /dev/null +++ b/test/wcc/data/r700_typed_int_lit/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 198 +// Migrated from 700_e2e row 18. +package main; +fn main() i32 = { + let buf: [4]u8; + buf[0] = 65u8; buf[1] = 66u8; buf[2] = 67u8; buf[3] = 0u8; + let s: i32 = 0; + let i: i32 = 0; + for (i < 3) { s += buf[i]: i32; i += 1; }; + return s; +}; diff --git a/test/wcc/data/r700_variadic_forward/case.ww b/test/wcc/data/r700_variadic_forward/case.ww new file mode 100644 index 00000000..f5b9b2ec --- /dev/null +++ b/test/wcc/data/r700_variadic_forward/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 131. +package main; +fn sum(args: i64...) i64 = { + let s: i64 = 0i64; + let i: i32 = 0; + for (i < args.len) { s += args[i]; i += 1; }; + return s; +}; +fn wrap(prefix: i64, args: i64...) i64 = { + return prefix + sum(args...); +}; +fn main() i32 = { + return wrap(2i64, 1i64, 2i64, 3i64, 4i64, 5i64, 7i64, 18i64): i32; +}; diff --git a/test/wcc/data/r700_variadic_gather/case.ww b/test/wcc/data/r700_variadic_gather/case.ww new file mode 100644 index 00000000..b9aef142 --- /dev/null +++ b/test/wcc/data/r700_variadic_gather/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 128. +package main; +fn sum(args: i64...) i64 = { + let s: i64 = 0i64; + let i: i32 = 0; + for (i < args.len) { s += args[i]; i += 1; }; + return s; +}; +fn main() i32 = { + return sum(1i64, 2i64, 3i64, 7i64, 9i64, 20i64): i32; +}; diff --git a/test/wcc/data/r700_variadic_tagged/case.ww b/test/wcc/data/r700_variadic_tagged/case.ww new file mode 100644 index 00000000..cc3a2ef9 --- /dev/null +++ b/test/wcc/data/r700_variadic_tagged/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 130. +package main; +type formattable = (i64 | str | bool); +fn sumtag(args: formattable...) i64 = { + let s: i64 = 0i64; + let i: i32 = 0; + for (i < args.len) { + match (args[i]) { + case let n: i64 => s += n; + case let v: str => s += v.len: i64; + case let b: bool => { if (b) { s += 39i64; }; }; + }; + i += 1; + }; + return s; +}; +fn main() i32 = { return sumtag(1i64, "hi", true): i32; }; diff --git a/test/wcc/data/r700_variadic_zero/case.ww b/test/wcc/data/r700_variadic_zero/case.ww new file mode 100644 index 00000000..fb0e1379 --- /dev/null +++ b/test/wcc/data/r700_variadic_zero/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 129. +package main; +fn sum(args: i64...) i64 = { + let s: i64 = 0i64; + let i: i32 = 0; + for (i < args.len) { s += args[i]; i += 1; }; + return s; +}; +fn main() i32 = { + let a: i64 = sum(); + let b: i64 = sum(42i64); + return (a + b): i32; +}; diff --git a/test/wcc/data/r700_vtable_fnptr/case.ww b/test/wcc/data/r700_vtable_fnptr/case.ww new file mode 100644 index 00000000..c317a52c --- /dev/null +++ b/test/wcc/data/r700_vtable_fnptr/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 29. +package main; +type ops = struct { add: fn(a: i32, b: i32) i32 }; +fn plus(a: i32, b: i32) i32 = { return a + b; }; +fn main() i32 = { + let v: ops = ops { add = plus }; + return v.add(20, 22); +}; diff --git a/test/wcc/data/r700_widen_tagged_i32/case.ww b/test/wcc/data/r700_widen_tagged_i32/case.ww new file mode 100644 index 00000000..e97658d7 --- /dev/null +++ b/test/wcc/data/r700_widen_tagged_i32/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 84. +package main; +fn classify(r: (str | i32 | rune)) i32 = { + match (r) { + case let s: str => return 1; + case let n: i32 => return n; + case let c: rune => return c: i32 + 100; + }; + return 0; +}; +fn main() i32 = { + let inner: (i32 | rune) = 42: i32; + return classify(inner); +}; diff --git a/test/wcc/data/r700_widen_tagged_let/case.ww b/test/wcc/data/r700_widen_tagged_let/case.ww new file mode 100644 index 00000000..2b2df92f --- /dev/null +++ b/test/wcc/data/r700_widen_tagged_let/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 42 +// Migrated from 700_e2e row 86. +package main; +fn main() i32 = { + let inner: (i32 | rune) = 42: i32; + let r: (str | i32 | rune) = inner; + match (r) { + case let s: str => return 1; + case let n: i32 => return n; + case let c: rune => return c: i32 + 100; + }; + return 0; +}; diff --git a/test/wcc/data/r700_widen_tagged_rune/case.ww b/test/wcc/data/r700_widen_tagged_rune/case.ww new file mode 100644 index 00000000..758b5fb7 --- /dev/null +++ b/test/wcc/data/r700_widen_tagged_rune/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 165 +// Migrated from 700_e2e row 85. +package main; +fn classify(r: (str | i32 | rune)) i32 = { + match (r) { + case let s: str => return 1; + case let n: i32 => return n; + case let c: rune => return c: i32 + 100; + }; + return 0; +}; +fn main() i32 = { + let inner: (i32 | rune) = 'A': rune; + return classify(inner); +}; diff --git a/test/wcc/data/r800append_struct_call_gp16/case.ww b/test/wcc/data/r800append_struct_call_gp16/case.ww new file mode 100644 index 00000000..1cdee376 --- /dev/null +++ b/test/wcc/data/r800append_struct_call_gp16/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 0 +// Graduated #34 reject pin: a 16B GP struct CALL element appends +// through the per-site scratch receive (was the loudstop fixture). +package main; +type pt = struct { x: i32, y: i32, z: i64 }; +fn mk() pt = { + return pt { x = 1, y = 2, z = 3 }; +}; +export fn main() i32 = { + let xs: []pt = []; + append(xs, mk()); + if (xs.len != 1) { return 1; }; + if (xs[0].x != 1 || xs[0].y != 2) { return 2; }; + if (xs[0].z != 3i64) { return 3; }; + return 0; +}; diff --git a/test/wcc/data/r806ap_call_src_gp16/case.ww b/test/wcc/data/r806ap_call_src_gp16/case.ww new file mode 100644 index 00000000..9ec3650b --- /dev/null +++ b/test/wcc/data/r806ap_call_src_gp16/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 0 +// Graduated #34 reject pin: size+i64 16B GP call element (was the +// reject fixture). +package main; +type box = struct { pc: size, a: i64 }; +fn mk() box = { return box { pc = 1, a = 2 }; }; +export fn main() i32 = { + let bs: []box = []; + append(bs, mk()); + if (bs.len != 1) { return 1; }; + if (bs[0].pc != 1) { return 2; }; + if (bs[0].a != 2i64) { return 3; }; + return 0; +};