Skip to content

Commit 761cbe8

Browse files
committed
Sorry-free
1 parent 3dfdbc8 commit 761cbe8

File tree

4 files changed

+129
-30
lines changed

4 files changed

+129
-30
lines changed

src/Init/Data/String/Basic.lean

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,7 @@ theorem utf8ByteSize_push {s : String} {c : Char} :
634634
(s.push c).utf8ByteSize = s.utf8ByteSize + c.utf8Size := by
635635
simp [← size_bytes, List.utf8Encode_singleton]
636636

637+
@[simp]
637638
theorem rawEndPos_push {s : String} {c : Char} : (s.push c).rawEndPos = s.rawEndPos + c := by
638639
simp [Pos.Raw.ext_iff]
639640

@@ -1130,6 +1131,11 @@ theorem Slice.Pos.get_eq_utf8DecodeChar {s : Slice} (pos : s.Pos) (h : pos ≠ s
11301131
pos.get h = s.str.bytes.utf8DecodeChar (s.startInclusive.offset.byteIdx + pos.offset.byteIdx)
11311132
((Pos.Raw.isValidForSlice_iff_isSome_utf8DecodeChar?.1 pos.isValidForSlice).elim (by simp_all [Pos.ext_iff]) (·.2)) := (rfl)
11321133

1134+
theorem Slice.Pos.utf8Encode_get_eq_extract {s : Slice} (pos : s.Pos) (h : pos ≠ s.endPos) :
1135+
List.utf8Encode [pos.get h] = s.str.bytes.extract (s.startInclusive.offset.byteIdx + pos.offset.byteIdx)
1136+
(s.startInclusive.offset.byteIdx + pos.offset.byteIdx + (pos.get h).utf8Size) := by
1137+
rw [get_eq_utf8DecodeChar pos h, List.utf8Encode_singleton, ByteArray.utf8EncodeChar_utf8DecodeChar]
1138+
11331139
/-- Returns the byte at the given position in the string, or `none` if the position is the end
11341140
position. -/
11351141
@[expose]
@@ -1495,6 +1501,14 @@ theorem Slice.Pos.lt_next {s : Slice} {pos : s.Pos} {h : pos ≠ s.endPos} :
14951501
pos < pos.next h := by
14961502
simp [Pos.lt_iff, Pos.Raw.lt_iff, Char.utf8Size_pos]
14971503

1504+
theorem Slice.Pos.copy_eq_copy_replaceEnd_append_get {s : Slice} {pos : s.Pos} (h : pos ≠ s.endPos) :
1505+
s.copy = (s.replaceEnd pos).copy ++ singleton (pos.get h) ++ (s.replaceStart (pos.next h)).copy := by
1506+
suffices (max (s.startInclusive.offset.byteIdx + (pos.offset.byteIdx + (pos.get h).utf8Size)) s.endExclusive.offset.byteIdx)
1507+
= s.endExclusive.offset.byteIdx by
1508+
simp [← bytes_inj, bytes_copy, utf8Encode_get_eq_extract, Nat.add_assoc, this]
1509+
rw [Nat.max_eq_right]
1510+
simpa [Pos.Raw.le_iff] using (pos.next h).offset_str_le_offset_endExclusive
1511+
14981512
@[inline, expose]
14991513
def Slice.Pos.prevAux {s : Slice} (pos : s.Pos) (h : pos ≠ s.startPos) : String.Pos.Raw :=
15001514
go (pos.offset.byteIdx - 1) (by
@@ -1861,10 +1875,13 @@ abbrev utf8SetAux (c' : Char) : List Char → Pos.Raw → Pos.Raw → List Char
18611875
Pos.Raw.utf8SetAux c'
18621876

18631877
@[simp]
1864-
theorem ValidPos.toSlice_get {s : String} {p : s.ValidPos} {h} :
1878+
theorem ValidPos.get_toSlice {s : String} {p : s.ValidPos} {h} :
18651879
p.toSlice.get h = p.get (ne_of_apply_ne (·.toSlice) (by simp_all)) := by
18661880
rfl
18671881

1882+
theorem ValidPos.get_eq_get_toSlice {s : String} {p : s.ValidPos} {h} :
1883+
p.get h = p.toSlice.get (ne_of_apply_ne Slice.Pos.ofSlice (by simp [h])) := rfl
1884+
18681885
@[simp]
18691886
theorem ValidPos.offset_next {s : String} (p : s.ValidPos) (h : p ≠ s.endValidPos) :
18701887
(p.next h).offset = p.offset + p.get h := by
@@ -1943,6 +1960,14 @@ theorem Pos.Raw.isValidForSlice_stringReplaceStart {s : String} {p : s.ValidPos}
19431960
rw [replaceStart, isValidForSlice_replaceStart, isValidForSlice_toSlice_iff,
19441961
ValidPos.offset_toSlice]
19451962

1963+
theorem ValidPos.utf8Encode_get_eq_extract {s : String} (pos : s.ValidPos) (h : pos ≠ s.endValidPos) :
1964+
List.utf8Encode [pos.get h] = s.bytes.extract pos.offset.byteIdx (pos.offset.byteIdx + (pos.get h).utf8Size) := by
1965+
rw [get_eq_get_toSlice, Slice.Pos.utf8Encode_get_eq_extract]
1966+
simp
1967+
1968+
theorem ValidPos.eq_copy_replaceEnd_append_get {s : String} {pos : s.ValidPos} (h : pos ≠ s.endValidPos) :
1969+
s = (s.replaceEnd pos).copy ++ singleton (pos.get h) ++ (s.replaceStart (pos.next h)).copy := by
1970+
simp [← bytes_inj, utf8Encode_get_eq_extract pos h, Slice.bytes_copy, ← size_bytes]
19461971

19471972
/--
19481973
Returns the next position in a string after position `p`. If `p` is not a valid position or

src/Init/Data/String/Lemmas/Map.lean

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/-
2+
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Markus Himmel
5+
-/
6+
module
7+
8+
prelude
9+
public import Init.Data.String.Modify
10+
import all Init.Data.String.Modify
11+
12+
/-!
13+
# Lemmas for `Init.Data.String.Modify`
14+
15+
This file contains lemmas for the operations defined in `Init.Data.String.Modify`.
16+
17+
Note that `Init.Data.String.Modify` already proves a few lemmas which are needed immediately.
18+
-/
19+
20+
public section
21+
22+
namespace String
23+
24+
-- TODO: `hp` actually follows from `h`.
25+
/-- You might want to invoke `ValidPos.Splits.exists_eq_singleton_append` to be able to apply this. -/
26+
theorem ValidPos.Splits.pastSet {s : String} {p : s.ValidPos} {t₁ t₂ : String} (hp : p ≠ s.endValidPos)
27+
{c d : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
28+
(p.pastSet d hp).Splits (t₁ ++ singleton d) t₂ := by
29+
obtain ⟨rfl, rfl, rfl⟩ := by simpa using h.eq (p.splits_next_right hp)
30+
apply splits_pastSet
31+
32+
-- TODO: `hp` actually follows from `h`.
33+
/-- You might want to invoke `ValidPos.Splits.exists_eq_singleton_append` to be able to apply this. -/
34+
theorem ValidPos.Splits.pastModify {s : String} {p : s.ValidPos} {t₁ t₂ : String} (hp : p ≠ s.endValidPos)
35+
{c : Char} (h : p.Splits t₁ (singleton c ++ t₂)) :
36+
(p.pastModify f hp).Splits (t₁ ++ singleton (f (p.get hp))) t₂ :=
37+
h.pastSet hp
38+
39+
theorem toList_mapAux {f : Char → Char} {s : String} {p : s.ValidPos}
40+
(h : p.Splits t₁ t₂) : (mapAux f s p).toList = t₁.toList ++ t₂.toList.map f := by
41+
fun_induction mapAux generalizing t₁ t₂ with
42+
| case1 s => simp_all
43+
| case2 s p hp ih =>
44+
obtain ⟨c, rfl⟩ := h.exists_eq_singleton_append hp
45+
simp [ih (h.pastModify hp)]
46+
47+
@[simp]
48+
theorem toList_map {f : Char → Char} {s : String} : (s.map f).toList = s.toList.map f := by
49+
simp [map, toList_mapAux s.splits_startValidPos]
50+
51+
end String

src/Init/Data/String/Lemmas/Splits.lean

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,25 @@ theorem Slice.Pos.splits {s : Slice} (p : s.Pos) :
8989
eq_append := copy_eq_copy_replaceEnd
9090
offset_eq_rawEndPos := by simp
9191

92+
theorem ValidPos.Splits.bytes_left_eq {s : String} {p : s.ValidPos} {t₁ t₂}
93+
(h : p.Splits t₁ t₂) : t₁.bytes = s.bytes.extract 0 p.offset.byteIdx := by
94+
simp [h.eq_append, h.offset_eq_rawEndPos, ByteArray.extract_append_eq_left]
95+
96+
theorem ValidPos.Splits.bytes_right_eq {s : String} {p : s.ValidPos} {t₁ t₂}
97+
(h : p.Splits t₁ t₂) : t₂.bytes = s.bytes.extract p.offset.byteIdx s.utf8ByteSize := by
98+
simp [h.eq_append, h.offset_eq_rawEndPos, ByteArray.extract_append_eq_right]
99+
92100
theorem ValidPos.Splits.eq_left {s : String} {p : s.ValidPos} {t₁ t₂ t₃ t₄}
93-
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₁ = t₃ := sorry
101+
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₁ = t₃ := by
102+
rw [← String.bytes_inj, h₁.bytes_left_eq, h₂.bytes_left_eq]
94103

95104
theorem ValidPos.Splits.eq_right {s : String} {p : s.ValidPos} {t₁ t₂ t₃ t₄}
96-
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₂ = t₄ := sorry
105+
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₂ = t₄ := by
106+
rw [← String.bytes_inj, h₁.bytes_right_eq, h₂.bytes_right_eq]
107+
108+
theorem ValidPos.Splits.eq {s : String} {p : s.ValidPos} {t₁ t₂ t₃ t₄}
109+
(h₁ : p.Splits t₁ t₂) (h₂ : p.Splits t₃ t₄) : t₁ = t₃ ∧ t₂ = t₄ :=
110+
⟨h₁.eq_left h₂, h₁.eq_right h₂⟩
97111

98112
@[simp]
99113
theorem splits_endValidPos (s : String) : s.endValidPos.Splits s "" where
@@ -111,9 +125,43 @@ theorem splits_startValidPos (s : String) : s.startValidPos.Splits "" s where
111125
offset_eq_rawEndPos := by simp
112126

113127
theorem ValidPos.splits_next_right {s : String} (p : s.ValidPos) (hp : p ≠ s.endValidPos) :
114-
p.Splits (s.replaceEnd p).copy (singleton (p.get hp) ++ (s.replaceStart (p.next hp)).copy) := sorry
128+
p.Splits (s.replaceEnd p).copy (singleton (p.get hp) ++ (s.replaceStart (p.next hp)).copy) where
129+
eq_append := by simpa [← append_assoc] using p.eq_copy_replaceEnd_append_get hp
130+
offset_eq_rawEndPos := by simp
115131

116132
theorem ValidPos.splits_next {s : String} (p : s.ValidPos) (hp : p ≠ s.endValidPos) :
117-
(p.next hp).Splits ((s.replaceEnd p).copy ++ singleton (p.get hp)) (s.replaceStart (p.next hp)).copy := sorry
133+
(p.next hp).Splits ((s.replaceEnd p).copy ++ singleton (p.get hp)) (s.replaceStart (p.next hp)).copy where
134+
eq_append := p.eq_copy_replaceEnd_append_get hp
135+
offset_eq_rawEndPos := by simp
136+
137+
theorem ValidPos.Splits.exists_eq_singleton_append {s : String} {p : s.ValidPos}
138+
(hp : p ≠ s.endValidPos) (h : p.Splits t₁ t₂) : ∃ t₂', t₂ = singleton (p.get hp) ++ t₂' :=
139+
⟨(s.replaceStart (p.next hp)).copy, h.eq_right (p.splits_next_right hp)⟩
140+
141+
theorem ValidPos.Splits.exists_eq_append_singleton {s : String} {p : s.ValidPos}
142+
(hp : p ≠ s.endValidPos) (h : (p.next hp).Splits t₁ t₂) : ∃ t₁', t₁ = t₁' ++ singleton (p.get hp) :=
143+
⟨(s.replaceEnd p).copy, h.eq_left (p.splits_next hp)⟩
144+
145+
-- TODO: move
146+
@[simp]
147+
theorem singleton_append_inj : singleton c ++ s = singleton d ++ t ↔ c = d ∧ s = t := by
148+
simp [← toList_inj]
149+
150+
-- TODO: move
151+
@[simp]
152+
theorem _root_.List.append_singleton_inj {l m : List α} : l ++ [a] = m ++ [b] ↔ l = m ∧ a = b := by
153+
rw [← List.reverse_inj, And.comm]; simp
154+
155+
-- TODO: move
156+
@[simp]
157+
theorem push_append_inj : push s c = push t d ↔ s = t ∧ c = d := by
158+
simp [← toList_inj]
159+
160+
-- TODO: `hp` actually follows from `h`.
161+
/-- You might want to invoke `ValidPos.Splits.exists_eq_singleton_append` to be able to apply this. -/
162+
theorem ValidPos.Splits.next {s : String} {p : s.ValidPos} (h : p.Splits t₁ (singleton c ++ t₂))
163+
(hp : p ≠ s.endValidPos) : (p.next hp).Splits (t₁ ++ singleton c) t₂ := by
164+
obtain ⟨rfl, rfl, rfl⟩ := by simpa using h.eq (splits_next_right p hp)
165+
exact splits_next p hp
118166

119167
end String

0 commit comments

Comments
 (0)