lib: char-literals for ascii/fnmatch/shlex magic decimals (Wave-1)

Replace magic ASCII decimals with char literals in ascii/fnmatch/shlex
predicates (e.g. `c < 48` → `c < '0'`). Byte-id-neutral: ascii params are
rune, so rune<rune emission is unchanged; fnmatch/shlex compare u8 against
value-preserving (<=126) rune constants. Range bounds (0/31/127), the ±32
case offset, the 128 high-bit mask, and fnmatch 0u8 sentinels stay decimal.

Regenerate the three combined.ww that embed ascii (w6c, wwdump, smoke).

Add functional rows pinning predicates reachable only via fnmatch ctype
classes / shlex split: [[:space:]]/[[:print:]]/[[:graph:]] + the '\t' arm
of [[:blank:]] (fnmatchtest), '\t'/'\n' split separators + issafe's
special-char set (shlextest) — so a wrong substitution would be caught.
This commit is contained in:
2026-06-02 19:24:40 +09:00
parent 90479fed68
commit d1310a03ad
8 changed files with 150 additions and 136 deletions

View File

@@ -134,6 +134,16 @@ fn check(pat: str, s: str, expected: bool, flags: i32) void = {
check("[[alpha:]]", ":]", true, 0);
check("[[:alpha:]]", "a", true, 0);
check("[[:blank:]]", " ", true, 0);
// pin the ascii.is{blank,space,print,graph} predicates: their
// char-literal bounds are reachable only through these classes.
check("[[:blank:]]", "\t", true, 0);
check("[[:space:]]", " ", true, 0);
check("[[:space:]]", "\t", true, 0);
check("[[:space:]]", "x", false, 0);
check("[[:print:]]", "~", true, 0);
check("[[:print:]]", "\t", false, 0);
check("[[:graph:]]", "a", true, 0);
check("[[:graph:]]", " ", false, 0);
check("[[:alnum:]]a", "a]a", false, 0);
check("[[:alnum:][[:digit:]]", "a", true, 0);