chore: move some material out of Init.Data.String.Basic (#10893)
This PR splits some low-hanging fruit out of `Init.Data.String.Basic`: basic material about `String.Pos.Raw`, `String.Substrig`, and `String.Iterator`. More splitting required and the remaining material is quite unorganized, but it's a start.
This commit is contained in:
parent
08bc333705
commit
b5dc11e8d3
40 changed files with 1456 additions and 1325 deletions
|
|
@ -16,3 +16,6 @@ public import Init.Data.String.Bootstrap
|
|||
public import Init.Data.String.Slice
|
||||
public import Init.Data.String.Pattern
|
||||
public import Init.Data.String.Stream
|
||||
public import Init.Data.String.PosRaw
|
||||
public import Init.Data.String.Substring
|
||||
public import Init.Data.String.TakeDrop
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -9,9 +9,24 @@ prelude
|
|||
import all Init.Data.ByteArray.Basic
|
||||
public import Init.Data.String.Basic
|
||||
import all Init.Data.String.Basic
|
||||
public import Init.Data.String.Iterator
|
||||
import all Init.Data.String.Iterator
|
||||
public import Init.Data.String.Substring
|
||||
|
||||
public section
|
||||
|
||||
namespace Substring
|
||||
|
||||
/--
|
||||
Returns an iterator into the underlying string, at the substring's starting position. The ending
|
||||
position is discarded, so the iterator alone cannot be used to determine whether its current
|
||||
position is within the original substring.
|
||||
-/
|
||||
@[inline] def toIterator : Substring → String.Iterator
|
||||
| ⟨s, b, _⟩ => ⟨s, b⟩
|
||||
|
||||
end Substring
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
|
|
|
|||
206
src/Init/Data/String/Iterator.lean
Normal file
206
src/Init/Data/String/Iterator.lean
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
/-!
|
||||
# `String.Iterator`
|
||||
|
||||
This file contains `String.Iterator`, an outgoing API to be replaced by the iterator framework in
|
||||
a future release.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
An iterator over the characters (Unicode code points) in a `String`. Typically created by
|
||||
`String.iter`.
|
||||
|
||||
String iterators pair a string with a valid byte index. This allows efficient character-by-character
|
||||
processing of strings while avoiding the need to manually ensure that byte indices are used with the
|
||||
correct strings.
|
||||
|
||||
An iterator is *valid* if the position `i` is *valid* for the string `s`, meaning `0 ≤ i ≤ s.rawEndPos`
|
||||
and `i` lies on a UTF8 byte boundary. If `i = s.rawEndPos`, the iterator is at the end of the string.
|
||||
|
||||
Most operations on iterators return unspecified values if the iterator is not valid. The functions
|
||||
in the `String.Iterator` API rule out the creation of invalid iterators, with two exceptions:
|
||||
- `Iterator.next iter` is invalid if `iter` is already at the end of the string (`iter.atEnd` is
|
||||
`true`), and
|
||||
- `Iterator.forward iter n`/`Iterator.nextn iter n` is invalid if `n` is strictly greater than the
|
||||
number of remaining characters.
|
||||
-/
|
||||
structure Iterator where
|
||||
/-- The string being iterated over. -/
|
||||
s : String
|
||||
/-- The current UTF-8 byte position in the string `s`.
|
||||
|
||||
This position is not guaranteed to be valid for the string. If the position is not valid, then the
|
||||
current character is `(default : Char)`, similar to `String.get` on an invalid position.
|
||||
-/
|
||||
i : Pos.Raw
|
||||
deriving DecidableEq, Inhabited
|
||||
|
||||
/-- Creates an iterator at the beginning of the string. -/
|
||||
@[inline] def mkIterator (s : String) : Iterator :=
|
||||
⟨s, 0⟩
|
||||
|
||||
@[inherit_doc mkIterator]
|
||||
abbrev iter := mkIterator
|
||||
|
||||
/--
|
||||
The size of a string iterator is the number of bytes remaining.
|
||||
|
||||
Recursive functions that iterate towards the end of a string will typically decrease this measure.
|
||||
-/
|
||||
instance : SizeOf String.Iterator where
|
||||
sizeOf i := i.1.utf8ByteSize - i.2.byteIdx
|
||||
|
||||
theorem Iterator.sizeOf_eq (i : String.Iterator) : sizeOf i = i.1.utf8ByteSize - i.2.byteIdx :=
|
||||
rfl
|
||||
|
||||
namespace Iterator
|
||||
@[inline, inherit_doc Iterator.s]
|
||||
def toString := Iterator.s
|
||||
|
||||
/--
|
||||
The number of UTF-8 bytes remaining in the iterator.
|
||||
-/
|
||||
@[inline] def remainingBytes : Iterator → Nat
|
||||
| ⟨s, i⟩ => s.rawEndPos.byteIdx - i.byteIdx
|
||||
|
||||
@[inline, inherit_doc Iterator.i]
|
||||
def pos := Iterator.i
|
||||
|
||||
/--
|
||||
Gets the character at the iterator's current position.
|
||||
|
||||
A run-time bounds check is performed. Use `String.Iterator.curr'` to avoid redundant bounds checks.
|
||||
|
||||
If the position is invalid, returns `(default : Char)`.
|
||||
-/
|
||||
@[inline] def curr : Iterator → Char
|
||||
| ⟨s, i⟩ => i.get s
|
||||
|
||||
/--
|
||||
Moves the iterator's position forward by one character, unconditionally.
|
||||
|
||||
It is only valid to call this function if the iterator is not at the end of the string (i.e.
|
||||
if `Iterator.atEnd` is `false`); otherwise, the resulting iterator will be invalid.
|
||||
-/
|
||||
@[inline] def next : Iterator → Iterator
|
||||
| ⟨s, i⟩ => ⟨s, i.next s⟩
|
||||
|
||||
/--
|
||||
Moves the iterator's position backward by one character, unconditionally.
|
||||
|
||||
The position is not changed if the iterator is at the beginning of the string.
|
||||
-/
|
||||
@[inline] def prev : Iterator → Iterator
|
||||
| ⟨s, i⟩ => ⟨s, i.prev s⟩
|
||||
|
||||
/--
|
||||
Checks whether the iterator is past its string's last character.
|
||||
-/
|
||||
@[inline] def atEnd : Iterator → Bool
|
||||
| ⟨s, i⟩ => i.byteIdx ≥ s.rawEndPos.byteIdx
|
||||
|
||||
/--
|
||||
Checks whether the iterator is at or before the string's last character.
|
||||
-/
|
||||
@[inline] def hasNext : Iterator → Bool
|
||||
| ⟨s, i⟩ => i.byteIdx < s.rawEndPos.byteIdx
|
||||
|
||||
/--
|
||||
Checks whether the iterator is after the beginning of the string.
|
||||
-/
|
||||
@[inline] def hasPrev : Iterator → Bool
|
||||
| ⟨_, i⟩ => i.byteIdx > 0
|
||||
|
||||
/--
|
||||
Gets the character at the iterator's current position.
|
||||
|
||||
The proof of `it.hasNext` ensures that there is, in fact, a character at the current position. This
|
||||
function is faster that `String.Iterator.curr` due to avoiding a run-time bounds check.
|
||||
-/
|
||||
@[inline] def curr' (it : Iterator) (h : it.hasNext) : Char :=
|
||||
match it with
|
||||
| ⟨s, i⟩ => i.get' s (by simpa only [hasNext, rawEndPos, decide_eq_true_eq, Pos.Raw.atEnd, ge_iff_le, Nat.not_le] using h)
|
||||
|
||||
/--
|
||||
Moves the iterator's position forward by one character, unconditionally.
|
||||
|
||||
The proof of `it.hasNext` ensures that there is, in fact, a position that's one character forwards.
|
||||
This function is faster that `String.Iterator.next` due to avoiding a run-time bounds check.
|
||||
-/
|
||||
@[inline] def next' (it : Iterator) (h : it.hasNext) : Iterator :=
|
||||
match it with
|
||||
| ⟨s, i⟩ => ⟨s, i.next' s (by simpa only [hasNext, rawEndPos, decide_eq_true_eq, Pos.Raw.atEnd, ge_iff_le, Nat.not_le] using h)⟩
|
||||
|
||||
/--
|
||||
Replaces the current character in the string.
|
||||
|
||||
Does nothing if the iterator is at the end of the string. If both the replacement character and the
|
||||
replaced character are 7-bit ASCII characters and the string is not shared, then it is updated
|
||||
in-place and not copied.
|
||||
-/
|
||||
@[inline] def setCurr : Iterator → Char → Iterator
|
||||
| ⟨s, i⟩, c => ⟨i.set s c, i⟩
|
||||
|
||||
/--
|
||||
Moves the iterator's position to the end of the string, just past the last character.
|
||||
-/
|
||||
@[inline] def toEnd : Iterator → Iterator
|
||||
| ⟨s, _⟩ => ⟨s, s.rawEndPos⟩
|
||||
|
||||
/--
|
||||
Extracts the substring between the positions of two iterators. The first iterator's position is the
|
||||
start of the substring, and the second iterator's position is the end.
|
||||
|
||||
Returns the empty string if the iterators are for different strings, or if the position of the first
|
||||
iterator is past the position of the second iterator.
|
||||
-/
|
||||
@[inline] def extract : Iterator → Iterator → String
|
||||
| ⟨s₁, b⟩, ⟨s₂, e⟩ =>
|
||||
if s₁ ≠ s₂ || b > e then ""
|
||||
else b.extract s₁ e
|
||||
|
||||
/--
|
||||
Moves the iterator's position forward by the specified number of characters.
|
||||
|
||||
The resulting iterator is only valid if the number of characters to skip is less than or equal
|
||||
to the number of characters left in the iterator.
|
||||
-/
|
||||
def forward : Iterator → Nat → Iterator
|
||||
| it, 0 => it
|
||||
| it, n+1 => forward it.next n
|
||||
|
||||
/--
|
||||
The remaining characters in an iterator, as a string.
|
||||
-/
|
||||
@[inline] def remainingToString : Iterator → String
|
||||
| ⟨s, i⟩ => i.extract s s.rawEndPos
|
||||
|
||||
@[inherit_doc forward]
|
||||
def nextn : Iterator → Nat → Iterator
|
||||
| it, 0 => it
|
||||
| it, i+1 => nextn it.next i
|
||||
|
||||
/--
|
||||
Moves the iterator's position back by the specified number of characters, stopping at the beginning
|
||||
of the string.
|
||||
-/
|
||||
def prevn : Iterator → Nat → Iterator
|
||||
| it, 0 => it
|
||||
| it, i+1 => prevn it.prev i
|
||||
|
||||
end Iterator
|
||||
|
||||
end String
|
||||
353
src/Init/Data/String/PosRaw.lean
Normal file
353
src/Init/Data/String/PosRaw.lean
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.ByteArray.Basic
|
||||
|
||||
/-!
|
||||
# Arithmetic of `String.Pos.Raw`
|
||||
|
||||
This file contains basic theory about which does not actually need to know anything about strings
|
||||
and therefore does not depend on `Init.Data.String.Decode`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
attribute [ext] String.Pos.Raw
|
||||
|
||||
instance : HSub String.Pos.Raw String String.Pos.Raw where
|
||||
hSub p s := { byteIdx := p.byteIdx - s.utf8ByteSize }
|
||||
|
||||
instance : HSub String.Pos.Raw Char String.Pos.Raw where
|
||||
hSub p c := { byteIdx := p.byteIdx - c.utf8Size }
|
||||
|
||||
@[export lean_string_pos_sub]
|
||||
def Pos.Internal.subImpl : String.Pos.Raw → String.Pos.Raw → String.Pos.Raw :=
|
||||
fun p₁ p₂ => ⟨p₁.byteIdx - p₂.byteIdx⟩
|
||||
|
||||
instance : HAdd String.Pos.Raw Char String.Pos.Raw where
|
||||
hAdd p c := { byteIdx := p.byteIdx + c.utf8Size }
|
||||
|
||||
instance : HAdd Char String.Pos.Raw String.Pos.Raw where
|
||||
hAdd c p := { byteIdx := c.utf8Size + p.byteIdx }
|
||||
|
||||
instance : HAdd String String.Pos.Raw String.Pos.Raw where
|
||||
hAdd s p := { byteIdx := s.utf8ByteSize + p.byteIdx }
|
||||
|
||||
instance : HAdd String.Pos.Raw String String.Pos.Raw where
|
||||
hAdd p s := { byteIdx := p.byteIdx + s.utf8ByteSize }
|
||||
|
||||
instance : LE String.Pos.Raw where
|
||||
le p₁ p₂ := p₁.byteIdx ≤ p₂.byteIdx
|
||||
|
||||
instance : LT String.Pos.Raw where
|
||||
lt p₁ p₂ := p₁.byteIdx < p₂.byteIdx
|
||||
|
||||
instance (p₁ p₂ : String.Pos.Raw) : Decidable (p₁ ≤ p₂) :=
|
||||
inferInstanceAs (Decidable (p₁.byteIdx ≤ p₂.byteIdx))
|
||||
|
||||
instance (p₁ p₂ : String.Pos.Raw) : Decidable (p₁ < p₂) :=
|
||||
inferInstanceAs (Decidable (p₁.byteIdx < p₂.byteIdx))
|
||||
|
||||
instance : Min String.Pos.Raw := minOfLe
|
||||
instance : Max String.Pos.Raw := maxOfLe
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_sub_char {p : Pos.Raw} {c : Char} : (p - c).byteIdx = p.byteIdx - c.utf8Size := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_sub_string {p : Pos.Raw} {s : String} : (p - s).byteIdx = p.byteIdx - s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_add_string {p : Pos.Raw} {s : String} : (p + s).byteIdx = p.byteIdx + s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_string_add {s : String} {p : Pos.Raw} : (s + p).byteIdx = s.utf8ByteSize + p.byteIdx := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_add_char {p : Pos.Raw} {c : Char} : (p + c).byteIdx = p.byteIdx + c.utf8Size := rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_char_add {c : Char} {p : Pos.Raw} : (c + p).byteIdx = c.utf8Size + p.byteIdx := rfl
|
||||
|
||||
|
||||
theorem Pos.Raw.le_iff {i₁ i₂ : Pos.Raw} : i₁ ≤ i₂ ↔ i₁.byteIdx ≤ i₂.byteIdx := .rfl
|
||||
|
||||
theorem Pos.Raw.lt_iff {i₁ i₂ : Pos.Raw} : i₁ < i₂ ↔ i₁.byteIdx < i₂.byteIdx := .rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_zero : (0 : Pos.Raw).byteIdx = 0 := rfl
|
||||
|
||||
/--
|
||||
Returns the size of the byte slice delineated by the positions `lo` and `hi`.
|
||||
-/
|
||||
@[expose, inline]
|
||||
def Pos.Raw.byteDistance (lo hi : Pos.Raw) : Nat :=
|
||||
hi.byteIdx - lo.byteIdx
|
||||
|
||||
theorem Pos.Raw.byteDistance_eq {lo hi : Pos.Raw} : lo.byteDistance hi = hi.byteIdx - lo.byteIdx :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem rawEndPos_empty : "".rawEndPos = 0 := rfl
|
||||
|
||||
@[deprecated rawEndPos_empty (since := "2025-10-20")]
|
||||
theorem endPos_empty : "".rawEndPos = 0 := rfl
|
||||
|
||||
/--
|
||||
Accesses the indicated byte in the UTF-8 encoding of a string.
|
||||
|
||||
At runtime, this function is implemented by efficient, constant-time code.
|
||||
-/
|
||||
@[extern "lean_string_get_byte_fast", expose]
|
||||
def getUTF8Byte (s : @& String) (p : Pos.Raw) (h : p < s.rawEndPos) : UInt8 :=
|
||||
s.bytes[p.byteIdx]
|
||||
|
||||
@[deprecated getUTF8Byte (since := "2025-10-01"), extern "lean_string_get_byte_fast", expose]
|
||||
abbrev getUtf8Byte (s : String) (p : Pos.Raw) (h : p < s.rawEndPos) : UInt8 :=
|
||||
s.getUTF8Byte p h
|
||||
|
||||
protected theorem Pos.Raw.le_trans {a b c : Pos.Raw} : a ≤ b → b ≤ c → a ≤ c := by
|
||||
simpa [le_iff] using Nat.le_trans
|
||||
|
||||
protected theorem Pos.Raw.lt_of_lt_of_le {a b c : Pos.Raw} : a < b → b ≤ c → a < c := by
|
||||
simpa [le_iff, lt_iff] using Nat.lt_of_lt_of_le
|
||||
|
||||
/--
|
||||
Offsets `p` by `offset` on the left. This is not an `HAdd` instance because it should be a
|
||||
relatively rare operation, so we use a name to make accidental use less likely. To offset a position
|
||||
by the size of a character character `c` or string `s`, you can use `c + p` resp. `s + p`.
|
||||
|
||||
This should be seen as an operation that converts relative positions into absolute positions.
|
||||
|
||||
See also `Pos.Raw.increaseBy`, which is an "advancing" operation.
|
||||
-/
|
||||
@[expose, inline]
|
||||
def Pos.Raw.offsetBy (p : Pos.Raw) (offset : Pos.Raw) : Pos.Raw where
|
||||
byteIdx := offset.byteIdx + p.byteIdx
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_offsetBy {p : Pos.Raw} {offset : Pos.Raw} :
|
||||
(p.offsetBy offset).byteIdx = offset.byteIdx + p.byteIdx := (rfl)
|
||||
|
||||
theorem Pos.Raw.offsetBy_assoc {p q r : Pos.Raw} :
|
||||
(p.offsetBy q).offsetBy r = p.offsetBy (q.offsetBy r) := by
|
||||
ext
|
||||
simp [Nat.add_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.offsetBy_zero_left {p : Pos.Raw} : (0 : Pos.Raw).offsetBy p = p := by
|
||||
ext
|
||||
simp
|
||||
|
||||
/--
|
||||
Decreases `p` by `offset`. This is not an `HSub` instance because it should be a relatively
|
||||
rare operation, so we use a name to make accidental use less likely. To unoffset a position
|
||||
by the size of a character `c` or string `s`, you can use `p - c` resp. `p - s`.
|
||||
|
||||
This should be seen as an operation that converts absolute positions into relative positions.
|
||||
|
||||
See also `Pos.Raw.decreaseBy`, which is an "unadvancing" operation.
|
||||
-/
|
||||
@[expose, inline]
|
||||
def Pos.Raw.unoffsetBy (p : Pos.Raw) (offset : Pos.Raw) : Pos.Raw where
|
||||
byteIdx := p.byteIdx - offset.byteIdx
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_unoffsetBy {p : Pos.Raw} {offset : Pos.Raw} :
|
||||
(p.unoffsetBy offset).byteIdx = p.byteIdx - offset.byteIdx := (rfl)
|
||||
|
||||
theorem Pos.Raw.offsetBy_unoffsetBy_of_le {p : Pos.Raw} {q : Pos.Raw} (h : q ≤ p) :
|
||||
(p.unoffsetBy q).offsetBy q = p := by
|
||||
ext
|
||||
simp_all [le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.unoffsetBy_offsetBy {p q : Pos.Raw} : (p.offsetBy q).unoffsetBy q = p := by
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.eq_zero_iff {p : Pos.Raw} : p = 0 ↔ p.byteIdx = 0 :=
|
||||
Pos.Raw.ext_iff
|
||||
|
||||
/--
|
||||
Advances `p` by `n` bytes. This is not an `HAdd` instance because it should be a relatively
|
||||
rare operation, so we use a name to make accidental use less likely. To add the size of a
|
||||
character `c` or string `s` to a raw position `p`, you can use `p + c` resp. `p + s`.
|
||||
|
||||
This should be seen as an "advance" or "skip".
|
||||
|
||||
See also `Pos.Raw.offsetBy`, which turns relative positions into absolute positions.
|
||||
-/
|
||||
@[expose, inline]
|
||||
def Pos.Raw.increaseBy (p : Pos.Raw) (n : Nat) : Pos.Raw where
|
||||
byteIdx := p.byteIdx + n
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_increaseBy {p : Pos.Raw} {n : Nat} :
|
||||
(p.increaseBy n).byteIdx = p.byteIdx + n := (rfl)
|
||||
|
||||
/--
|
||||
Move the position `p` back by `n` bytes. This is not an `HSub` instance because it should be a
|
||||
relatively rare operation, so we use a name to make accidental use less likely. To remove the size
|
||||
of a character `c` or string `s` from a raw position `p`, you can use `p - c` resp. `p - s`.
|
||||
|
||||
This should be seen as the inverse of an "advance" or "skip".
|
||||
|
||||
See also `Pos.Raw.unoffsetBy`, which turns absolute positions into relative positions.
|
||||
-/
|
||||
@[expose, inline]
|
||||
def Pos.Raw.decreaseBy (p : Pos.Raw) (n : Nat) : Pos.Raw where
|
||||
byteIdx := p.byteIdx - n
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_decreaseBy {p : Pos.Raw} {n : Nat} :
|
||||
(p.decreaseBy n).byteIdx = p.byteIdx - n := (rfl)
|
||||
|
||||
theorem Pos.Raw.increaseBy_charUtf8Size {p : Pos.Raw} {c : Char} :
|
||||
p.increaseBy c.utf8Size = p + c := by
|
||||
simp [Pos.Raw.ext_iff]
|
||||
|
||||
/-- Increases the byte offset of the position by `1`. Not to be confused with `ValidPos.next`. -/
|
||||
@[inline, expose]
|
||||
def Pos.Raw.inc (p : Pos.Raw) : Pos.Raw :=
|
||||
⟨p.byteIdx + 1⟩
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_inc {p : Pos.Raw} : p.inc.byteIdx = p.byteIdx + 1 := (rfl)
|
||||
|
||||
/-- Decreases the byte offset of the position by `1`. Not to be confused with `ValidPos.prev`. -/
|
||||
@[inline, expose]
|
||||
def Pos.Raw.dec (p : Pos.Raw) : Pos.Raw :=
|
||||
⟨p.byteIdx - 1⟩
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.byteIdx_dec {p : Pos.Raw} : p.dec.byteIdx = p.byteIdx - 1 := (rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Pos.Raw.le_refl {p : Pos.Raw} : p ≤ p := by simp [le_iff]
|
||||
|
||||
theorem Pos.Raw.lt_inc {p : Pos.Raw} : p < p.inc := by simp [lt_iff]
|
||||
|
||||
theorem Pos.Raw.le_of_lt {p q : Pos.Raw} : p < q → p ≤ q := by simpa [lt_iff, le_iff] using Nat.le_of_lt
|
||||
|
||||
theorem Pos.Raw.inc_le {p q : Pos.Raw} : p.inc ≤ q ↔ p < q := by simpa [lt_iff, le_iff] using Nat.succ_le
|
||||
|
||||
theorem Pos.Raw.lt_of_le_of_lt {a b c : Pos.Raw} : a ≤ b → b < c → a < c := by
|
||||
simpa [le_iff, lt_iff] using Nat.lt_of_le_of_lt
|
||||
|
||||
theorem Pos.Raw.ne_of_lt {a b : Pos.Raw} : a < b → a ≠ b := by
|
||||
simpa [lt_iff, Pos.Raw.ext_iff] using Nat.ne_of_lt
|
||||
|
||||
@[deprecated Pos.Raw.lt_iff (since := "2025-10-10")]
|
||||
theorem pos_lt_eq (p₁ p₂ : Pos.Raw) : (p₁ < p₂) = (p₁.1 < p₂.1) :=
|
||||
propext Pos.Raw.lt_iff
|
||||
|
||||
@[deprecated Pos.Raw.byteIdx_add_char (since := "2025-10-10")]
|
||||
theorem pos_add_char (p : Pos.Raw) (c : Char) : (p + c).byteIdx = p.byteIdx + c.utf8Size :=
|
||||
Pos.Raw.byteIdx_add_char
|
||||
|
||||
protected theorem Pos.Raw.ne_zero_of_lt : {a b : Pos.Raw} → a < b → b ≠ 0
|
||||
| _, _, hlt, rfl => Nat.not_lt_zero _ hlt
|
||||
|
||||
/--
|
||||
Returns either `p₁` or `p₂`, whichever has the least byte index.
|
||||
-/
|
||||
protected abbrev Pos.Raw.min (p₁ p₂ : Pos.Raw) : Pos.Raw :=
|
||||
{ byteIdx := p₁.byteIdx.min p₂.byteIdx }
|
||||
|
||||
@[export lean_string_pos_min]
|
||||
def Pos.Raw.Internal.minImpl (p₁ p₂ : Pos.Raw) : Pos.Raw :=
|
||||
Pos.Raw.min p₁ p₂
|
||||
|
||||
namespace Pos.Raw
|
||||
|
||||
theorem byteIdx_mk (n : Nat) : byteIdx ⟨n⟩ = n := rfl
|
||||
|
||||
@[simp] theorem mk_zero : ⟨0⟩ = (0 : Pos.Raw) := rfl
|
||||
|
||||
@[simp] theorem mk_byteIdx (p : Pos.Raw) : ⟨p.byteIdx⟩ = p := rfl
|
||||
|
||||
@[deprecated byteIdx_offsetBy (since := "2025-10-08")]
|
||||
theorem add_byteIdx {p₁ p₂ : Pos.Raw} : (p₂.offsetBy p₁).byteIdx = p₁.byteIdx + p₂.byteIdx := by
|
||||
simp
|
||||
|
||||
@[deprecated byteIdx_offsetBy (since := "2025-10-08")]
|
||||
theorem add_eq {p₁ p₂ : Pos.Raw} : p₂.offsetBy p₁ = ⟨p₁.byteIdx + p₂.byteIdx⟩ := rfl
|
||||
|
||||
@[deprecated byteIdx_unoffsetBy (since := "2025-10-08")]
|
||||
theorem sub_byteIdx (p₁ p₂ : Pos.Raw) : (p₁.unoffsetBy p₂).byteIdx = p₁.byteIdx - p₂.byteIdx := rfl
|
||||
|
||||
@[deprecated byteIdx_add_char (since := "2025-10-10")]
|
||||
theorem addChar_byteIdx (p : Pos.Raw) (c : Char) : (p + c).byteIdx = p.byteIdx + c.utf8Size :=
|
||||
byteIdx_add_char
|
||||
|
||||
theorem add_char_eq (p : Pos.Raw) (c : Char) : p + c = ⟨p.byteIdx + c.utf8Size⟩ := rfl
|
||||
|
||||
@[deprecated add_char_eq (since := "2025-10-10")]
|
||||
theorem addChar_eq (p : Pos.Raw) (c : Char) : p + c = ⟨p.byteIdx + c.utf8Size⟩ :=
|
||||
add_char_eq p c
|
||||
|
||||
theorem byteIdx_zero_add_char (c : Char) : ((0 : Pos.Raw) + c).byteIdx = c.utf8Size := by
|
||||
simp only [byteIdx_add_char, byteIdx_zero, Nat.zero_add]
|
||||
|
||||
@[deprecated byteIdx_zero_add_char (since := "2025-10-10")]
|
||||
theorem zero_addChar_byteIdx (c : Char) : ((0 : Pos.Raw) + c).byteIdx = c.utf8Size :=
|
||||
byteIdx_zero_add_char c
|
||||
|
||||
theorem zero_add_char_eq (c : Char) : (0 : Pos.Raw) + c = ⟨c.utf8Size⟩ := by rw [← byteIdx_zero_add_char]
|
||||
|
||||
@[deprecated zero_add_char_eq (since := "2025-10-10")]
|
||||
theorem zero_addChar_eq (c : Char) : (0 : Pos.Raw) + c = ⟨c.utf8Size⟩ :=
|
||||
zero_add_char_eq c
|
||||
|
||||
theorem add_char_right_comm (p : Pos.Raw) (c₁ c₂ : Char) : p + c₁ + c₂ = p + c₂ + c₁ := by
|
||||
simpa [Pos.Raw.ext_iff] using Nat.add_right_comm ..
|
||||
|
||||
@[deprecated add_char_right_comm (since := "2025-10-10")]
|
||||
theorem addChar_right_comm (p : Pos.Raw) (c₁ c₂ : Char) : p + c₁ + c₂ = p + c₂ + c₁ :=
|
||||
add_char_right_comm p c₁ c₂
|
||||
|
||||
theorem ne_of_gt {i₁ i₂ : Pos.Raw} (h : i₁ < i₂) : i₂ ≠ i₁ := (ne_of_lt h).symm
|
||||
|
||||
@[deprecated byteIdx_add_string (since := "2025-10-10")]
|
||||
theorem byteIdx_addString (p : Pos.Raw) (s : String) :
|
||||
(p + s).byteIdx = p.byteIdx + s.utf8ByteSize := byteIdx_add_string
|
||||
|
||||
@[deprecated byteIdx_addString (since := "2025-03-18")]
|
||||
abbrev addString_byteIdx := @byteIdx_add_string
|
||||
|
||||
theorem addString_eq (p : Pos.Raw) (s : String) : p + s = ⟨p.byteIdx + s.utf8ByteSize⟩ := rfl
|
||||
|
||||
theorem byteIdx_zero_add_string (s : String) : ((0 : Pos.Raw) + s).byteIdx = s.utf8ByteSize := by
|
||||
simp only [byteIdx_add_string, byteIdx_zero, Nat.zero_add]
|
||||
|
||||
@[deprecated byteIdx_zero_add_string (since := "2025-10-10")]
|
||||
theorem byteIdx_zero_addString (s : String) : ((0 : Pos.Raw) + s).byteIdx = s.utf8ByteSize :=
|
||||
byteIdx_zero_add_string s
|
||||
|
||||
@[deprecated byteIdx_zero_addString (since := "2025-03-18")]
|
||||
abbrev zero_addString_byteIdx := @byteIdx_zero_add_string
|
||||
|
||||
theorem zero_add_string_eq (s : String) : (0 : Pos.Raw) + s = ⟨s.utf8ByteSize⟩ := by
|
||||
rw [← byteIdx_zero_add_string]
|
||||
|
||||
@[deprecated zero_add_string_eq (since := "2025-10-10")]
|
||||
theorem zero_addString_eq (s : String) : (0 : Pos.Raw) + s = ⟨s.utf8ByteSize⟩ :=
|
||||
zero_add_string_eq s
|
||||
|
||||
@[simp] theorem mk_le_mk {i₁ i₂ : Nat} : Pos.Raw.mk i₁ ≤ Pos.Raw.mk i₂ ↔ i₁ ≤ i₂ := .rfl
|
||||
|
||||
@[simp] theorem mk_lt_mk {i₁ i₂ : Nat} : Pos.Raw.mk i₁ < Pos.Raw.mk i₂ ↔ i₁ < i₂ := .rfl
|
||||
|
||||
end Pos.Raw
|
||||
|
||||
end String
|
||||
|
|
@ -6,7 +6,8 @@ Author: Leonardo de Moura, Mario Carneiro
|
|||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Substring
|
||||
public import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
521
src/Init/Data/String/Substring.lean
Normal file
521
src/Init/Data/String/Substring.lean
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
/-!
|
||||
# The `Substring` type
|
||||
|
||||
This file contains API for `Substring` type, which is a legacy API that will be replaced by the
|
||||
safer variant `String.Slice`.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace Substring
|
||||
|
||||
/--
|
||||
Checks whether a substring is empty.
|
||||
|
||||
A substring is empty if its start and end positions are the same.
|
||||
-/
|
||||
@[inline] def isEmpty (ss : Substring) : Bool :=
|
||||
ss.bsize == 0
|
||||
|
||||
@[export lean_substring_isempty]
|
||||
def Internal.isEmptyImpl (ss : Substring) : Bool :=
|
||||
Substring.isEmpty ss
|
||||
|
||||
/--
|
||||
Copies the region of the underlying string pointed to by a substring into a fresh string.
|
||||
-/
|
||||
@[inline] def toString : Substring → String
|
||||
| ⟨s, b, e⟩ => b.extract s e
|
||||
|
||||
@[export lean_substring_tostring]
|
||||
def Internal.toStringImpl : Substring → String :=
|
||||
Substring.toString
|
||||
|
||||
/--
|
||||
Returns the character at the given position in the substring.
|
||||
|
||||
The position is relative to the substring, rather than the underlying string, and no bounds checking
|
||||
is performed with respect to the substring's end position. If the relative position is not a valid
|
||||
position in the underlying string, the fallback value `(default : Char)`, which is `'A'`, is
|
||||
returned. Does not panic.
|
||||
-/
|
||||
@[inline] def get : Substring → String.Pos.Raw → Char
|
||||
| ⟨s, b, _⟩, p => (p.offsetBy b).get s
|
||||
|
||||
@[export lean_substring_get]
|
||||
def Internal.getImpl : Substring → String.Pos.Raw → Char :=
|
||||
Substring.get
|
||||
|
||||
/--
|
||||
Returns the next position in a substring after the given position. If the position is at the end of
|
||||
the substring, it is returned unmodified.
|
||||
|
||||
Both the input position and the returned position are interpreted relative to the substring's start
|
||||
position, not the underlying string.
|
||||
-/
|
||||
@[inline] def next : Substring → String.Pos.Raw → String.Pos.Raw
|
||||
| ⟨s, b, e⟩, p =>
|
||||
let absP := p.offsetBy b
|
||||
if absP = e then p else { byteIdx := (absP.next s).byteIdx - b.byteIdx }
|
||||
|
||||
theorem lt_next (s : Substring) (i : String.Pos.Raw) (h : i.1 < s.bsize) :
|
||||
i.1 < (s.next i).1 := by
|
||||
simp [next]; rw [if_neg ?a]
|
||||
case a =>
|
||||
refine mt (congrArg String.Pos.Raw.byteIdx) (Nat.ne_of_lt ?_)
|
||||
exact (Nat.add_comm .. ▸ Nat.add_lt_of_lt_sub h :)
|
||||
apply Nat.lt_sub_of_add_lt
|
||||
rw [Nat.add_comm]; apply String.Pos.Raw.lt_next
|
||||
|
||||
/--
|
||||
Returns the previous position in a substring, just prior to the given position. If the position is
|
||||
at the beginning of the substring, it is returned unmodified.
|
||||
|
||||
Both the input position and the returned position are interpreted relative to the substring's start
|
||||
position, not the underlying string.
|
||||
-/
|
||||
@[inline] def prev : Substring → String.Pos.Raw → String.Pos.Raw
|
||||
| ⟨s, b, _⟩, p =>
|
||||
let absP := p.offsetBy b
|
||||
if absP = b then p else { byteIdx := (absP.prev s).byteIdx - b.byteIdx }
|
||||
|
||||
@[export lean_substring_prev]
|
||||
def Internal.prevImpl : Substring → String.Pos.Raw → String.Pos.Raw :=
|
||||
Substring.prev
|
||||
|
||||
/--
|
||||
Returns the position that's the specified number of characters forward from the given position in a
|
||||
substring. If the end position of the substring is reached, it is returned.
|
||||
|
||||
Both the input position and the returned position are interpreted relative to the substring's start
|
||||
position, not the underlying string.
|
||||
-/
|
||||
def nextn : Substring → Nat → String.Pos.Raw → String.Pos.Raw
|
||||
| _, 0, p => p
|
||||
| ss, i+1, p => ss.nextn i (ss.next p)
|
||||
|
||||
/--
|
||||
Returns the position that's the specified number of characters prior to the given position in a
|
||||
substring. If the start position of the substring is reached, it is returned.
|
||||
|
||||
Both the input position and the returned position are interpreted relative to the substring's start
|
||||
position, not the underlying string.
|
||||
-/
|
||||
def prevn : Substring → Nat → String.Pos.Raw → String.Pos.Raw
|
||||
| _, 0, p => p
|
||||
| ss, i+1, p => ss.prevn i (ss.prev p)
|
||||
|
||||
/--
|
||||
Returns the first character in the substring.
|
||||
|
||||
If the substring is empty, but the substring's start position is a valid position in the underlying
|
||||
string, then the character at the start position is returned. If the substring's start position is
|
||||
not a valid position in the string, the fallback value `(default : Char)`, which is `'A'`, is
|
||||
returned. Does not panic.
|
||||
-/
|
||||
@[inline, expose] def front (s : Substring) : Char :=
|
||||
s.get 0
|
||||
|
||||
@[export lean_substring_front]
|
||||
def Internal.frontImpl : Substring → Char :=
|
||||
Substring.front
|
||||
|
||||
/--
|
||||
Returns the substring-relative position of the first occurrence of `c` in `s`, or `s.bsize` if `c`
|
||||
doesn't occur.
|
||||
-/
|
||||
@[inline] def posOf (s : Substring) (c : Char) : String.Pos.Raw :=
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => { byteIdx := (String.posOfAux s c e b).byteIdx - b.byteIdx }
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the beginning of a substring
|
||||
by advancing its start position.
|
||||
|
||||
If the substring's end position is reached, the start position is not advanced past it.
|
||||
-/
|
||||
@[inline] def drop : Substring → Nat → Substring
|
||||
| ss@⟨s, b, e⟩, n => ⟨s, (ss.nextn n 0).offsetBy b, e⟩
|
||||
|
||||
@[export lean_substring_drop]
|
||||
def Internal.dropImpl : Substring → Nat → Substring :=
|
||||
Substring.drop
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the end of a substring
|
||||
by moving its end position towards its start position.
|
||||
|
||||
If the substring's start position is reached, the end position is not retracted past it.
|
||||
-/
|
||||
@[inline] def dropRight : Substring → Nat → Substring
|
||||
| ss@⟨s, b, _⟩, n => ⟨s, b, (ss.prevn n ⟨ss.bsize⟩).offsetBy b⟩
|
||||
|
||||
/--
|
||||
Retains only the specified number of characters (Unicode code points) at the beginning of a
|
||||
substring, by moving its end position towards its start position.
|
||||
|
||||
If the substring's start position is reached, the end position is not retracted past it.
|
||||
-/
|
||||
@[inline] def take : Substring → Nat → Substring
|
||||
| ss@⟨s, b, _⟩, n => ⟨s, b, (ss.nextn n 0).offsetBy b⟩
|
||||
|
||||
/--
|
||||
Retains only the specified number of characters (Unicode code points) at the end of a substring, by
|
||||
moving its start position towards its end position.
|
||||
|
||||
If the substring's end position is reached, the start position is not advanced past it.
|
||||
-/
|
||||
@[inline] def takeRight : Substring → Nat → Substring
|
||||
| ss@⟨s, b, e⟩, n => ⟨s, (ss.prevn n ⟨ss.bsize⟩).offsetBy b, e⟩
|
||||
|
||||
/--
|
||||
Checks whether a position in a substring is precisely equal to its ending position.
|
||||
|
||||
The position is understood relative to the substring's starting position, rather than the underlying
|
||||
string's starting position.
|
||||
-/
|
||||
@[inline] def atEnd : Substring → String.Pos.Raw → Bool
|
||||
| ⟨_, b, e⟩, p => p.offsetBy b == e
|
||||
|
||||
/--
|
||||
Returns the region of the substring delimited by the provided start and stop positions, as a
|
||||
substring. The positions are interpreted with respect to the substring's start position, rather than
|
||||
the underlying string.
|
||||
|
||||
If the resulting substring is empty, then the resulting substring is a substring of the empty string
|
||||
`""`. Otherwise, the underlying string is that of the input substring with the beginning and end
|
||||
positions adjusted.
|
||||
-/
|
||||
@[inline] def extract : Substring → String.Pos.Raw → String.Pos.Raw → Substring
|
||||
| ⟨s, b, e⟩, b', e' => if b' ≥ e' then ⟨"", 0, 0⟩ else ⟨s, e.min (b'.offsetBy b), e.min (e'.offsetBy b)⟩
|
||||
|
||||
@[export lean_substring_extract]
|
||||
def Internal.extractImpl : Substring → String.Pos.Raw → String.Pos.Raw → Substring :=
|
||||
Substring.extract
|
||||
|
||||
/--
|
||||
Splits a substring `s` on occurrences of the separator string `sep`. The default separator is `" "`.
|
||||
|
||||
When `sep` is empty, the result is `[s]`. When `sep` occurs in overlapping patterns, the first match
|
||||
is taken. There will always be exactly `n+1` elements in the returned list if there were `n`
|
||||
non-overlapping matches of `sep` in the string. The separators are not included in the returned
|
||||
substrings, which are all substrings of `s`'s string.
|
||||
-/
|
||||
def splitOn (s : Substring) (sep : String := " ") : List Substring :=
|
||||
if sep == "" then
|
||||
[s]
|
||||
else
|
||||
let rec loop (b i j : String.Pos.Raw) (r : List Substring) : List Substring :=
|
||||
if h : i.byteIdx < s.bsize then
|
||||
have := Nat.sub_lt_sub_left h (lt_next s i h)
|
||||
if s.get i == j.get sep then
|
||||
let i := s.next i
|
||||
let j := j.next sep
|
||||
if j.atEnd sep then
|
||||
loop i i 0 (s.extract b (i.unoffsetBy j) :: r)
|
||||
else
|
||||
loop b i j r
|
||||
else
|
||||
loop b (s.next i) 0 r
|
||||
else
|
||||
let r := if j.atEnd sep then
|
||||
"".toSubstring :: s.extract b (i.unoffsetBy j) :: r
|
||||
else
|
||||
s.extract b i :: r
|
||||
r.reverse
|
||||
termination_by s.bsize - i.1
|
||||
loop 0 0 0 []
|
||||
|
||||
/--
|
||||
Folds a function over a substring from the left, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with each character in order, using `f`.
|
||||
-/
|
||||
@[inline] def foldl {α : Type u} (f : α → Char → α) (init : α) (s : Substring) : α :=
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => String.foldlAux f s e b init
|
||||
|
||||
/--
|
||||
Folds a function over a substring from the right, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with each character in reverse order, using `f`.
|
||||
-/
|
||||
@[inline] def foldr {α : Type u} (f : Char → α → α) (init : α) (s : Substring) : α :=
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => String.foldrAux f init s e b
|
||||
|
||||
/--
|
||||
Checks whether the Boolean predicate `p` returns `true` for any character in a substring.
|
||||
|
||||
Short-circuits at the first character for which `p` returns `true`.
|
||||
-/
|
||||
@[inline] def any (s : Substring) (p : Char → Bool) : Bool :=
|
||||
match s with
|
||||
| ⟨s, b, e⟩ => String.anyAux s e p b
|
||||
|
||||
/--
|
||||
Checks whether the Boolean predicate `p` returns `true` for every character in a substring.
|
||||
|
||||
Short-circuits at the first character for which `p` returns `false`.
|
||||
-/
|
||||
@[inline] def all (s : Substring) (p : Char → Bool) : Bool :=
|
||||
!s.any (fun c => !p c)
|
||||
|
||||
@[export lean_substring_all]
|
||||
def Internal.allImpl (s : Substring) (p : Char → Bool) : Bool :=
|
||||
Substring.all s p
|
||||
|
||||
/--
|
||||
Checks whether a substring contains the specified character.
|
||||
-/
|
||||
@[inline] def contains (s : Substring) (c : Char) : Bool :=
|
||||
s.any (fun a => a == c)
|
||||
|
||||
@[specialize] def takeWhileAux (s : String) (stopPos : String.Pos.Raw) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
if h : i < stopPos then
|
||||
if p (i.get s) then
|
||||
have := Nat.sub_lt_sub_left h (String.Pos.Raw.lt_next s i)
|
||||
takeWhileAux s stopPos p (i.next s)
|
||||
else i
|
||||
else i
|
||||
termination_by stopPos.1 - i.1
|
||||
|
||||
/--
|
||||
Retains only the longest prefix of a substring in which a Boolean predicate returns `true` for all
|
||||
characters by moving the substring's end position towards its start position.
|
||||
-/
|
||||
@[inline] def takeWhile : Substring → (Char → Bool) → Substring
|
||||
| ⟨s, b, e⟩, p =>
|
||||
let e := takeWhileAux s e p b;
|
||||
⟨s, b, e⟩
|
||||
|
||||
@[export lean_substring_takewhile]
|
||||
def Internal.takeWhileImpl : Substring → (Char → Bool) → Substring :=
|
||||
Substring.takeWhile
|
||||
|
||||
/--
|
||||
Removes the longest prefix of a substring in which a Boolean predicate returns `true` for all
|
||||
characters by moving the substring's start position. The start position is moved to the position of
|
||||
the first character for which the predicate returns `false`, or to the substring's end position if
|
||||
the predicate always returns `true`.
|
||||
-/
|
||||
@[inline] def dropWhile : Substring → (Char → Bool) → Substring
|
||||
| ⟨s, b, e⟩, p =>
|
||||
let b := takeWhileAux s e p b;
|
||||
⟨s, b, e⟩
|
||||
|
||||
@[specialize] def takeRightWhileAux (s : String) (begPos : String.Pos.Raw) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
if h : begPos < i then
|
||||
have := String.Pos.Raw.prev_lt_of_pos s i <| mt (congrArg String.Pos.Raw.byteIdx) <|
|
||||
Ne.symm <| Nat.ne_of_lt <| Nat.lt_of_le_of_lt (Nat.zero_le _) h
|
||||
let i' := i.prev s
|
||||
let c := i'.get s
|
||||
if !p c then i
|
||||
else takeRightWhileAux s begPos p i'
|
||||
else i
|
||||
termination_by i.1
|
||||
|
||||
/--
|
||||
Retains only the longest suffix of a substring in which a Boolean predicate returns `true` for all
|
||||
characters by moving the substring's start position towards its end position.
|
||||
-/
|
||||
@[inline] def takeRightWhile : Substring → (Char → Bool) → Substring
|
||||
| ⟨s, b, e⟩, p =>
|
||||
let b := takeRightWhileAux s b p e
|
||||
⟨s, b, e⟩
|
||||
|
||||
/--
|
||||
Removes the longest suffix of a substring in which a Boolean predicate returns `true` for all
|
||||
characters by moving the substring's end position. The end position is moved just after the position
|
||||
of the last character for which the predicate returns `false`, or to the substring's start position
|
||||
if the predicate always returns `true`.
|
||||
-/
|
||||
@[inline] def dropRightWhile : Substring → (Char → Bool) → Substring
|
||||
| ⟨s, b, e⟩, p =>
|
||||
let e := takeRightWhileAux s b p e
|
||||
⟨s, b, e⟩
|
||||
|
||||
/--
|
||||
Removes leading whitespace from a substring by moving its start position to the first non-whitespace
|
||||
character, or to its end position if there is no non-whitespace character.
|
||||
|
||||
“Whitespace” is defined as characters for which `Char.isWhitespace` returns `true`.
|
||||
-/
|
||||
@[inline] def trimLeft (s : Substring) : Substring :=
|
||||
s.dropWhile Char.isWhitespace
|
||||
|
||||
/--
|
||||
Removes trailing whitespace from a substring by moving its end position to the last non-whitespace
|
||||
character, or to its start position if there is no non-whitespace character.
|
||||
|
||||
“Whitespace” is defined as characters for which `Char.isWhitespace` returns `true`.
|
||||
-/
|
||||
@[inline] def trimRight (s : Substring) : Substring :=
|
||||
s.dropRightWhile Char.isWhitespace
|
||||
|
||||
/--
|
||||
Removes leading and trailing whitespace from a substring by first moving its start position to the
|
||||
first non-whitespace character, and then moving its end position to the last non-whitespace
|
||||
character.
|
||||
|
||||
If the substring consists only of whitespace, then the resulting substring's start position is moved
|
||||
to its end position.
|
||||
|
||||
“Whitespace” is defined as characters for which `Char.isWhitespace` returns `true`.
|
||||
|
||||
Examples:
|
||||
* `" red green blue ".toSubstring.trim.toString = "red green blue"`
|
||||
* `" red green blue ".toSubstring.trim.startPos = ⟨1⟩`
|
||||
* `" red green blue ".toSubstring.trim.stopPos = ⟨15⟩`
|
||||
* `" ".toSubstring.trim.startPos = ⟨5⟩`
|
||||
-/
|
||||
@[inline] def trim : Substring → Substring
|
||||
| ⟨s, b, e⟩ =>
|
||||
let b := takeWhileAux s e Char.isWhitespace b
|
||||
let e := takeRightWhileAux s b Char.isWhitespace e
|
||||
⟨s, b, e⟩
|
||||
|
||||
/--
|
||||
Checks whether the substring can be interpreted as the decimal representation of a natural number.
|
||||
|
||||
A substring can be interpreted as a decimal natural number if it is not empty and all the characters
|
||||
in it are digits.
|
||||
|
||||
Use `Substring.toNat?` to convert such a substring to a natural number.
|
||||
-/
|
||||
@[inline] def isNat (s : Substring) : Bool :=
|
||||
!s.isEmpty && s.all fun c => c.isDigit
|
||||
|
||||
/--
|
||||
Checks whether the substring can be interpreted as the decimal representation of a natural number,
|
||||
returning the number if it can.
|
||||
|
||||
A substring can be interpreted as a decimal natural number if it is not empty and all the characters
|
||||
in it are digits.
|
||||
|
||||
Use `Substring.isNat` to check whether the substring is such a substring.
|
||||
-/
|
||||
def toNat? (s : Substring) : Option Nat :=
|
||||
if s.isNat then
|
||||
some <| s.foldl (fun n c => n*10 + (c.toNat - '0'.toNat)) 0
|
||||
else
|
||||
none
|
||||
|
||||
/--
|
||||
Given a `Substring`, returns another one which has valid endpoints
|
||||
and represents the same substring according to `Substring.toString`.
|
||||
(Note, the substring may still be inverted, i.e. beginning greater than end.)
|
||||
-/
|
||||
def repair : Substring → Substring
|
||||
| ⟨s, b, e⟩ => ⟨s, if b.isValid s then b else s.rawEndPos, if e.isValid s then e else s.rawEndPos⟩
|
||||
|
||||
/--
|
||||
Checks whether two substrings represent equal strings. Usually accessed via the `==` operator.
|
||||
|
||||
Two substrings do not need to have the same underlying string or the same start and end positions;
|
||||
instead, they are equal if they contain the same sequence of characters.
|
||||
-/
|
||||
def beq (ss1 ss2 : Substring) : Bool :=
|
||||
let ss1 := ss1.repair
|
||||
let ss2 := ss2.repair
|
||||
ss1.bsize == ss2.bsize && String.Pos.Raw.substrEq ss1.str ss1.startPos ss2.str ss2.startPos ss1.bsize
|
||||
|
||||
@[export lean_substring_beq]
|
||||
def Internal.beqImpl (ss1 ss2 : Substring) : Bool :=
|
||||
Substring.beq ss1 ss2
|
||||
|
||||
instance hasBeq : BEq Substring := ⟨beq⟩
|
||||
|
||||
/--
|
||||
Checks whether two substrings have the same position and content.
|
||||
|
||||
The two substrings do not need to have the same underlying string for this check to succeed.
|
||||
-/
|
||||
def sameAs (ss1 ss2 : Substring) : Bool :=
|
||||
ss1.startPos == ss2.startPos && ss1 == ss2
|
||||
|
||||
/--
|
||||
Returns the longest common prefix of two substrings.
|
||||
|
||||
The returned substring uses the same underlying string as `s`.
|
||||
-/
|
||||
def commonPrefix (s t : Substring) : Substring :=
|
||||
{ s with stopPos := loop s.startPos t.startPos }
|
||||
where
|
||||
/-- Returns the ending position of the common prefix, working up from `spos, tpos`. -/
|
||||
loop spos tpos :=
|
||||
if h : spos < s.stopPos ∧ tpos < t.stopPos then
|
||||
if spos.get s.str == tpos.get t.str then
|
||||
have := Nat.sub_lt_sub_left h.1 (String.Pos.Raw.lt_next s.str spos)
|
||||
loop (spos.next s.str) (tpos.next t.str)
|
||||
else
|
||||
spos
|
||||
else
|
||||
spos
|
||||
termination_by s.stopPos.byteIdx - spos.byteIdx
|
||||
|
||||
/--
|
||||
Returns the longest common suffix of two substrings.
|
||||
|
||||
The returned substring uses the same underlying string as `s`.
|
||||
-/
|
||||
def commonSuffix (s t : Substring) : Substring :=
|
||||
{ s with startPos := loop s.stopPos t.stopPos }
|
||||
where
|
||||
/-- Returns the starting position of the common prefix, working down from `spos, tpos`. -/
|
||||
loop spos tpos :=
|
||||
if h : s.startPos < spos ∧ t.startPos < tpos then
|
||||
let spos' := spos.prev s.str
|
||||
let tpos' := tpos.prev t.str
|
||||
if spos'.get s.str == tpos'.get t.str then
|
||||
have : spos' < spos := String.Pos.Raw.prev_lt_of_pos s.str spos (String.Pos.Raw.ne_zero_of_lt h.1)
|
||||
loop spos' tpos'
|
||||
else
|
||||
spos
|
||||
else
|
||||
spos
|
||||
termination_by spos.byteIdx
|
||||
|
||||
/--
|
||||
If `pre` is a prefix of `s`, returns the remainder. Returns `none` otherwise.
|
||||
|
||||
The substring `pre` is a prefix of `s` if there exists a `t : Substring` such that
|
||||
`s.toString = pre.toString ++ t.toString`. If so, the result is the substring of `s` without the
|
||||
prefix.
|
||||
-/
|
||||
def dropPrefix? (s : Substring) (pre : Substring) : Option Substring :=
|
||||
let t := s.commonPrefix pre
|
||||
if t.bsize = pre.bsize then
|
||||
some { s with startPos := t.stopPos }
|
||||
else
|
||||
none
|
||||
|
||||
/--
|
||||
If `suff` is a suffix of `s`, returns the remainder. Returns `none` otherwise.
|
||||
|
||||
The substring `suff` is a suffix of `s` if there exists a `t : Substring` such that
|
||||
`s.toString = t.toString ++ suff.toString`. If so, the result the substring of `s` without the
|
||||
suffix.
|
||||
-/
|
||||
def dropSuffix? (s : Substring) (suff : Substring) : Option Substring :=
|
||||
let t := s.commonSuffix suff
|
||||
if t.bsize = suff.bsize then
|
||||
some { s with stopPos := t.startPos }
|
||||
else
|
||||
none
|
||||
|
||||
@[simp] theorem prev_zero (s : Substring) : s.prev 0 = 0 := by simp [prev]
|
||||
|
||||
@[simp] theorem prevn_zero (s : Substring) : ∀ n, s.prevn n 0 = 0
|
||||
| 0 => rfl
|
||||
| n+1 => by simp [prevn, prevn_zero s n]
|
||||
|
||||
end Substring
|
||||
314
src/Init/Data/String/TakeDrop.lean
Normal file
314
src/Init/Data/String/TakeDrop.lean
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Substring
|
||||
|
||||
/-!
|
||||
# `String.take` and variants
|
||||
|
||||
This file contains the implementations of `String.take` and its variants. Currently, they are
|
||||
implemented in terms of `Substring`; soon, they will be implemented in terms of `String.Slice`
|
||||
instead.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the start of the string.
|
||||
|
||||
If `n` is greater than `s.length`, returns `""`.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".drop 4 = "green blue"`
|
||||
* `"red green blue".drop 10 = "blue"`
|
||||
* `"red green blue".drop 50 = ""`
|
||||
-/
|
||||
@[inline] def drop (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.drop n).toString
|
||||
|
||||
@[export lean_string_drop]
|
||||
def Internal.dropImpl (s : String) (n : Nat) : String :=
|
||||
String.drop s n
|
||||
|
||||
/--
|
||||
Removes the specified number of characters (Unicode code points) from the end of the string.
|
||||
|
||||
If `n` is greater than `s.length`, returns `""`.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".dropRight 5 = "red green"`
|
||||
* `"red green blue".dropRight 11 = "red"`
|
||||
* `"red green blue".dropRight 50 = ""`
|
||||
-/
|
||||
@[inline] def dropRight (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.dropRight n).toString
|
||||
|
||||
@[export lean_string_dropright]
|
||||
def Internal.dropRightImpl (s : String) (n : Nat) : String :=
|
||||
String.dropRight s n
|
||||
|
||||
/--
|
||||
Creates a new string that contains the first `n` characters (Unicode code points) of `s`.
|
||||
|
||||
If `n` is greater than `s.length`, returns `s`.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".take 3 = "red"`
|
||||
* `"red green blue".take 1 = "r"`
|
||||
* `"red green blue".take 0 = ""`
|
||||
* `"red green blue".take 100 = "red green blue"`
|
||||
-/
|
||||
@[inline] def take (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.take n).toString
|
||||
|
||||
/--
|
||||
Creates a new string that contains the last `n` characters (Unicode code points) of `s`.
|
||||
|
||||
If `n` is greater than `s.length`, returns `s`.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".takeRight 4 = "blue"`
|
||||
* `"red green blue".takeRight 1 = "e"`
|
||||
* `"red green blue".takeRight 0 = ""`
|
||||
* `"red green blue".takeRight 100 = "red green blue"`
|
||||
-/
|
||||
@[inline] def takeRight (s : String) (n : Nat) : String :=
|
||||
(s.toSubstring.takeRight n).toString
|
||||
|
||||
/--
|
||||
Creates a new string that contains the longest prefix of `s` in which `p` returns `true` for all
|
||||
characters.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".takeWhile (·.isLetter) = "red"`
|
||||
* `"red green blue".takeWhile (· == 'r') = "r"`
|
||||
* `"red green blue".takeWhile (· != 'n') = "red gree"`
|
||||
* `"red green blue".takeWhile (fun _ => true) = "red green blue"`
|
||||
-/
|
||||
@[inline] def takeWhile (s : String) (p : Char → Bool) : String :=
|
||||
(s.toSubstring.takeWhile p).toString
|
||||
|
||||
/--
|
||||
Creates a new string by removing the longest prefix from `s` in which `p` returns `true` for all
|
||||
characters.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".dropWhile (·.isLetter) = " green blue"`
|
||||
* `"red green blue".dropWhile (· == 'r') = "ed green blue"`
|
||||
* `"red green blue".dropWhile (· != 'n') = "n blue"`
|
||||
* `"red green blue".dropWhile (fun _ => true) = ""`
|
||||
-/
|
||||
@[inline] def dropWhile (s : String) (p : Char → Bool) : String :=
|
||||
(s.toSubstring.dropWhile p).toString
|
||||
|
||||
/--
|
||||
Creates a new string that contains the longest suffix of `s` in which `p` returns `true` for all
|
||||
characters.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".takeRightWhile (·.isLetter) = "blue"`
|
||||
* `"red green blue".takeRightWhile (· == 'e') = "e"`
|
||||
* `"red green blue".takeRightWhile (· != 'n') = " blue"`
|
||||
* `"red green blue".takeRightWhile (fun _ => true) = "red green blue"`
|
||||
-/
|
||||
@[inline] def takeRightWhile (s : String) (p : Char → Bool) : String :=
|
||||
(s.toSubstring.takeRightWhile p).toString
|
||||
|
||||
/--
|
||||
Creates a new string by removing the longest suffix from `s` in which `p` returns `true` for all
|
||||
characters.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".dropRightWhile (·.isLetter) = "red green "`
|
||||
* `"red green blue".dropRightWhile (· == 'e') = "red green blu"`
|
||||
* `"red green blue".dropRightWhile (· != 'n') = "red green"`
|
||||
* `"red green blue".dropRightWhile (fun _ => true) = ""`
|
||||
-/
|
||||
@[inline] def dropRightWhile (s : String) (p : Char → Bool) : String :=
|
||||
(s.toSubstring.dropRightWhile p).toString
|
||||
|
||||
/--
|
||||
Checks whether the first string (`s`) begins with the second (`pre`).
|
||||
|
||||
`String.isPrefix` is a version that takes the potential prefix before the string.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".startsWith "red" = true`
|
||||
* `"red green blue".startsWith "green" = false`
|
||||
* `"red green blue".startsWith "" = true`
|
||||
* `"red".startsWith "red" = true`
|
||||
-/
|
||||
@[inline] def startsWith (s pre : String) : Bool :=
|
||||
s.toSubstring.take pre.length == pre.toSubstring
|
||||
|
||||
/--
|
||||
Checks whether the first string (`s`) ends with the second (`post`).
|
||||
|
||||
Examples:
|
||||
* `"red green blue".endsWith "blue" = true`
|
||||
* `"red green blue".endsWith "green" = false`
|
||||
* `"red green blue".endsWith "" = true`
|
||||
* `"red".endsWith "red" = true`
|
||||
-/
|
||||
@[inline] def endsWith (s post : String) : Bool :=
|
||||
s.toSubstring.takeRight post.length == post.toSubstring
|
||||
|
||||
/--
|
||||
Removes trailing whitespace from a string.
|
||||
|
||||
“Whitespace” is defined as characters for which `Char.isWhitespace` returns `true`.
|
||||
|
||||
Examples:
|
||||
* `"abc".trimRight = "abc"`
|
||||
* `" abc".trimRight = " abc"`
|
||||
* `"abc \t ".trimRight = "abc"`
|
||||
* `" abc ".trimRight = " abc"`
|
||||
* `"abc\ndef\n".trimRight = "abc\ndef"`
|
||||
-/
|
||||
@[inline] def trimRight (s : String) : String :=
|
||||
s.toSubstring.trimRight.toString
|
||||
|
||||
/--
|
||||
Removes leading whitespace from a string.
|
||||
|
||||
“Whitespace” is defined as characters for which `Char.isWhitespace` returns `true`.
|
||||
|
||||
Examples:
|
||||
* `"abc".trimLeft = "abc"`
|
||||
* `" abc".trimLeft = " abc"`
|
||||
* `"abc \t ".trimLeft = "abc \t "`
|
||||
* `" abc ".trimLeft = "abc "`
|
||||
* `"abc\ndef\n".trimLeft = "abc\ndef\n"`
|
||||
-/
|
||||
@[inline] def trimLeft (s : String) : String :=
|
||||
s.toSubstring.trimLeft.toString
|
||||
|
||||
/--
|
||||
Removes leading and trailing whitespace from a string.
|
||||
|
||||
“Whitespace” is defined as characters for which `Char.isWhitespace` returns `true`.
|
||||
|
||||
Examples:
|
||||
* `"abc".trim = "abc"`
|
||||
* `" abc".trim = "abc"`
|
||||
* `"abc \t ".trim = "abc"`
|
||||
* `" abc ".trim = "abc"`
|
||||
* `"abc\ndef\n".trim = "abc\ndef"`
|
||||
-/
|
||||
@[inline] def trim (s : String) : String :=
|
||||
s.toSubstring.trim.toString
|
||||
|
||||
@[export lean_string_trim]
|
||||
def Internal.trimImpl (s : String) : String :=
|
||||
String.trim s
|
||||
|
||||
/--
|
||||
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
|
||||
returns `true` for the character at the position. Stops incrementing at the end of the string or
|
||||
when `p` returns `false` for the current character.
|
||||
|
||||
Examples:
|
||||
* `let s := " a "; s.get (s.nextWhile Char.isWhitespace 0) = 'a'`
|
||||
* `let s := "a "; s.get (s.nextWhile Char.isWhitespace 0) = 'a'`
|
||||
* `let s := "ba "; s.get (s.nextWhile Char.isWhitespace 0) = 'b'`
|
||||
-/
|
||||
@[inline] def Pos.Raw.nextWhile (s : String) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
Substring.takeWhileAux s s.rawEndPos p i
|
||||
|
||||
@[deprecated Pos.Raw.nextWhile (since := "2025-10-10")]
|
||||
abbrev nextWhile (s : String) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
Pos.Raw.nextWhile s p i
|
||||
|
||||
@[export lean_string_nextwhile]
|
||||
def Internal.nextWhileImpl (s : String) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
i.nextWhile s p
|
||||
|
||||
/--
|
||||
Repeatedly increments a position in a string, as if by `String.next`, while the predicate `p`
|
||||
returns `false` for the character at the position. Stops incrementing at the end of the string or
|
||||
when `p` returns `true` for the current character.
|
||||
|
||||
Examples:
|
||||
* `let s := " a "; s.get (s.nextUntil Char.isWhitespace 0) = ' '`
|
||||
* `let s := " a "; s.get (s.nextUntil Char.isLetter 0) = 'a'`
|
||||
* `let s := "a "; s.get (s.nextUntil Char.isWhitespace 0) = ' '`
|
||||
-/
|
||||
@[inline] def Pos.Raw.nextUntil (s : String) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
nextWhile s (fun c => !p c) i
|
||||
|
||||
@[deprecated Pos.Raw.nextUntil (since := "2025-10-10")]
|
||||
def nextUntil (s : String) (p : Char → Bool) (i : String.Pos.Raw) : String.Pos.Raw :=
|
||||
i.nextUntil s p
|
||||
|
||||
/--
|
||||
If `pre` is a prefix of `s`, returns the remainder. Returns `none` otherwise.
|
||||
|
||||
The string `pre` is a prefix of `s` if there exists a `t : String` such that `s = pre ++ t`. If so,
|
||||
the result is `some t`.
|
||||
|
||||
Use `String.stripPrefix` to return the string unchanged when `pre` is not a prefix.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".dropPrefix? "red " = some "green blue"`
|
||||
* `"red green blue".dropPrefix? "reed " = none`
|
||||
* `"red green blue".dropPrefix? "" = some "red green blue"`
|
||||
-/
|
||||
def dropPrefix? (s : String) (pre : String) : Option Substring :=
|
||||
s.toSubstring.dropPrefix? pre.toSubstring
|
||||
|
||||
/--
|
||||
If `suff` is a suffix of `s`, returns the remainder. Returns `none` otherwise.
|
||||
|
||||
The string `suff` is a suffix of `s` if there exists a `t : String` such that `s = t ++ suff`. If so,
|
||||
the result is `some t`.
|
||||
|
||||
Use `String.stripSuffix` to return the string unchanged when `suff` is not a suffix.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".dropSuffix? " blue" = some "red green"`
|
||||
* `"red green blue".dropSuffix? " blu " = none`
|
||||
* `"red green blue".dropSuffix? "" = some "red green blue"`
|
||||
-/
|
||||
def dropSuffix? (s : String) (suff : String) : Option Substring :=
|
||||
s.toSubstring.dropSuffix? suff.toSubstring
|
||||
|
||||
/--
|
||||
If `pre` is a prefix of `s`, returns the remainder. Returns `s` unmodified otherwise.
|
||||
|
||||
The string `pre` is a prefix of `s` if there exists a `t : String` such that `s = pre ++ t`. If so,
|
||||
the result is `t`. Otherwise, it is `s`.
|
||||
|
||||
Use `String.dropPrefix?` to return `none` when `pre` is not a prefix.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".stripPrefix "red " = "green blue"`
|
||||
* `"red green blue".stripPrefix "reed " = "red green blue"`
|
||||
* `"red green blue".stripPrefix "" = "red green blue"`
|
||||
-/
|
||||
def stripPrefix (s : String) (pre : String) : String :=
|
||||
s.dropPrefix? pre |>.map Substring.toString |>.getD s
|
||||
|
||||
/--
|
||||
If `suff` is a suffix of `s`, returns the remainder. Returns `s` unmodified otherwise.
|
||||
|
||||
The string `suff` is a suffix of `s` if there exists a `t : String` such that `s = t ++ suff`. If so,
|
||||
the result is `t`. Otherwise, it is `s`.
|
||||
|
||||
Use `String.dropSuffix?` to return `none` when `suff` is not a suffix.
|
||||
|
||||
Examples:
|
||||
* `"red green blue".stripSuffix " blue" = "red green"`
|
||||
* `"red green blue".stripSuffix " blu " = "red green blue"`
|
||||
* `"red green blue".stripSuffix "" = "red green blue"`
|
||||
-/
|
||||
def stripSuffix (s : String) (suff : String) : String :=
|
||||
s.dropSuffix? suff |>.map Substring.toString |>.getD s
|
||||
|
||||
end String
|
||||
|
|
@ -6,7 +6,7 @@ Authors: Leonardo de Moura and Sebastian Ullrich
|
|||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Substring
|
||||
|
||||
/-!
|
||||
Here we give the. implementation of `Name.toString`. There is also a private implementation in
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ prelude
|
|||
public import Init.System.IOError
|
||||
public import Init.System.FilePath
|
||||
public import Init.Data.Ord.UInt
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module
|
|||
prelude
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.System.FilePath
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.EnvExtension
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.Data.Name
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public import Std.Data.TreeMap.Raw.Basic
|
|||
public import Init.Data.Ord.String
|
||||
import Init.Data.Range.Polymorphic.Iterators
|
||||
import Init.Data.Range.Polymorphic.Nat
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.Data.JsonRpc
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Init.Data.Ord.Basic
|
||||
import Init.Data.String.TakeDrop
|
||||
import Init.Data.Ord.String
|
||||
import Init.Data.Ord.UInt
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module
|
|||
prelude
|
||||
public import Lean.Data.Json.FromToJson.Basic
|
||||
public import Lean.ToExpr
|
||||
import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.Syntax
|
||||
import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ prelude
|
|||
|
||||
import Init.Data.Ord
|
||||
public import Lean.DocString.Types
|
||||
public import Init.Data.String.TakeDrop
|
||||
import Init.Data.String.Iterator
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ public import Lean.PrivateName
|
|||
public import Lean.LoadDynlib
|
||||
public import Init.Dynamic
|
||||
import Init.Data.Slice
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ prelude
|
|||
public import Lean.Message
|
||||
public import Lean.EnvExtension
|
||||
public import Lean.DocString.Links
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Init.System.IO
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module
|
|||
prelude
|
||||
public import Init.System.IO
|
||||
import Init.Data.ToString.Name
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Std.Internal.Parsec.Basic
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Iterator
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Std.Time.Zoned
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Std.Time.Zoned.Database.Basic
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
public section
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ prelude
|
|||
public import Init.Data.Order
|
||||
import Lake.Util.Name
|
||||
import Lake.Config.Kinds
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.Setup
|
||||
public import Init.Data.String.TakeDrop
|
||||
|
||||
open Lean
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public import Init.System.FilePath
|
|||
public import Std.Data.TreeMap.Basic
|
||||
public import Lean.Data.Name
|
||||
import Lake.Util.Name
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
open System Lean
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module
|
|||
prelude
|
||||
public import Lake.Util.Date
|
||||
import Lake.Util.String
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
/-!
|
||||
# TOML Date-Time
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public import Init.Data.Float
|
|||
public import Lake.Toml.Data.Dict
|
||||
public import Lake.Toml.Data.DateTime
|
||||
import Lake.Util.String
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
/-!
|
||||
# TOML Value
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.TakeDrop
|
||||
|
||||
namespace Lake
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lean.Data.Json
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
open System Lean
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module
|
|||
prelude
|
||||
public import Init.Data.ToString
|
||||
public import Lake.Util.Proc
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
open System
|
||||
namespace Lake
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public import Lake.Util.Error
|
|||
public import Lake.Util.EStateT
|
||||
public import Lean.Message
|
||||
public import Lake.Util.Lift
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
open Lean
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ module
|
|||
|
||||
prelude
|
||||
public import Lake.Util.Log
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
namespace Lake
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public import Lake.Util.Log
|
|||
import all Init.Data.String.Extra
|
||||
import Lake.Util.JsonObject
|
||||
import Lake.Util.Proc
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
open Lean
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module
|
|||
prelude
|
||||
public import Lean.Data.Json
|
||||
public import Lake.Util.Date
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
/-! # Version
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ module
|
|||
prelude
|
||||
public import Init.Prelude
|
||||
import Init.Data.ToString
|
||||
import Init.Data.String.TakeDrop
|
||||
|
||||
namespace Lake
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue