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:
@@ -113,17 +113,17 @@ fn pat_next(pat: str, pos: *i32, fl: flag) (u8 | star | question | bracket | end
|
||||
if (*pos >= pat.len) { let e: endt; return e; };
|
||||
let c: u8 = pat[*pos];
|
||||
*pos += 1;
|
||||
if (c == 42u8) { let r: star; return r; }; // '*'
|
||||
if (c == 63u8) { let r: question; return r; }; // '?'
|
||||
if (c == 91u8) { let r: bracket; return r; }; // '['
|
||||
if (c == 92u8) { // '\\'
|
||||
if (c == '*') { let r: star; return r; };
|
||||
if (c == '?') { let r: question; return r; };
|
||||
if (c == '[') { let r: bracket; return r; };
|
||||
if (c == '\\') {
|
||||
if (((fl as i32) & (flag.NOESCAPE as i32)) == 0) {
|
||||
if (*pos >= pat.len) { let e: invalid; return e; };
|
||||
let c2: u8 = pat[*pos];
|
||||
*pos += 1;
|
||||
return c2;
|
||||
};
|
||||
return 92u8;
|
||||
return '\\';
|
||||
};
|
||||
return c;
|
||||
};
|
||||
@@ -161,7 +161,7 @@ fn match_ctype(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
let nameoff: i32 = *pos;
|
||||
let i: i32 = 0;
|
||||
let r: u8 = 0u8;
|
||||
for (r != 58u8) { // ':'
|
||||
for (r != ':') {
|
||||
let rr = advance_or_err(pat, pos);
|
||||
match (rr) {
|
||||
case let e: invalid => return e;
|
||||
@@ -176,7 +176,7 @@ fn match_ctype(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
match (rr) {
|
||||
case let e: invalid => return e;
|
||||
case let f: u8 => {
|
||||
if (f != 93u8) { let e: invalid; return e; }; // ']'
|
||||
if (f != ']') { let e: invalid; return e; };
|
||||
};
|
||||
};
|
||||
let name: str;
|
||||
@@ -212,9 +212,9 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
case let e: invalid => return e;
|
||||
case let f: u8 => { first = f; };
|
||||
};
|
||||
if (first == 94u8) { let e: invalid; return e; }; // '^' is Hare-invalid
|
||||
if (first == '^') { let e: invalid; return e; }; // '^' is Hare-invalid
|
||||
let inv: bool = false;
|
||||
if (first == 33u8) { // '!'
|
||||
if (first == '!') {
|
||||
inv = true;
|
||||
let r1 = advance_or_err(pat, pos);
|
||||
match (r1) {
|
||||
@@ -222,10 +222,10 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
case let f: u8 => { first = f; };
|
||||
};
|
||||
};
|
||||
let found: bool = (first != 91u8) && (first == c);
|
||||
let found: bool = (first != '[') && (first == c);
|
||||
let havelast: bool = true;
|
||||
let last: u8 = first;
|
||||
if (first == 93u8) { // ']' as first member
|
||||
if (first == ']') { // ']' as first member
|
||||
let r2 = advance_or_err(pat, pos);
|
||||
match (r2) {
|
||||
case let e: invalid => return e;
|
||||
@@ -235,22 +235,22 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
let r: u8 = first;
|
||||
let loop: bool = true;
|
||||
for (loop) {
|
||||
if (r == 93u8) { // ']' closes
|
||||
if (r == ']') { // ']' closes
|
||||
loop = false;
|
||||
} else { if (r == 45u8) { // '-' range
|
||||
} else { if (r == '-') { // '-' range
|
||||
let er = advance_or_err(pat, pos);
|
||||
let endv: u8 = 0u8;
|
||||
match (er) {
|
||||
case let e: invalid => return e;
|
||||
case let f: u8 => { endv = f; };
|
||||
};
|
||||
if (endv == 93u8) {
|
||||
if (endv == ']') {
|
||||
// Trailing '-' matches itself. Un-eat ']'
|
||||
// so the next iteration sees it.
|
||||
*pos -= 1;
|
||||
last = 45u8;
|
||||
last = '-';
|
||||
havelast = true;
|
||||
if (c == 45u8) { found = true; };
|
||||
if (c == '-') { found = true; };
|
||||
} else {
|
||||
if (!havelast) { let e: invalid; return e; };
|
||||
if ((last: u32) <= (c: u32) && (c: u32) <= (endv: u32)) {
|
||||
@@ -258,16 +258,16 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
};
|
||||
havelast = false; // forbid `a-f-n`
|
||||
};
|
||||
} else { if (r == 91u8) { // '['
|
||||
} else { if (r == '[') {
|
||||
let nx = advance_or_err(pat, pos);
|
||||
let nxv: u8 = 0u8;
|
||||
match (nx) {
|
||||
case let e: invalid => return e;
|
||||
case let f: u8 => { nxv = f; };
|
||||
};
|
||||
if (nxv == 61u8) { let e: invalid; return e; }; // '='
|
||||
if (nxv == 46u8) { let e: invalid; return e; }; // '.'
|
||||
if (nxv == 58u8) { // ':' class
|
||||
if (nxv == '=') { let e: invalid; return e; };
|
||||
if (nxv == '.') { let e: invalid; return e; };
|
||||
if (nxv == ':') { // ':' class
|
||||
let t = match_ctype(pat, pos, c);
|
||||
match (t) {
|
||||
case let e: invalid => return e;
|
||||
@@ -278,9 +278,9 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
} else {
|
||||
// Not a class — un-eat the byte after '['.
|
||||
*pos -= 1;
|
||||
if (c == 91u8) { found = true; };
|
||||
if (c == '[') { found = true; };
|
||||
};
|
||||
last = 91u8;
|
||||
last = '[';
|
||||
havelast = true;
|
||||
} else { // literal byte
|
||||
if (c == r) { found = true; };
|
||||
@@ -300,9 +300,9 @@ fn match_bracket(pat: str, pos: *i32, c: u8) (bool | invalid) = {
|
||||
// have been an empty collating/equivalence/class).
|
||||
let cnt: i32 = *pos - oldpos;
|
||||
if (havelast && first == last && cnt >= 4) {
|
||||
if (first == 61u8) { let e: invalid; return e; };
|
||||
if (first == 46u8) { let e: invalid; return e; };
|
||||
if (first == 58u8) { let e: invalid; return e; };
|
||||
if (first == '=') { let e: invalid; return e; };
|
||||
if (first == '.') { let e: invalid; return e; };
|
||||
if (first == ':') { let e: invalid; return e; };
|
||||
};
|
||||
if (inv) { return !found; };
|
||||
return found;
|
||||
@@ -534,7 +534,7 @@ fn fnmatch_pathname(pattern: str, string: str, fl: flag) (bool | invalid) = {
|
||||
case let e: invalid => return e;
|
||||
case endt => { kind = 1; inner = false; };
|
||||
case let r: u8 => {
|
||||
if (r == 47u8) { kind = 0; inner = false; };
|
||||
if (r == '/') { kind = 0; inner = false; };
|
||||
};
|
||||
case bracket => {
|
||||
let mr = match_bracket(pattern, &pp, 0u8);
|
||||
@@ -552,7 +552,7 @@ fn fnmatch_pathname(pattern: str, string: str, fl: flag) (bool | invalid) = {
|
||||
if (donetokens) { return false; };
|
||||
let segstart_s: i32 = sp;
|
||||
for (sp < string.len) {
|
||||
if (string[sp] == 47u8) { break; };
|
||||
if (string[sp] == '/') { break; };
|
||||
sp += 1;
|
||||
};
|
||||
let seg: str;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user