From 23fccee4a0913549c7b2def2d2df15d78709fd4d Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 19 May 2026 05:19:21 +0900 Subject: [PATCH] lib/bytes+test: graduate contains to Hare (u8|[]u8)... variadic (#10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit contains(s, needle: (u8|[]u8)) -> contains(s: []u8, needles: (u8|[]u8)...) bool per ref/hare/bytes/contains.ha:6. Body: for-loop over needles.len; inner match (needles[i]) with u8/ []u8 arms each forwarding to index(s, ...) with early return true on the i32-match arm. 0-arg returns false per Hare spec. Mirrors sister #9 strings.contains body shape modulo element type. Sister of #9 (7c5463c). Element shape (u8|[]u8) — slice payload + scalar u8 — structurally distinct from (str|rune). Was flagged as potential new-latent surface; verified clean by 967_bytes_run + cross-module 750_mklabel_modscoped[bytes_strings_contains] + 995_self_rebuild byte-id. No cgen wedge fired — #15 frame growth + #12 sum-tag forward + #16 fnparamslookupmod close it on the slice- payload variant too. contains_cases adds 5 variadic rows (signalled 1700+i): 0-arg false, 1-arg slice hit, 1-arg u8 hit, 3-arg mixed middle-hit, 3-arg all-miss. Module-header non-variadic divergence note removed. make test 126/126; ww2==ww3==ww4 byte-id holds via 995_self_rebuild. --- lib/bytes/bytes.ww | 29 +++++++++++++++++++--------- lib/bytes/bytestest.ww | 12 ++++++++++++ selfhost/cmd/w6c/main.combined.ww | 29 +++++++++++++++++++--------- selfhost/cmd/wwdump/main.combined.ww | 29 +++++++++++++++++++--------- selfhost/test/smoke.combined.ww | 29 +++++++++++++++++++--------- 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/lib/bytes/bytes.ww b/lib/bytes/bytes.ww index f7a88198..ab3db696 100644 --- a/lib/bytes/bytes.ww +++ b/lib/bytes/bytes.ww @@ -7,9 +7,6 @@ // 2/3/4-byte needles and falls back to two_way (Crochemore-Perrin) // for longer (ref/hare/bytes/index.ha:61, ref/hare/bytes/two_way.ha). // Correctness equivalent. -// - contains takes a single needle; Hare's contains is variadic -// `(u8 | []u8)...` (ref/hare/bytes/contains.ha:5). No caller needs -// the variadic shape yet; graduate when one does. // equal — true iff `a` and `b` have the same length and contents. // ref/hare/bytes/equal.ha:9. @@ -92,12 +89,26 @@ export fn rindex(s: []u8, needle: (u8 | []u8)) (i32 | void) = { return; }; -// contains — true iff `needle` (byte or sub-slice) appears in `s`. -// ref/hare/bytes/contains.ha:5 (variadic subset; see header note). -export fn contains(s: []u8, needle: (u8 | []u8)) bool = { - match (index(s, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` (byte or sub-slice) appears in `s`. +// ref/hare/bytes/contains.ha:6. +export fn contains(s: []u8, needles: (u8 | []u8)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let b: u8 => { + match (index(s, b)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let n: []u8 => { + match (index(s, n)) { + case let bo: i32 => return true; + case void => void; + }; + }; + }; + i += 1; }; return false; }; diff --git a/lib/bytes/bytestest.ww b/lib/bytes/bytestest.ww index a25f1a1b..5dcc6350 100644 --- a/lib/bytes/bytestest.ww +++ b/lib/bytes/bytestest.ww @@ -195,6 +195,18 @@ fn fail() void = { os.exit(signalled + 10); }; if (!bytes.contains(a[0:4], n[0:2])) { fail(); }; let m: [2]u8; m[0] = 9u8; m[1] = 9u8; if ( bytes.contains(a[0:4], m[0:2])) { fail(); }; + + // Variadic rows. ref/hare/bytes/contains.ha:6. + signalled = 1700; + if ( bytes.contains(a[0:4])) { fail(); }; + signalled = 1701; + if (!bytes.contains(a[0:4], n[0:2])) { fail(); }; + signalled = 1702; + if (!bytes.contains(a[0:4], 7u8)) { fail(); }; + signalled = 1703; + if (!bytes.contains(a[0:4], m[0:2], n[0:2], 42u8)) { fail(); }; + signalled = 1704; + if ( bytes.contains(a[0:4], m[0:2], 42u8, m[0:2])) { fail(); }; }; // ---- hasprefix -------------------------------------------------------- diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 231cda4a..7ae1d07d 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -867,9 +867,6 @@ export fn freearena(a: *arena) void = { // 2/3/4-byte needles and falls back to two_way (Crochemore-Perrin) // for longer (ref/hare/bytes/index.ha:61, ref/hare/bytes/two_way.ha). // Correctness equivalent. -// - contains takes a single needle; Hare's contains is variadic -// `(u8 | []u8)...` (ref/hare/bytes/contains.ha:5). No caller needs -// the variadic shape yet; graduate when one does. // equal — true iff `a` and `b` have the same length and contents. // ref/hare/bytes/equal.ha:9. @@ -952,12 +949,26 @@ export fn rindex(s: []u8, needle: (u8 | []u8)) (i32 | void) = { return; }; -// contains — true iff `needle` (byte or sub-slice) appears in `s`. -// ref/hare/bytes/contains.ha:5 (variadic subset; see header note). -export fn contains(s: []u8, needle: (u8 | []u8)) bool = { - match (index(s, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` (byte or sub-slice) appears in `s`. +// ref/hare/bytes/contains.ha:6. +export fn contains(s: []u8, needles: (u8 | []u8)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let b: u8 => { + match (index(s, b)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let n: []u8 => { + match (index(s, n)) { + case let bo: i32 => return true; + case void => void; + }; + }; + }; + i += 1; }; return false; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 043db4a3..91f79bc4 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -867,9 +867,6 @@ export fn freearena(a: *arena) void = { // 2/3/4-byte needles and falls back to two_way (Crochemore-Perrin) // for longer (ref/hare/bytes/index.ha:61, ref/hare/bytes/two_way.ha). // Correctness equivalent. -// - contains takes a single needle; Hare's contains is variadic -// `(u8 | []u8)...` (ref/hare/bytes/contains.ha:5). No caller needs -// the variadic shape yet; graduate when one does. // equal — true iff `a` and `b` have the same length and contents. // ref/hare/bytes/equal.ha:9. @@ -952,12 +949,26 @@ export fn rindex(s: []u8, needle: (u8 | []u8)) (i32 | void) = { return; }; -// contains — true iff `needle` (byte or sub-slice) appears in `s`. -// ref/hare/bytes/contains.ha:5 (variadic subset; see header note). -export fn contains(s: []u8, needle: (u8 | []u8)) bool = { - match (index(s, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` (byte or sub-slice) appears in `s`. +// ref/hare/bytes/contains.ha:6. +export fn contains(s: []u8, needles: (u8 | []u8)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let b: u8 => { + match (index(s, b)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let n: []u8 => { + match (index(s, n)) { + case let bo: i32 => return true; + case void => void; + }; + }; + }; + i += 1; }; return false; }; diff --git a/selfhost/test/smoke.combined.ww b/selfhost/test/smoke.combined.ww index 536f0fb5..7e26bcb9 100644 --- a/selfhost/test/smoke.combined.ww +++ b/selfhost/test/smoke.combined.ww @@ -758,9 +758,6 @@ export fn exists(path: str) bool = { // 2/3/4-byte needles and falls back to two_way (Crochemore-Perrin) // for longer (ref/hare/bytes/index.ha:61, ref/hare/bytes/two_way.ha). // Correctness equivalent. -// - contains takes a single needle; Hare's contains is variadic -// `(u8 | []u8)...` (ref/hare/bytes/contains.ha:5). No caller needs -// the variadic shape yet; graduate when one does. // equal — true iff `a` and `b` have the same length and contents. // ref/hare/bytes/equal.ha:9. @@ -843,12 +840,26 @@ export fn rindex(s: []u8, needle: (u8 | []u8)) (i32 | void) = { return; }; -// contains — true iff `needle` (byte or sub-slice) appears in `s`. -// ref/hare/bytes/contains.ha:5 (variadic subset; see header note). -export fn contains(s: []u8, needle: (u8 | []u8)) bool = { - match (index(s, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` (byte or sub-slice) appears in `s`. +// ref/hare/bytes/contains.ha:6. +export fn contains(s: []u8, needles: (u8 | []u8)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let b: u8 => { + match (index(s, b)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let n: []u8 => { + match (index(s, n)) { + case let bo: i32 => return true; + case void => void; + }; + }; + }; + i += 1; }; return false; };