@@ -10,6 +10,7 @@ public import Init.Data.String.Pattern
1010public import Init.Data.Ord.Basic
1111public import Init.Data.Iterators.Combinators.FilterMap
1212public import Init.Data.String.ToSlice
13+ public import Init.Data.String.Termination
1314
1415set_option doc.verso true
1516
@@ -403,19 +404,19 @@ Examples:
403404 * {lean}`"red green blue".toSlice.dropWhile (fun (_ : Char) => true) == "".toSlice`
404405 -/
405406@[inline]
406- partial def dropWhile [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
407- go s
407+ def dropWhile [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
408+ go s.startPos
408409where
409410 @[specialize pat]
410- go (s : Slice) : Slice :=
411- if let some nextS := dropPrefix? s pat then
412- -- TODO: need lawful patterns to show this terminates
413- if s.startInclusive.offset < nextS.startInclusive.offset then
414- go nextS
411+ go (curr : s.Pos) : Slice :=
412+ if let some nextCurr := ForwardPattern.dropPrefix? (s.replaceStart curr) pat then
413+ if curr < Pos.ofReplaceStart nextCurr then
414+ go (Pos.ofReplaceStart nextCurr)
415415 else
416- s
416+ s.replaceStart curr
417417 else
418- s
418+ s.replaceStart curr
419+ termination_by curr
419420
420421/--
421422Removes leading whitespace from a slice by moving its start position to the first non-whitespace
@@ -463,19 +464,19 @@ Examples:
463464 * {lean}`"red green blue".toSlice.takeWhile (fun (_ : Char) => true) == "red green blue".toSlice`
464465 -/
465466@[inline]
466- partial def takeWhile [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
467+ def takeWhile [ForwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
467468 go s.startPos
468469where
469470 @[specialize pat]
470471 go (curr : s.Pos) : Slice :=
471472 if let some nextCurr := ForwardPattern.dropPrefix? (s.replaceStart curr) pat then
472- if (s.replaceStart curr).startPos < nextCurr then
473- -- TODO: need lawful patterns to show this terminates
473+ if curr < Pos.ofReplaceStart nextCurr then
474474 go (Pos.ofReplaceStart nextCurr)
475475 else
476476 s.replaceEnd curr
477477 else
478478 s.replaceEnd curr
479+ termination_by curr
479480
480481/--
481482Finds the position of the first match of the pattern {name}`pat` in a slice {name}`s`. If there
@@ -712,23 +713,23 @@ Examples:
712713 * {lean}`"red green blue".toSlice.dropEndWhile (fun (_ : Char) => true) == "".toSlice`
713714 -/
714715@[inline]
715- partial def dropEndWhile [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
716- go s
716+ def dropEndWhile [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
717+ go s.endPos
717718where
718719 @[specialize pat]
719- go (s : Slice) : Slice :=
720- if let some nextS := dropSuffix? s pat then
721- -- TODO: need lawful patterns to show this terminates
722- if nextS.endExclusive.offset < s.endExclusive.offset then
723- go nextS
720+ go (curr : s.Pos) : Slice :=
721+ if let some nextCurr := BackwardPattern.dropSuffix? (s.replaceEnd curr) pat then
722+ if Pos.ofReplaceEnd nextCurr < curr then
723+ go (Pos.ofReplaceEnd nextCurr)
724724 else
725- s
725+ s.replaceEnd curr
726726 else
727- s
727+ s.replaceEnd curr
728+ termination_by curr.down
728729
729730/--
730- Removes trailing whitespace from a slice by moving its start position to the first non-whitespace
731- character, or to its end position if there is no non-whitespace character.
731+ Removes trailing whitespace from a slice by moving its end position to the last non-whitespace
732+ character, or to its start position if there is no non-whitespace character.
732733
733734“Whitespace” is defined as characters for which {name}`Char.isWhitespace` returns {name}`true`.
734735
@@ -771,19 +772,19 @@ Examples:
771772 * {lean}`"red green blue".toSlice.takeEndWhile (fun (_ : Char) => true) == "red green blue".toSlice`
772773 -/
773774@[inline]
774- partial def takeEndWhile [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
775+ def takeEndWhile [BackwardPattern ρ] (s : Slice) (pat : ρ) : Slice :=
775776 go s.endPos
776777where
777778 @[specialize pat]
778779 go (curr : s.Pos) : Slice :=
779780 if let some nextCurr := BackwardPattern.dropSuffix? (s.replaceEnd curr) pat then
780- if nextCurr < (s.replaceEnd curr).endPos then
781- -- TODO: need lawful patterns to show this terminates
781+ if Pos.ofReplaceEnd nextCurr < curr then
782782 go (Pos.ofReplaceEnd nextCurr)
783783 else
784784 s.replaceStart curr
785785 else
786786 s.replaceStart curr
787+ termination_by curr.down
787788
788789/--
789790Finds the position of the first match of the pattern {name}`pat` in a slice {name}`true`, starting
@@ -1338,4 +1339,36 @@ Examples:
13381339def back (s : Slice) : Char :=
13391340 s.back?.getD default
13401341
1342+ /--
1343+ Appends the slices in a list of slices, placing the separator {name}`s` between each pair.
1344+
1345+ Examples:
1346+ * {lean}`", ".toSlice.intercalate ["red".toSlice, "green".toSlice, "blue".toSlice] = "red, green, blue"`
1347+ * {lean}`" and ".toSlice.intercalate ["tea".toSlice, "coffee".toSlice] = "tea and coffee"`
1348+ * {lean}`" | ".toSlice.intercalate ["M".toSlice, "".toSlice, "N".toSlice] = "M | | N"`
1349+ -/
1350+ def intercalate (s : Slice) : List Slice → String
1351+ | [] => ""
1352+ | a :: as => go a.copy s as
1353+ where go (acc : String) (s : Slice) : List Slice → String
1354+ | a :: as => go (acc ++ s ++ a) s as
1355+ | [] => acc
1356+
1357+ @[inherit_doc Slice.copy]
1358+ def toString (s : Slice) : String :=
1359+ s.copy
1360+
1361+ instance : ToString String.Slice where
1362+ toString := toString
1363+
1364+ /--
1365+ Converts a string to the Lean compiler's representation of names. The resulting name is
1366+ hierarchical, and the string is split at the dots ({lean}`'.'`).
1367+
1368+ {lean}`"a.b".toSlice.toName` is the name {lit}`a.b`, not {lit}`«a.b»`. For the latter, use
1369+ `Name.mkSimple`.
1370+ -/
1371+ def toName (s : Slice) : Lean.Name :=
1372+ s.toString.toName
1373+
13411374end String.Slice
0 commit comments