fold-6 carrier-split (drew's ruling): the 6 uniesc value rows (rune/string escape decode) are already covered 1:1 by test/lang/uniesc_test.ww @test rows -- same escape forms, same expected codepoints/bytes, same lexer escape-decode path, and dual-stage via test-lang-byteid (frontend-swap .s byte-id proves wwstage decode transitively, strictly more sensitive than re-running). So drop the duplicate value rows from the C driver; 110_uniesc_run.c slims to just the .wwi roundtrip -- a 2-package sep-build observer that can't be an in-language @test and isn't a reject case (its eventual runww home tracked as #19). The carrier still runs both stages for the roundtrip; no coverage lost, test count unchanged (404).
143 lines
4.2 KiB
C
143 lines
4.2 KiB
C
/*
|
|
* 110_uniesc_run — .wwi round-trip carrier for \u / \U Unicode escapes.
|
|
*
|
|
* The value-row half (rune/string \u \U \x decode asserts) migrated to the
|
|
* in-language row-table test/lang/uniesc_test.ww (fold-6, task #4); this
|
|
* file retains ONLY the .wwi round-trip case, which is a two-package
|
|
* sep-build observer with no in-language @test home (it asserts the
|
|
* PRODUCER re-serializes a wide-rune `def` byte-exact, observed across a
|
|
* package boundary — not expressible as a single-compile @test).
|
|
*
|
|
* An exported wide-rune `def` re-serialized by the producer must re-parse
|
|
* into the same codepoint (the write-twin of the lexer read-fix —
|
|
* cmd/w6c/wwi.c wwi_rune / selfhost/cmd/wcc/wwi.ww wwirune emit \u/\U above
|
|
* 0xFF). Runs through both the cstage `ww` and wwstage `ww_ww` drivers
|
|
* (task #50); the wwstage arm is skipped when ww_ww is absent (a
|
|
* cstage-only build), mirroring 640_int_cast_signed.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
|
|
static int
|
|
runwait(const char *cmd)
|
|
{
|
|
int rc = system(cmd);
|
|
if (rc == -1) return -1;
|
|
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
|
return -1;
|
|
}
|
|
|
|
/* run_roundtrip — sep-build a two-package program where the imported
|
|
* package exports wide-rune defs; the producer must serialize them as
|
|
* \u/\U so the importer re-parses the same codepoint. Returns the built
|
|
* program's exit code (42 on a correct round-trip). */
|
|
static int
|
|
run_roundtrip(const char *driver, int id)
|
|
{
|
|
char dir[80], wrdir[112], wrp[176], mainp[160], cmd[1024], outbin[160];
|
|
snprintf(dir, sizeof dir, "/tmp/wwue_rt_%d_%d", getpid(), id);
|
|
snprintf(wrdir, sizeof wrdir, "%s/wr", dir);
|
|
mkdir(dir, 0755);
|
|
mkdir(wrdir, 0755);
|
|
snprintf(wrp, sizeof wrp, "%s/wr.ww", wrdir);
|
|
snprintf(mainp, sizeof mainp, "%s/main.ww", dir);
|
|
|
|
FILE *f = fopen(wrp, "wb");
|
|
if (!f) {
|
|
snprintf(cmd, sizeof cmd, "rm -rf %s", dir);
|
|
(void)system(cmd);
|
|
return -1;
|
|
}
|
|
/* one def per serializer branch: \x (<=0xFF), \u (<=0xFFFF), \U. */
|
|
fputs("package wr;\n"
|
|
"export def EACUTE: rune = '\\u00e9';\n"
|
|
"export def EURO: rune = '\\u20ac';\n"
|
|
"export def SMILEY: rune = '\\U0001F600';\n", f);
|
|
fclose(f);
|
|
f = fopen(mainp, "wb");
|
|
if (!f) {
|
|
snprintf(cmd, sizeof cmd, "rm -rf %s", dir);
|
|
(void)system(cmd);
|
|
return -1;
|
|
}
|
|
fputs("package main;\n"
|
|
"import wr;\n"
|
|
"fn main() i32 = {\n"
|
|
" let a: rune = wr.EACUTE;\n"
|
|
" let b: rune = wr.EURO;\n"
|
|
" let c: rune = wr.SMILEY;\n"
|
|
" if ((a: u32) != 233u32) { return 1; };\n"
|
|
" if ((b: u32) != 8364u32) { return 2; };\n"
|
|
" if ((c: u32) != 128512u32) { return 3; };\n"
|
|
" return 42;\n"
|
|
"};\n", f);
|
|
fclose(f);
|
|
|
|
snprintf(cmd, sizeof cmd, "cd %s && %s build main.ww", dir, driver);
|
|
if (runwait(cmd) != 0) {
|
|
fprintf(stderr, "roundtrip: build via %s failed\n", driver);
|
|
snprintf(cmd, sizeof cmd, "rm -rf %s", dir);
|
|
(void)system(cmd);
|
|
return -1;
|
|
}
|
|
snprintf(outbin, sizeof outbin, "%s/main", dir);
|
|
int got = runwait(outbin);
|
|
snprintf(cmd, sizeof cmd, "rm -rf %s", dir);
|
|
(void)system(cmd);
|
|
return got;
|
|
}
|
|
|
|
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 cdrv[1024];
|
|
snprintf(cdrv, sizeof cdrv, "%s/ww", bin);
|
|
char wdrv[1024];
|
|
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 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, "uniesc_run: skip %s (no %s)\n",
|
|
drivers[d].name, drivers[d].path);
|
|
continue;
|
|
}
|
|
int rt = run_roundtrip(drivers[d].path, d);
|
|
total++;
|
|
if (rt != 42) {
|
|
fprintf(stderr,
|
|
"uniesc_run[%s][wwi_roundtrip]: exit=%d want=42\n",
|
|
drivers[d].name, rt);
|
|
fail++;
|
|
}
|
|
}
|
|
if (fail) {
|
|
fprintf(stderr, "uniesc_run: %d/%d fixtures failed\n",
|
|
fail, total);
|
|
return 1;
|
|
}
|
|
printf("uniesc_run: %d/%d ok\n", total, total);
|
|
return 0;
|
|
}
|