diff --git a/lib/strings/strings.ww b/lib/strings/strings.ww index e66adeaa..1919c2db 100644 --- a/lib/strings/strings.ww +++ b/lib/strings/strings.ww @@ -7,10 +7,6 @@ // Hare strips ASCII whitespace via `bytes::ltrim(input, // whitespace...)`; that needs `lib/bytes` variadic graduation // (future commit). -// - `contains` is non-variadic. Hare's is -// `contains(haystack, needles: (str | rune)...)` -// (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 @@ -293,13 +289,26 @@ export fn rindex(haystack: str, needle: (str | rune)) (i32 | void) = { return; }; -// contains — true iff `needle` occurs in `haystack`. -// ref/hare/strings/contains.ha:9 (subset: Hare's variadic form -// `(needles: (str | rune)...)` blocks on task #16). -export fn contains(haystack: str, needle: (str | rune)) bool = { - match (byteindex(haystack, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` occurs in `haystack`. +// ref/hare/strings/contains.ha:9. +export fn contains(haystack: str, needles: (str | rune)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let s: str => { + match (byteindex(haystack, s)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let r: rune => { + match (byteindex(haystack, r)) { + case let bo: i32 => return true; + case void => void; + }; + }; + }; + i += 1; }; return false; }; diff --git a/lib/strings/stringstest.ww b/lib/strings/stringstest.ww index bf1e2d1d..8faf6ef7 100644 --- a/lib/strings/stringstest.ww +++ b/lib/strings/stringstest.ww @@ -139,6 +139,20 @@ fn streq(a: str, b: str) bool = { if ( strings.contains("hello world", "foobar")) { fail(); }; if (!strings.contains("こんにちは", 0x306Bu32: rune)) { fail(); }; // 'に' if (!strings.contains("こんにちは", "ちは")) { fail(); }; + + // Variadic rows. ref/hare/strings/contains.ha:27. + signalled = 1600; + if ( strings.contains("hello")) { fail(); }; + signalled = 1601; + if (!strings.contains("hello world", "world")) { fail(); }; + signalled = 1602; + if (!strings.contains("hello", 'l')) { fail(); }; + signalled = 1603; + if (!strings.contains("hello world", "foo", "world", 'x')) { fail(); }; + signalled = 1604; + if ( strings.contains("hello", "foo", 'z', "bar")) { fail(); }; + signalled = 1605; + if (!strings.contains("héllo", "x", 0xE9u32: rune)) { fail(); }; }; // ---- byteindex -------------------------------------------------------- diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 0a859be8..231cda4a 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -1449,10 +1449,6 @@ export fn position(d: *decoder) i32 = { // Hare strips ASCII whitespace via `bytes::ltrim(input, // whitespace...)`; that needs `lib/bytes` variadic graduation // (future commit). -// - `contains` is non-variadic. Hare's is -// `contains(haystack, needles: (str | rune)...)` -// (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 @@ -1735,13 +1731,26 @@ export fn rindex(haystack: str, needle: (str | rune)) (i32 | void) = { return; }; -// contains — true iff `needle` occurs in `haystack`. -// ref/hare/strings/contains.ha:9 (subset: Hare's variadic form -// `(needles: (str | rune)...)` blocks on task #16). -export fn contains(haystack: str, needle: (str | rune)) bool = { - match (byteindex(haystack, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` occurs in `haystack`. +// ref/hare/strings/contains.ha:9. +export fn contains(haystack: str, needles: (str | rune)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let s: str => { + match (byteindex(haystack, s)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let r: rune => { + match (byteindex(haystack, r)) { + 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 018cd310..043db4a3 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -1449,10 +1449,6 @@ export fn position(d: *decoder) i32 = { // Hare strips ASCII whitespace via `bytes::ltrim(input, // whitespace...)`; that needs `lib/bytes` variadic graduation // (future commit). -// - `contains` is non-variadic. Hare's is -// `contains(haystack, needles: (str | rune)...)` -// (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 @@ -1735,13 +1731,26 @@ export fn rindex(haystack: str, needle: (str | rune)) (i32 | void) = { return; }; -// contains — true iff `needle` occurs in `haystack`. -// ref/hare/strings/contains.ha:9 (subset: Hare's variadic form -// `(needles: (str | rune)...)` blocks on task #16). -export fn contains(haystack: str, needle: (str | rune)) bool = { - match (byteindex(haystack, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` occurs in `haystack`. +// ref/hare/strings/contains.ha:9. +export fn contains(haystack: str, needles: (str | rune)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let s: str => { + match (byteindex(haystack, s)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let r: rune => { + match (byteindex(haystack, r)) { + 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 ed442b72..536f0fb5 100644 --- a/selfhost/test/smoke.combined.ww +++ b/selfhost/test/smoke.combined.ww @@ -1340,10 +1340,6 @@ export fn position(d: *decoder) i32 = { // Hare strips ASCII whitespace via `bytes::ltrim(input, // whitespace...)`; that needs `lib/bytes` variadic graduation // (future commit). -// - `contains` is non-variadic. Hare's is -// `contains(haystack, needles: (str | rune)...)` -// (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 @@ -1626,13 +1622,26 @@ export fn rindex(haystack: str, needle: (str | rune)) (i32 | void) = { return; }; -// contains — true iff `needle` occurs in `haystack`. -// ref/hare/strings/contains.ha:9 (subset: Hare's variadic form -// `(needles: (str | rune)...)` blocks on task #16). -export fn contains(haystack: str, needle: (str | rune)) bool = { - match (byteindex(haystack, needle)) { - case let i: i32 => return true; - case void => return false; +// contains — true iff any of `needles` occurs in `haystack`. +// ref/hare/strings/contains.ha:9. +export fn contains(haystack: str, needles: (str | rune)...) bool = { + let i: i32 = 0; + for (i < needles.len) { + match (needles[i]) { + case let s: str => { + match (byteindex(haystack, s)) { + case let bo: i32 => return true; + case void => void; + }; + }; + case let r: rune => { + match (byteindex(haystack, r)) { + case let bo: i32 => return true; + case void => void; + }; + }; + }; + i += 1; }; return false; };