Files
ww/lib/ascii/ascii.ww
Hojun-Cho e16634baec lib: add missing Hare-stdlib functions (ascii/bytes/strings/path/endian)
ascii: valid, validstr, ispunct, isprint, iscntrl, isgraph, isblank,
strcasecmp.

bytes: hasprefix, hassuffix, rindex, rindexbyte, contains, reverse,
zero.

strings: rindex, sub, trimprefix, trimsuffix, ltrimbyte, rtrimbyte,
trimbyte. The byte-set trim is a single-byte subset of Hare's
`trim(input, exclude: rune...)`; no variadic ABI yet.

path: dirname, basename, extension, join. Owned-str returns where the
result isn't a borrowed view of the input (join).

endian: full Hare table — be/le get/put for u16/u32/u64 plus the
network-order htonu/ntohu pair extended to 32/64.

lib/CLAUDE.md rewritten to reflect the post-graduation policy
(tagged-union returns, owned-str returns, plan9 names, documented
deviations for non-graduating modules).

Makefile picks up lib/ascii and lib/fmt as wwdump_ww / w6c_ww deps so
lib-only edits regenerate the affected binaries.
2026-05-13 04:03:55 +09:00

135 lines
3.3 KiB
Plaintext

// ascii — rune-class predicates and case folding for the ASCII range.
// Matches Hare's ascii::isdigit family (rune-taking signature). Runes
// outside 0..127 always answer `false`. The lexer hot path uses these
// inline; they are expected to inline to a couple of compares.
export fn isdigit(c: rune) bool = {
if (c < 48) { return false; };
if (c > 57) { return false; };
return true;
};
export fn isupper(c: rune) bool = {
if (c < 65) { return false; };
if (c > 90) { return false; };
return true;
};
export fn islower(c: rune) bool = {
if (c < 97) { return false; };
if (c > 122) { return false; };
return true;
};
export fn isalpha(c: rune) bool = {
if (isupper(c)) { return true; };
return islower(c);
};
export fn isalnum(c: rune) bool = {
if (isalpha(c)) { return true; };
return isdigit(c);
};
// isspace — the C/Hare set: space, tab, NL, VT, FF, CR.
export fn isspace(c: rune) bool = {
if (c == 32) { return true; }; // ' '
if (c == 9) { return true; }; // '\t'
if (c == 10) { return true; }; // '\n'
if (c == 11) { return true; }; // '\v'
if (c == 12) { return true; }; // '\f'
if (c == 13) { return true; }; // '\r'
return false;
};
export fn isxdigit(c: rune) bool = {
if (isdigit(c)) { return true; };
if (c >= 65) {
if (c <= 70) { return true; }; // 'A'..'F'
};
if (c >= 97) {
if (c <= 102) { return true; }; // 'a'..'f'
};
return false;
};
// valid — `c` is in the 0..127 ASCII range.
export fn valid(c: rune) bool = {
if (c < 0) { return false; };
if (c > 127) { return false; };
return true;
};
// validstr — every byte in `s` is ASCII (0..127).
export fn validstr(s: str) bool = {
let i: i32 = 0;
for (i < s.len) {
// High-bit test rather than `> 127u8`; both cgens lower
// the bitwise form identically. The `> u8` form picks
// JA vs JG depending on signed/unsigned dispatch.
if ((s[i] & 128u8) != 0u8) { return false; };
i += 1;
};
return true;
};
// iscntrl — control chars: 0..31 and 127.
export fn iscntrl(c: rune) bool = {
if (c >= 0) { if (c <= 31) { return true; }; };
if (c == 127) { return true; };
return false;
};
// isblank — space and tab.
export fn isblank(c: rune) bool = {
if (c == 32) { return true; }; // ' '
if (c == 9) { return true; }; // '\t'
return false;
};
// isprint — printable: space through '~'.
export fn isprint(c: rune) bool = {
if (c < 32) { return false; };
if (c > 126) { return false; };
return true;
};
// isgraph — printable, non-space.
export fn isgraph(c: rune) bool = {
if (c < 33) { return false; };
if (c > 126) { return false; };
return true;
};
// ispunct — printable, non-alnum, non-space.
export fn ispunct(c: rune) bool = {
if (!isgraph(c)) { return false; };
if (isalnum(c)) { return false; };
return true;
};
// tolower / toupper — fold ASCII case. Non-letters pass through.
export fn tolower(c: rune) rune = {
if (isupper(c)) { return c + 32; };
return c;
};
export fn toupper(c: rune) rune = {
if (islower(c)) { return c - 32; };
return c;
};
// strcasecmp — three-way ASCII case-insensitive compare.
export fn strcasecmp(a: str, b: str) i32 = {
let n: i32 = a.len;
if (b.len < n) { n = b.len; };
let i: i32 = 0;
for (i < n) {
let ca: rune = tolower(a[i]: rune);
let cb: rune = tolower(b[i]: rune);
if (ca != cb) { return (ca - cb): i32; };
i += 1;
};
return a.len - b.len;
};