Spaces:
Sleeping
Sleeping
| -- File: lean/PathSpec.lean | |
| -- Path Canonicalization Specification | |
| -- Agents migrate a C path library to Rust (Vec<String> segment lists). | |
| -- Path = List String where each element is a non-empty segment (no "/" markers). | |
| namespace PathSpec | |
| abbrev Path := List String | |
| -- Internal: reversed accumulator, head = most recently added segment | |
| def normalizeAux (acc : Path) : Path → Path | |
| | [] => acc.reverse | |
| | seg :: rest => | |
| if seg == "." then normalizeAux acc rest | |
| else if seg == ".." then | |
| match acc with | |
| | [] => normalizeAux [] rest -- clamp at root | |
| | _ :: acc' => normalizeAux acc' rest | |
| else normalizeAux (seg :: acc) rest | |
| -- Remove "." segments; resolve ".." clamped at root | |
| def normalize (p : Path) : Path := normalizeAux [] p | |
| -- Join two segment lists: normalize the concatenation | |
| def join (base rel : Path) : Path := normalize (base ++ rel) | |
| -- Path depth = segment count | |
| def depth (p : Path) : Nat := p.length | |
| -- A path is in normal form if it contains no "." or ".." segments | |
| def isNormal (p : Path) : Bool := | |
| p.all (fun s => s != "." && s != "..") | |
| -- Helper: elements of normalizeAux output are never "." or ".." | |
| theorem normalizeAux_no_special (acc p : Path) | |
| (hacc : ∀ s ∈ acc, s ≠ "." ∧ s ≠ "..") : | |
| ∀ s ∈ normalizeAux acc p, s ≠ "." ∧ s ≠ ".." := by | |
| induction p generalizing acc with | |
| | nil => | |
| intro s hs | |
| simp only [normalizeAux] at hs | |
| exact hacc s (List.mem_reverse.mp hs) | |
| | cons seg rest ih => | |
| intro s hs | |
| cases h1 : (seg == ".") | |
| · -- (seg == ".") = false | |
| cases h2 : (seg == "..") | |
| · -- (seg == "..") = false — seg is normal, pushed onto acc | |
| simp only [normalizeAux, h1, h2] at hs | |
| apply ih (seg :: acc) _ s hs | |
| intro t ht | |
| rcases List.mem_cons.mp ht with rfl | ht' | |
| · exact ⟨fun heq => by simp [heq] at h1, fun heq => by simp [heq] at h2⟩ | |
| · exact hacc t ht' | |
| · -- (seg == "..") = true — pop acc | |
| cases acc with | |
| | nil => | |
| simp only [normalizeAux, h1, h2, ↓reduceIte] at hs | |
| exact ih [] (fun _ hm => by simp at hm) s hs | |
| | cons x acc' => | |
| simp only [normalizeAux, h1, h2, ↓reduceIte] at hs | |
| exact ih acc' (fun t ht => hacc t (List.mem_cons.mpr (Or.inr ht))) s hs | |
| · -- (seg == ".") = true — skip | |
| simp only [normalizeAux, h1, ↓reduceIte] at hs | |
| exact ih acc hacc s hs | |
| -- Helper: normalizeAux on a path with no special segments equals acc.reverse ++ p | |
| theorem normalizeAux_on_normal (acc p : Path) | |
| (hp : ∀ s ∈ p, s ≠ "." ∧ s ≠ "..") : | |
| normalizeAux acc p = acc.reverse ++ p := by | |
| induction p generalizing acc with | |
| | nil => simp [normalizeAux] | |
| | cons seg rest ih => | |
| obtain ⟨hne1, hne2⟩ := hp seg (List.mem_cons.mpr (Or.inl rfl)) | |
| have h1 : (seg == ".") = false := beq_eq_false_iff_ne.mpr hne1 | |
| have h2 : (seg == "..") = false := beq_eq_false_iff_ne.mpr hne2 | |
| simp only [normalizeAux, h1, h2] | |
| rw [ih (seg :: acc) (fun s hs => hp s (List.mem_cons.mpr (Or.inr hs)))] | |
| simp [List.reverse_cons, List.append_assoc] | |
| -- Normalization is idempotent | |
| theorem normalize_idempotent (p : Path) : normalize (normalize p) = normalize p := by | |
| unfold normalize | |
| rw [normalizeAux_on_normal [] | |
| (normalizeAux [] p) | |
| (normalizeAux_no_special [] p (fun _ h => by simp at h))] | |
| simp | |
| -- DRT checks (native_decide: ground equalities) | |
| example : normalize ["usr", "local", "..", "bin"] = ["usr", "bin"] := by native_decide | |
| example : normalize [".", "a", ".", "b"] = ["a", "b"] := by native_decide | |
| example : normalize ["..", "a"] = ["a"] := by native_decide | |
| example : normalize ["a", "b", "..", ".."] = [] := by native_decide | |
| example : normalize ["a", ".", "b", "..", "c"] = ["a", "c"] := by native_decide | |
| example : join ["usr", "local"] ["bin"] = ["usr", "local", "bin"] := by native_decide | |
| example : join ["a", "b"] [".."] = ["a"] := by native_decide | |
| example : depth ["a", "b", "c"] = 3 := by native_decide | |
| example : depth [] = 0 := by native_decide | |
| end PathSpec | |