/* * 919_array_static_init_run — runtime + byte-id net for #129 Phase * A.3: module-level let/def with array initializer. * * Pre-A.3 state: * - Int-element arrays (u8/i8/u16/u32/u64/i32 etc) already worked * in both stages via fold_int_literal. * - Float-element arrays ([N]f64, [N]f32) → undef-ref at link * (emit_lets array arm fold_int_literal fails on FLOATLIT). * - Array DEFs (def A: [N]T = [...]) → emit_defs no array arm * (storage missing) AND cgindex broken (reads LEAQ (BP), BX — * stack frame, not data section). * - Array-in-struct field (`def D: dt = dt{tag=42, buf=[...]}`) → * #129 A.2 rule-7 fatal "array field rhs not foldable" — the * shape parked in A.2 awaiting A.3. * * Phase A.3 fix (mirror A.1/A.2 SSoT-helper precedent): * - cstage: emit_array_data + emit_array_lit_bytes helpers with * element-kind dispatch (int via fold_int_literal preserving * bootstrap byte-id, float via inline bitcast + sign-XOR byte- * loop mirror of A.1, struct via emit_struct_lit_bytes recursion * mirror of A.2). Two-pass validate-then-emit avoids partial-byte * corruption on rhs-fold-failure. * - cstage: emit_lets array arm routes through helper; emit_defs * gains array arm. * - cstage: DefArray registry + def_isarraydef populated in * let_collect; cgindex N_INDEX direct-ident `isglobal` gate * widened to (let_islet || def_isarraydef). * - cstage: emit_struct_lit_bytes (A.2 helper) gains TY_ARRAY field * arm calling emit_array_lit_bytes recursively (closes A.2 parked * shape 15). * - wwstage: parallel emitarraydata + emitarraylitbytes; emitstruct * litbytes TY_ARRAY arm; defvartnode helper; cgindex falls through * to defvartnode after letvartnode nil. * * Bootstrap RISK: live consumers in lib/os, lib/bufio, lib/strings, * lib/encoding/utf8 (dfa + masks), lib/strconv/stof_data * (left_shift_table). All use typed-int-literal elements; the int-elem * helper path is byte-for-byte preserved → bootstrap NEUTRAL. * * Rows (size strata 1B/2B/4B/8B × count strata 1/2/4 × int/float/struct/ * empty/no-rhs/def-variant, avoiding the 16B-evade pattern from A.2): * * - (a) `let A: [4]u8 = [1u8, 2u8, 3u8, 4u8]` — 1B regression * - (b) `let A: [4]u32 = [1u32, 2u32, 3u32, 4u32]` — 4B regression * - (c) `let A: [2]u64 = [1u64, 2u64]` — 8B regression * - (d) `let A: [4]i32 = [-1, -2, -3, -4]` — N_UN peel regression * - (e) `let A: [4]f64 = [1.5, -2.5, 3.5, -4.5]` — NEW float-elem * - (f) `let A: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32]` — NEW * f32 narrow + sign-XOR per element * - (g) `def A: [4]u32 = [11u32, 22u32, 33u32, 44u32]` — NEW * def-storage + LOAD-widening * - (h) `def A: [4]f64 = [1.5, 2.5, 3.5, 4.5]` — NEW def-variant of * float * - (i) `def D: dt = dt{tag=42, buf=[1u8,2u8,3u8,4u8]}` — NEW * closes A.2 shape 15 (struct-with-array-field) * - (j) `let A: [4]u8 = [0u8, 0u8, 0u8, 0u8]` — explicit-zero * regression * - (k) `let A: [1]u8 = [0u8]` — single-elem (matches lib/os/ * emptypath pattern) * * Each row: cstage `ww build` + run asserting exit code + w6c vs * w6c_ww `.s` cmp (rule-10 byte-id). * * Deferred: * - Pointer-element arrays `[N]*T = [&G, &H]` — needs DATAR per * element (own task/fold). * - Nested arrays `[N][M]T` — no current consumer. * - Bare-int `[N]u8 = [1, 2, 3, 4]` — #130 (checker issue). * - Partial init `[4]u8 = [1u8]` — checker rejects (parser/checker * decision). */ #include #include #include #include #include #include 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 *label; const char *src; int want_exit; }; static const struct row rows[] = { { "let_u8_arr", "package main;\n" "let A: [4]u8 = [1u8, 2u8, 3u8, 4u8];\n" "export fn main() i32 = { return A[0]: i32; };\n", 1 }, { "let_u32_arr", "package main;\n" "let A: [4]u32 = [1u32, 2u32, 3u32, 4u32];\n" "export fn main() i32 = { return A[0]: i32; };\n", 1 }, { "let_u64_arr", "package main;\n" "let A: [2]u64 = [1u64, 2u64];\n" "export fn main() i32 = { return A[0]: i32; };\n", 1 }, { "let_i32_neg_arr", "package main;\n" "let A: [4]i32 = [-1, -2, -3, -4];\n" "export fn main() i32 = { return A[0]; };\n", 255 /* -1 */ }, /* Float-element array — NEW in A.3. Includes both signs to exercise * the sign-XOR byte-loop per element. */ { "let_f64_arr", "package main;\n" "let A: [4]f64 = [1.5, -2.5, 3.5, -4.5];\n" "export fn main() i32 = { return (A[0]: i32); };\n", 1 }, { "let_f32_arr", "package main;\n" "let A: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32];\n" "export fn main() i32 = { return (A[0]: i32); };\n", 1 }, /* def-variant exercises the LOAD-widening (def_isarraydef) at * cgindex/cgident. Storage emit also new. */ { "def_u32_arr", "package main;\n" "def A: [4]u32 = [11u32, 22u32, 33u32, 44u32];\n" "export fn main() i32 = { return A[0]: i32; };\n", 11 }, { "def_f64_arr", "package main;\n" "def A: [4]f64 = [1.5, 2.5, 3.5, 4.5];\n" "export fn main() i32 = { return (A[0]: i32); };\n", 1 }, /* The A.2-parked shape-15 — closes via emit_struct_lit_bytes * TY_ARRAY field arm. */ { "let_struct_with_arr_field", "package main;\n" "type dt = struct { tag: i32, buf: [4]u8 };\n" "let D: dt = dt{tag=42, buf=[1u8, 2u8, 3u8, 4u8]};\n" "export fn main() i32 = { return D.tag; };\n", 42 }, { "let_u8_zero_arr", "package main;\n" "let A: [4]u8 = [0u8, 0u8, 0u8, 0u8];\n" "export fn main() i32 = { return A[0]: i32; };\n", 0 }, { "let_u8_single", "package main;\n" "let A: [1]u8 = [7u8];\n" "export fn main() i32 = { return A[0]: i32; };\n", 7 }, { NULL, NULL, 0 } }; static int slurp_eq(const char *a, const char *b) { FILE *fa = fopen(a, "rb"); FILE *fb = fopen(b, "rb"); if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } int rc = 0; for (;;) { int ca = fgetc(fa); int cb = fgetc(fb); if (ca != cb) { rc = -1; break; } if (ca == EOF) break; } fclose(fa); fclose(fb); return rc; } int main(void) { const char *bin = getenv("BIN"); if (!bin) bin = "out/bin"; 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; } char w6c[1100], w6c_ww[1100]; snprintf(w6c, sizeof w6c, "%s/w6c", bin); snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); if (access(w6c_ww, X_OK) != 0) { fprintf(stderr, "arrinit: w6c_ww missing — cannot run " "the cs==ww byte-id gate (the whole point of this test)\n"); return 1; } int n = 0, fail = 0; for (int i = 0; rows[i].src; i++, n++) { char src[64]; snprintf(src, sizeof src, "/tmp/wwari_%d_%d.ww", getpid(), i); FILE *f = fopen(src, "wb"); if (f == NULL) { fail++; continue; } fputs(rows[i].src, f); fclose(f); char tmpdir[64]; snprintf(tmpdir, sizeof tmpdir, "/tmp/wwari_%d_d_%d", getpid(), i); mkdir(tmpdir, 0755); char cmd[2048]; snprintf(cmd, sizeof cmd, "cd %s && %s/ww build %s", tmpdir, bin, src); if (runwait(cmd) != 0) { fprintf(stderr, "row[%s]: cstage build failed\n", rows[i].label); fail++; unlink(src); rmdir(tmpdir); continue; } char outbin[128]; const char *base = strrchr(src, '/'); base = base ? base + 1 : src; snprintf(outbin, sizeof outbin, "%s/%s", tmpdir, base); char *dot = strrchr(outbin, '.'); if (dot && strcmp(dot, ".ww") == 0) *dot = '\0'; int got = runwait(outbin); if (got != rows[i].want_exit) { fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", rows[i].label, got, rows[i].want_exit); fail++; } unlink(outbin); rmdir(tmpdir); char cs_s[64], ws_s[64]; snprintf(cs_s, sizeof cs_s, "/tmp/wwari_%d_%d_cs.s", getpid(), i); snprintf(ws_s, sizeof ws_s, "/tmp/wwari_%d_%d_ww.s", getpid(), i); snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, cs_s, src); if (runwait(cmd) != 0) { fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); fail++; unlink(src); continue; } snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c_ww, ws_s, src); if (runwait(cmd) != 0) { fprintf(stderr, "row[%s]: w6c_ww failed\n", rows[i].label); fail++; unlink(src); unlink(cs_s); continue; } if (slurp_eq(cs_s, ws_s) != 0) { fprintf(stderr, "row[%s]: cstage/wwstage .s DIFFER (rule-10 " "byte-id violation)\n", rows[i].label); fail++; } unlink(src); unlink(cs_s); unlink(ws_s); } if (fail) { fprintf(stderr, "%d/%d array-static-init tests failed\n", fail, n); return 1; } printf("arrinit: %d/%d ok (cstage run + cs==ww byte-id)\n", n, n); return 0; }