/* * 923_signed_data_emit_run — top-level `let` bindings of signed * integer types must emit a module-scope DATA slot whose initialiser * is the literal's two's-complement bytes (#19). * * Pre-fix both stages skipped the scalar DATAW arm when the rhs was * N_UN(TK_MINUS, INTLIT). cstage's emit_lets fell through to the * default `else continue;` so `let x: i8 = -1i8;` produced no DATAW * row and the link failed with "undefined reference to x". Wwstage's * emitletdataw silently left the slot at zero — link succeeded but * the read returned 0 instead of -1, a corpus-coverage-blind bug. * * The array arm carried the same defect on both stages. cstage's * walker bailed on the first non-foldable element (then dropped the * whole DATAW row for the array via the `is_array continue` fall- * through); wwstage emitted zeros at every unfoldable index, again * silently. The utf8 DFA shape (`let dfa: [8]i8 = [0i8, -1i8, ...]`) * is the canonical real-source trigger. * * Sister to #24, which fixed the same N_UN-fold gap on the `def`- * emit side (emit_defs / emitdefconstants) via the shared * fold_int_literal / foldintliteral helper. Task #19 routes the * `let`-emit paths (scalar + array) through the same helper. * * Rows pin the full signed-int matrix (i8/i16/i32/i64) for both * scalar and 1D array shapes, plus positive controls so a future * regression of the gate that affects only the negative arm still * leaves the positive rows green. The negative-zero (TK_MINUS over * 0) and TK_TILDE rows pin the other two N_UN ops the helper covers. * * Stage matrix: cstage always; wwstage gated on `ww_ww` existing. * Runtime checks all read through cast-strip + literal compare so a * cgen-side narrow-load regression surfaces here rather than hiding * behind the DATA slot's wider-than-elem padding. */ #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; }; static const struct row rows[] = { { "i8_neg_scalar", "let x: i8 = -1i8;\n" "fn main() i32 = { if (x != -1i8) { return 1; }; return 0; };\n", 0 }, { "i8_pos_scalar", "let x: i8 = 42i8;\n" "fn main() i32 = { if (x != 42i8) { return 1; }; return 0; };\n", 0 }, { "i16_neg_scalar", "let x: i16 = -2i16;\n" "fn main() i32 = { if (x != -2i16) { return 1; }; return 0; };\n", 0 }, { "i16_pos_scalar", "let x: i16 = 1000i16;\n" "fn main() i32 = { if (x != 1000i16) { return 1; }; return 0; };\n", 0 }, { "i32_neg_scalar", "let x: i32 = -100i32;\n" "fn main() i32 = { if (x != -100i32) { return 1; }; return 0; };\n", 0 }, { "i32_pos_scalar", "let x: i32 = 100000i32;\n" "fn main() i32 = { if (x != 100000i32) { return 1; }; return 0; };\n", 0 }, { "i64_neg_scalar", "let x: i64 = -1000i64;\n" "fn main() i32 = { if (x != -1000i64) { return 1; }; return 0; };\n", 0 }, { "i64_pos_scalar", "let x: i64 = 1000000i64;\n" "fn main() i32 = { if (x != 1000000i64) { return 1; }; return 0; };\n", 0 }, /* TK_TILDE over a literal — the other N_UN op fold_int_literal * covers. ~0u64 == 0xFFFFFFFFFFFFFFFF == -1i64. */ { "i64_tilde_scalar", "let x: i64 = (~0u64): i64;\n" "fn main() i32 = { if (x != -1i64) { return 1; }; return 0; };\n", 0 }, /* Array of i8: utf8 DFA shape. The negative entries silently * zeroed pre-fix on wwstage; cstage emitted nothing at all and * the link failed before this row could even build. */ { "i8_arr_dfa", "let dfa: [8]i8 = [0i8, -1i8, 1i8, 2i8, 0i8, 0i8, -1i8, -1i8];\n" "fn main() i32 = {\n" " if (dfa[0] != 0i8) { return 1; };\n" " if (dfa[1] != -1i8) { return 2; };\n" " if (dfa[2] != 1i8) { return 3; };\n" " if (dfa[3] != 2i8) { return 4; };\n" " if (dfa[6] != -1i8) { return 5; };\n" " if (dfa[7] != -1i8) { return 6; };\n" " return 0;\n" "};\n", 0 }, { "i16_arr_mixed", "let a: [4]i16 = [1i16, -2i16, 3i16, -4i16];\n" "fn main() i32 = {\n" " if (a[0] != 1i16) { return 1; };\n" " if (a[1] != -2i16) { return 2; };\n" " if (a[2] != 3i16) { return 3; };\n" " if (a[3] != -4i16) { return 4; };\n" " return 0;\n" "};\n", 0 }, { "i32_arr_mixed", "let a: [4]i32 = [10i32, -20i32, 30i32, -40i32];\n" "fn main() i32 = {\n" " if (a[0] != 10i32) { return 1; };\n" " if (a[1] != -20i32) { return 2; };\n" " if (a[2] != 30i32) { return 3; };\n" " if (a[3] != -40i32) { return 4; };\n" " return 0;\n" "};\n", 0 }, { "i64_arr_mixed", "let a: [4]i64 = [100i64, -200i64, 300i64, -400i64];\n" "fn main() i32 = {\n" " if (a[0] != 100i64) { return 1; };\n" " if (a[1] != -200i64) { return 2; };\n" " if (a[2] != 300i64) { return 3; };\n" " if (a[3] != -400i64) { return 4; };\n" " return 0;\n" "};\n", 0 }, }; static int run_driver(const char *driver, const struct row *r, int i) { char src[64], tmpdir[64], cmd[1024]; snprintf(src, sizeof src, "/tmp/sde_%d_%d.ww", getpid(), i); snprintf(tmpdir, sizeof tmpdir, "/tmp/sde_%d_d_%d", getpid(), i); FILE *f = fopen(src, "wb"); if (!f) return -1; fputs(r->src, f); fclose(f); mkdir(tmpdir, 0755); snprintf(cmd, sizeof cmd, "cd %s && %s build %s", tmpdir, driver, src); if (runwait(cmd) != 0) { fprintf(stderr, "row[%s]: build via %s failed\n", r->label, driver); unlink(src); rmdir(tmpdir); return -1; } const char *base = strrchr(src, '/'); base = base ? base + 1 : src; char outbin[128]; snprintf(outbin, sizeof outbin, "%s/%s", tmpdir, base); char *dot = strrchr(outbin, '.'); if (dot && strcmp(dot, ".ww") == 0) *dot = '\0'; int got = runwait(outbin); unlink(src); unlink(outbin); rmdir(tmpdir); return got; } int main(void) { const char *bin = getenv("BIN"); if (!bin) bin = "out/bin"; char absbin[512]; if (bin[0] != '/') { char cwd[256]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); bin = absbin; } char cdrv[640]; snprintf(cdrv, sizeof cdrv, "%s/ww", bin); char wdrv[640]; snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); struct { const char *name; const char *path; int gated_on_existence; } drivers[] = { { "cstage", cdrv, 0 }, { "wwstage", wdrv, 1 }, { NULL, NULL, 0 }, }; int n = (int)(sizeof rows / sizeof rows[0]); int total = 0, fail = 0; for (int d = 0; drivers[d].name; d++) { if (drivers[d].gated_on_existence && access(drivers[d].path, X_OK) != 0) { fprintf(stderr, "signed_data_emit: skip %s (no %s)\n", drivers[d].name, drivers[d].path); continue; } for (int i = 0; i < n; i++) { int got = run_driver(drivers[d].path, &rows[i], i); total++; if (got != rows[i].want) { fprintf(stderr, "signed_data_emit[%s][%s]: exit=%d want=%d\n", drivers[d].name, rows[i].label, got, rows[i].want); fail++; } } } if (fail) { fprintf(stderr, "signed_data_emit: %d/%d fixtures failed\n", fail, total); return 1; } printf("signed_data_emit: %d/%d ok\n", total, total); return 0; }