lib/ascii: add strlower_buf/strupper_buf (#11)

Restore Hare's two-tier delegation: strlower/strupper alloc a buffer
then delegate to strlower_buf/strupper_buf, which fold ASCII case
into a caller-provided buffer. Too-small buffer returns nomem via the
`let nm: nomem` value form. ref/hare/ascii/string.ha:21,43.

Regen w6c/wwdump/smoke combined.ww — all three embed lib/ascii.
This commit is contained in:
2026-06-01 16:00:33 +09:00
parent cdb74e8a49
commit 2b893b9353
5 changed files with 142 additions and 24 deletions

View File

@@ -4477,15 +4477,10 @@ export fn strcasecmp(a: str, b: str) i32 = {
};
// strlower — ASCII-lowercased copy of s, newly allocated.
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
// equals Hare's rune fold and is length-preserving.
// _buf variants deferred — ww has no nomem-value form / static-append
// builtin; restore Hare's two-tier delegation when they land (#230).
// ref/hare/ascii/string.ha:11.
export fn strlower(s: str) (str | nomem) = {
// empty bypass: ww alloc([],0) routes through nomem; Hare allocs 0
// and zero-loops (ref/hare/ascii/string.ha)
// and zero-loops (ref/hare/ascii/string.ha:12).
if (s.len == 0) {
let r: str;
r.ptr = nil;
@@ -4493,6 +4488,22 @@ export fn strlower(s: str) (str | nomem) = {
return r;
};
let buf: []u8 = alloc([], s.len: u64)?;
return strlower_buf(s, buf);
};
// strlower_buf — ASCII-lowercase s into buf (overwrites). nomem if buf
// too small. ref/hare/ascii/string.ha:21.
// Byte-wise fold: ASCII case-fold only touches bytes <0x80; UTF-8
// multibyte bytes are >=0x80 and pass through unchanged, so byte-wise
// equals Hare's rune fold and is length-preserving.
// ww uses an explicit `buf.cap < s.len` check + `let nm: nomem` value
// because it has no static-append builtin; Hare reaches the same
// nomem-on-too-small via `static append(buf, ...)?` (string.ha:25).
export fn strlower_buf(s: str, buf: []u8) (str | nomem) = {
if (buf.cap < s.len) {
let nm: nomem;
return nm;
};
let i: i32 = 0;
for (i < s.len) {
buf.ptr[i] = tolower(s[i]: rune): u8;
@@ -4512,6 +4523,15 @@ export fn strupper(s: str) (str | nomem) = {
return r;
};
let buf: []u8 = alloc([], s.len: u64)?;
return strupper_buf(s, buf);
};
// strupper_buf — see strlower_buf. ref/hare/ascii/string.ha:43.
export fn strupper_buf(s: str, buf: []u8) (str | nomem) = {
if (buf.cap < s.len) {
let nm: nomem;
return nm;
};
let i: i32 = 0;
for (i < s.len) {
buf.ptr[i] = toupper(s[i]: rune): u8;