lib/types,wcc/ww: export the limit constants (#48)

lib/types limit consts were bare `def`s, so the .wwi (sep-compile's
interface) correctly omitted them while the flat combined.ww let a
cross-package user (lib/strings splitn → types.I32_MAX) reach the
private def — sep-compile then failed (wwstage `asserttyped: dot
'I32_MAX'`; cstage undefined-ref). Hare exports types::I32_MAX and the
whole limit family (ref/hare/types/limits.ha, arch+x86_64.ha); ww not
exporting them was the divergence.

export the 24 existing limit defs ({I,U}{8,16,32,64}_{MIN,MAX},
INT/UINT/SIZE/UINTPTR_{MIN,MAX}) and the existing RUNE_MIN, and add
exported RUNE_MAX. ww's derived machine-word int/uint/size/uintptr
VALUES are kept verbatim (user-ratified 64-bit-int divergence); fidelity
here is the NAME SET + export-visibility, not the values. RUNE_MAX is
written `0x10ffff: rune` — same codepoint as Hare's '\U0010ffff', forced
because ww's lexer has no \u/\U escape (#50).

Exporting the consts made `w6c -I` walk them and fatal on RUNE_MIN
('\0'): the .wwi const-expr unparser had no N_RUNELIT arm. Add one,
both stages (wwi_rune / wwirune), rendering a \xHH-escaped rune literal
(>0xFF fails loud, #50). Const casts need no arm — the checker folds
them to integer literals before the producer runs. 989_m2wwi_run gains
a types.wwi gate (byte-id + re-parse + asserts export def I32_MAX and
RUNE_MAX reach the interface). byte-id-neutral: a def emits no symbol.
This commit is contained in:
2026-06-15 23:06:11 +09:00
parent 4622556c62
commit f69ef9b9da
10 changed files with 384 additions and 177 deletions

View File

@@ -323,6 +323,65 @@ out:
return rc;
}
/* #48 gate: the lib/types limit constants are `export def`s (Hare exports
* types::I32_MAX &c). Produce types.wwi on both stages directly from the
* real lib source (no imports → its own primary unit), assert byte-id +
* re-parse + that the exported limits actually appear in the .wwi (a non-
* exported def is omitted, so this proves the export reached the interface
* a cross-package sep-compile consumer reads). Returns 0 on pass. */
static int
typesexport(const char *bin, const char *cwd)
{
char td[64], cmd[4096], src[1024];
int rc = -1;
snprintf(td, sizeof td, "/tmp/wwm2typ_%d", getpid());
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
runwait(cmd);
mkdir(td, 0755);
snprintf(src, sizeof src, "%s/lib/types/types.ww", cwd);
char cs[1100], ws[1100];
snprintf(cs, sizeof cs, "%s/cs.wwi", td);
snprintf(ws, sizeof ws, "%s/ww.wwi", td);
snprintf(cmd, sizeof cmd,
"timeout 180 %s/w6c -I %s %s >/dev/null 2>&1", bin, cs, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "m2wwi FAIL: types — w6c -I rejected\n");
goto out;
}
snprintf(cmd, sizeof cmd,
"timeout 180 %s/w6c_ww -I %s %s >/dev/null 2>&1", bin, ws, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "m2wwi FAIL: types — w6c_ww -I rejected\n");
goto out;
}
if (files_eq(cs, ws) != 0) {
fprintf(stderr, "m2wwi FAIL: types — cs.wwi != ww.wwi\n");
goto out;
}
if (file_contains(cs, "export def I32_MAX") != 0
|| file_contains(cs, "export def RUNE_MAX") != 0) {
fprintf(stderr, "m2wwi FAIL: types — limit consts not exported "
"into the .wwi (cross-package sep-compile would not see "
"types.I32_MAX)\n");
goto out;
}
snprintf(cmd, sizeof cmd,
"timeout 180 %s/wwdump -a %s >/dev/null 2>&1", bin, cs);
if (runwait(cmd) != 0) {
fprintf(stderr, "m2wwi FAIL: types — emitted .wwi does not "
"re-parse (wwdump -a)\n");
goto out;
}
rc = 0;
out:
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
runwait(cmd);
return rc;
}
int
main(void)
{
@@ -339,6 +398,8 @@ main(void)
}
if (synth(bin) != 0) fail++;
else npos++;
if (typesexport(bin, cwd) != 0) fail++;
else npos++;
if (negative(bin) != 0) fail++;
if (fail) {