Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bend2/comp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,10 @@ function char_code(s) {
}

function string_contains(s, p) {
// Without a packed-Char marker, native substring search respects boundaries.
if (!s.includes("\uDC00")) {
return s.includes(p);
}
// A match must start at a Char boundary, not inside a packed U32 code.
for (let at = 0; at <= s.length; at += char_len(s, at)) {
if (s.startsWith(p, at)) {
Expand Down
6 changes: 4 additions & 2 deletions guide/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,8 @@ def main() -> String:
U32.show(a) ++ " = " ++ Nat.show(b)
```

Every def is named `Type.verb`, and the same verbs recur across `Nat`, `U32`
and `F32`: `add sub mul div mod` for arithmetic, `and or xor not shl shr` for
Names follow `Type.verb`; `Nat`, `U32` and `F32` share verbs:
`add sub mul div mod` for arithmetic, `and or xor not shl shr` for
bits (`U32` only), `cmp` (returning `Cmp`, not on `F32`) and `is_eq is_ne is_lt
is_le is_gt is_ge` (returning `Bool`) for comparisons, `show` to `String` and
`read` back from it (answering a `Maybe`). Operators and `<`-style comparisons
Expand All @@ -500,6 +500,8 @@ result), `Set` on top of it, the `Equal` lemmas, and the effects. `bend base`
prints all of it, `bend base --types` only the types, and `bend base Map` one
name and everything under it.

String searches respect Char boundaries.

### Modules

A module is a file, and an import gives it a local name:
Expand Down
22 changes: 22 additions & 0 deletions tests/base/string_contains_boundaries.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Base

def packed(n: U32) -> String:
SCon{Char.from_u32(n), ""}

def main() -> IO(Unit):
do IO<Unit>:
IO.print(Bool.show(String.contains("abc", "")))
IO.print(Bool.show(String.contains("hello", "ell")))
IO.print(Bool.show(String.contains("hello", "x")))
IO.print(Bool.show(String.contains("a\u{1F600}b", "\u{1F600}")))
IO.print(Bool.show(String.contains(packed(1114177), "A")))
IO.print(Bool.show(String.contains("\u{10000}abc", packed(407048291))))
IO.print(Bool.show(String.contains(SCon{Char.from_u32(1114177), "A"}, "A")))

#|True
#|True
#|False
#|True
#|False
#|False
#|True