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.
This commit is contained in:
@@ -1170,6 +1170,61 @@ export fn isxdigit(c: rune) bool = {
|
||||
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; };
|
||||
@@ -1181,6 +1236,20 @@ export fn toupper(c: rune) rune = {
|
||||
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;
|
||||
};
|
||||
|
||||
// MODULE: lex
|
||||
// lib/ww/lex/lex.ww — port of cmd/wcc/lex.c.
|
||||
//
|
||||
|
||||
@@ -1170,6 +1170,61 @@ export fn isxdigit(c: rune) bool = {
|
||||
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; };
|
||||
@@ -1181,6 +1236,20 @@ export fn toupper(c: rune) rune = {
|
||||
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;
|
||||
};
|
||||
|
||||
// MODULE: lex
|
||||
// lib/ww/lex/lex.ww — port of cmd/wcc/lex.c.
|
||||
//
|
||||
|
||||
@@ -644,6 +644,61 @@ export fn isxdigit(c: rune) bool = {
|
||||
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; };
|
||||
@@ -655,6 +710,20 @@ export fn toupper(c: rune) rune = {
|
||||
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;
|
||||
};
|
||||
|
||||
// MODULE: test
|
||||
// selfhost/test/smoke.ww — end-to-end smoke for the selfhost path.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user