From c9cf25be2855f46cfa57e71c911f53dba873b01b Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 19 May 2026 00:56:30 +0900 Subject: [PATCH] selfhost: regen combined.ww for 5466ea0 strings.concat variadic Frozen-artifact catch-up. 5466ea0 modified lib/strings/strings.ww and lib/strings/stringstest.ww but did not regenerate the three bundled .combined.ww files. Bisect of the frozen-fallback build path was broken at 5466ea0..HEAD. --- selfhost/cmd/w6c/main.combined.ww | 48 ++++++++++++++++++---------- selfhost/cmd/wwdump/main.combined.ww | 48 ++++++++++++++++++---------- selfhost/test/smoke.combined.ww | 48 ++++++++++++++++++---------- 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index e80cde94..54822ef2 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -1445,17 +1445,18 @@ export fn position(d: *decoder) i32 = { // // Documented divergences from Hare: // -// - `concat(a, b)` is 2-arg. Hare ships `concat(strs: str...)` -// (ref/hare/strings/concat.ha:5). Blocks on task #16 (cstage -// variadic-pack drops .len of multi-field element type). Cite -// reverts on fix. // - `trim` / `ltrim` / `rtrim` take a single rune. Hare's are -// `(exclude: rune...)` (ref/hare/strings/trim.ha:54). Same -// blocker as concat. Hare's no-rune branch (strip whitespace) -// is also dropped — depends on a rune set. +// `(trim: rune...)` (ref/hare/strings/trim.ha:11,32,54). The +// port body uses `iter`/`next` + inner match against the pack + +// `prev` step-back; that shape triggers #36 (wwstage scanlocals +// misses match-arm `case let` bindings, slot offsets diverge — +// `.ai/probe_trim_36extra.{ww,diff}`). Hare's no-rune +// strip-whitespace branch additionally needs `lib/bytes` +// variadic graduation. // - `contains` is non-variadic. Hare's is // `contains(haystack, needles: (str | rune)...)` -// (ref/hare/strings/contains.ha:9). Same blocker. +// (ref/hare/strings/contains.ha:9). Gated on `(str|rune)...` +// tagged-variadic gather + runtime — task #5. // - `byteindex` / `rbyteindex` rune arms encode via // `utf8.encoderune`; the legacy impls scanned for `r: u8` (an // undocumented ASCII-only restriction that silently dropped @@ -1549,17 +1550,30 @@ export fn freeall(s: []str) void = { }; }; -// concat — fresh allocation containing `a` then `b`. Caller releases -// with `os.free(r.ptr, r.len: u64)`. ref/hare/strings/concat.ha:5 -// (subset: Hare's `(strs: str...)` blocks on task #16). -export fn concat(a: str, b: str) str = { - let total: i32 = a.len + b.len; - let buf: *u8 = os.alloc(total: u64): *u8; +// concat — fresh allocation containing each element of `strs` in +// order. Caller releases with `os.free(r.ptr, r.len: u64)`. +// ref/hare/strings/concat.ha:5. Hare's `nomem` return is dropped: +// `os.alloc` aborts on OOM. +export fn concat(strs: str...) str = { + let total: i32 = 0; let i: i32 = 0; - for (i < a.len) { buf[i] = a[i]; i += 1; }; - let j: i32 = 0; - for (j < b.len) { buf[a.len + j] = b[j]; j += 1; }; + for (i < strs.len) { total += strs[i].len; i += 1; }; let r: str; + r.ptr = nil; + r.len = 0; + if (total == 0) { return r; }; + let buf: *u8 = os.alloc(total: u64): *u8; + let off: i32 = 0; + i = 0; + for (i < strs.len) { + let j: i32 = 0; + for (j < strs[i].len) { + buf[off + j] = strs[i][j]; + j += 1; + }; + off += strs[i].len; + i += 1; + }; r.ptr = buf; r.len = total; return r; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 371c487b..82ac9036 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -1445,17 +1445,18 @@ export fn position(d: *decoder) i32 = { // // Documented divergences from Hare: // -// - `concat(a, b)` is 2-arg. Hare ships `concat(strs: str...)` -// (ref/hare/strings/concat.ha:5). Blocks on task #16 (cstage -// variadic-pack drops .len of multi-field element type). Cite -// reverts on fix. // - `trim` / `ltrim` / `rtrim` take a single rune. Hare's are -// `(exclude: rune...)` (ref/hare/strings/trim.ha:54). Same -// blocker as concat. Hare's no-rune branch (strip whitespace) -// is also dropped — depends on a rune set. +// `(trim: rune...)` (ref/hare/strings/trim.ha:11,32,54). The +// port body uses `iter`/`next` + inner match against the pack + +// `prev` step-back; that shape triggers #36 (wwstage scanlocals +// misses match-arm `case let` bindings, slot offsets diverge — +// `.ai/probe_trim_36extra.{ww,diff}`). Hare's no-rune +// strip-whitespace branch additionally needs `lib/bytes` +// variadic graduation. // - `contains` is non-variadic. Hare's is // `contains(haystack, needles: (str | rune)...)` -// (ref/hare/strings/contains.ha:9). Same blocker. +// (ref/hare/strings/contains.ha:9). Gated on `(str|rune)...` +// tagged-variadic gather + runtime — task #5. // - `byteindex` / `rbyteindex` rune arms encode via // `utf8.encoderune`; the legacy impls scanned for `r: u8` (an // undocumented ASCII-only restriction that silently dropped @@ -1549,17 +1550,30 @@ export fn freeall(s: []str) void = { }; }; -// concat — fresh allocation containing `a` then `b`. Caller releases -// with `os.free(r.ptr, r.len: u64)`. ref/hare/strings/concat.ha:5 -// (subset: Hare's `(strs: str...)` blocks on task #16). -export fn concat(a: str, b: str) str = { - let total: i32 = a.len + b.len; - let buf: *u8 = os.alloc(total: u64): *u8; +// concat — fresh allocation containing each element of `strs` in +// order. Caller releases with `os.free(r.ptr, r.len: u64)`. +// ref/hare/strings/concat.ha:5. Hare's `nomem` return is dropped: +// `os.alloc` aborts on OOM. +export fn concat(strs: str...) str = { + let total: i32 = 0; let i: i32 = 0; - for (i < a.len) { buf[i] = a[i]; i += 1; }; - let j: i32 = 0; - for (j < b.len) { buf[a.len + j] = b[j]; j += 1; }; + for (i < strs.len) { total += strs[i].len; i += 1; }; let r: str; + r.ptr = nil; + r.len = 0; + if (total == 0) { return r; }; + let buf: *u8 = os.alloc(total: u64): *u8; + let off: i32 = 0; + i = 0; + for (i < strs.len) { + let j: i32 = 0; + for (j < strs[i].len) { + buf[off + j] = strs[i][j]; + j += 1; + }; + off += strs[i].len; + i += 1; + }; r.ptr = buf; r.len = total; return r; diff --git a/selfhost/test/smoke.combined.ww b/selfhost/test/smoke.combined.ww index 6717cdc7..8868c60a 100644 --- a/selfhost/test/smoke.combined.ww +++ b/selfhost/test/smoke.combined.ww @@ -1336,17 +1336,18 @@ export fn position(d: *decoder) i32 = { // // Documented divergences from Hare: // -// - `concat(a, b)` is 2-arg. Hare ships `concat(strs: str...)` -// (ref/hare/strings/concat.ha:5). Blocks on task #16 (cstage -// variadic-pack drops .len of multi-field element type). Cite -// reverts on fix. // - `trim` / `ltrim` / `rtrim` take a single rune. Hare's are -// `(exclude: rune...)` (ref/hare/strings/trim.ha:54). Same -// blocker as concat. Hare's no-rune branch (strip whitespace) -// is also dropped — depends on a rune set. +// `(trim: rune...)` (ref/hare/strings/trim.ha:11,32,54). The +// port body uses `iter`/`next` + inner match against the pack + +// `prev` step-back; that shape triggers #36 (wwstage scanlocals +// misses match-arm `case let` bindings, slot offsets diverge — +// `.ai/probe_trim_36extra.{ww,diff}`). Hare's no-rune +// strip-whitespace branch additionally needs `lib/bytes` +// variadic graduation. // - `contains` is non-variadic. Hare's is // `contains(haystack, needles: (str | rune)...)` -// (ref/hare/strings/contains.ha:9). Same blocker. +// (ref/hare/strings/contains.ha:9). Gated on `(str|rune)...` +// tagged-variadic gather + runtime — task #5. // - `byteindex` / `rbyteindex` rune arms encode via // `utf8.encoderune`; the legacy impls scanned for `r: u8` (an // undocumented ASCII-only restriction that silently dropped @@ -1440,17 +1441,30 @@ export fn freeall(s: []str) void = { }; }; -// concat — fresh allocation containing `a` then `b`. Caller releases -// with `os.free(r.ptr, r.len: u64)`. ref/hare/strings/concat.ha:5 -// (subset: Hare's `(strs: str...)` blocks on task #16). -export fn concat(a: str, b: str) str = { - let total: i32 = a.len + b.len; - let buf: *u8 = os.alloc(total: u64): *u8; +// concat — fresh allocation containing each element of `strs` in +// order. Caller releases with `os.free(r.ptr, r.len: u64)`. +// ref/hare/strings/concat.ha:5. Hare's `nomem` return is dropped: +// `os.alloc` aborts on OOM. +export fn concat(strs: str...) str = { + let total: i32 = 0; let i: i32 = 0; - for (i < a.len) { buf[i] = a[i]; i += 1; }; - let j: i32 = 0; - for (j < b.len) { buf[a.len + j] = b[j]; j += 1; }; + for (i < strs.len) { total += strs[i].len; i += 1; }; let r: str; + r.ptr = nil; + r.len = 0; + if (total == 0) { return r; }; + let buf: *u8 = os.alloc(total: u64): *u8; + let off: i32 = 0; + i = 0; + for (i < strs.len) { + let j: i32 = 0; + for (j < strs[i].len) { + buf[off + j] = strs[i][j]; + j += 1; + }; + off += strs[i].len; + i += 1; + }; r.ptr = buf; r.len = total; return r;