lib/ascii: add strlower/strupper
Port ref/hare/ascii/string.ha strlower/strupper as the allocating entry points: byte-wise ASCII case fold, equivalent to Hare's rune fold since case-folding only touches bytes <0x80 and every UTF-8 multibyte byte is >=0x80 (passes through unchanged, length-preserving). nomem arises only from the allocation's `?`. strlower_buf/strupper_buf are deferred: ww has no nomem-value form or capacity-bounded static-append to express Hare's too-small-buffer path (#230); restore the two-tier delegation when those land. Divergence (rule 7): the empty-input fast path returns a nil/0 str because ww's alloc([], 0) routes through nomem, whereas Hare allocs a zero-length buffer and zero-loops; documented at the bypass site. Test vectors mirror Hare's @test (ABC/abc/[[[/こ/empty/aB1z). Adds lib/ascii/asciitest.ww + test/wcc/904_ascii_run.c (registered in the Makefile TESTS list and a build rule). Regenerates the ascii-embedding selfhost combined.ww amalgams (#110 freshness); the wwdump amalgam also reorders the ascii block after strings to satisfy the new import edge.
This commit is contained in:
@@ -4290,6 +4290,8 @@ let POW5_TABLE: [26]u64 = [
|
||||
|
||||
package ascii;
|
||||
|
||||
import strings;
|
||||
|
||||
export fn isdigit(c: rune) bool = {
|
||||
if (c < 48) { return false; };
|
||||
if (c > 57) { return false; };
|
||||
@@ -4420,6 +4422,51 @@ export fn strcasecmp(a: str, b: str) i32 = {
|
||||
return a.len - b.len;
|
||||
};
|
||||
|
||||
// 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)
|
||||
if (s.len == 0) {
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
r.len = 0;
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = tolower(s[i]: rune): u8;
|
||||
i += 1;
|
||||
};
|
||||
buf.len = s.len;
|
||||
return strings.frombytes(buf);
|
||||
};
|
||||
|
||||
// strupper — ASCII-uppercased copy of s, newly allocated.
|
||||
// ref/hare/ascii/string.ha:33.
|
||||
export fn strupper(s: str) (str | nomem) = {
|
||||
if (s.len == 0) {
|
||||
let r: str;
|
||||
r.ptr = nil;
|
||||
r.len = 0;
|
||||
return r;
|
||||
};
|
||||
let buf: []u8 = alloc([], s.len: u64)?;
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
buf.ptr[i] = toupper(s[i]: rune): u8;
|
||||
i += 1;
|
||||
};
|
||||
buf.len = s.len;
|
||||
return strings.frombytes(buf);
|
||||
};
|
||||
|
||||
// strconv — string-to-float. Mirrors ref/hare/strconv/stof.ha
|
||||
// (Hare in turn adapts Go): Eisel-Lemire fast path [1] with the
|
||||
// Simple-Decimal-Conversion slow path [2] (decimal.ww) as fallback.
|
||||
|
||||
Reference in New Issue
Block a user