/- Copyright (c) 2018 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Sebastian Ullrich, Leonardo de Moura Trie for tokenizing the Lean language -/ prelude import init.data.rbmap import init.lean.format namespace Lean namespace Parser inductive Trie (α : Type) | Node : Option α → RBNode Char (fun _ => Trie) → Trie namespace Trie variables {α : Type} def empty : Trie α := ⟨none, RBNode.leaf⟩ instance : HasEmptyc (Trie α) := ⟨empty⟩ instance : Inhabited (Trie α) := ⟨Node none RBNode.leaf⟩ private partial def insertEmptyAux (s : String) (val : α) : String.Pos → Trie α | i => match s.atEnd i with | true => Trie.Node (some val) RBNode.leaf | false => let c := s.get i; let t := insertEmptyAux (s.next i); Trie.Node none (RBNode.singleton c t) private partial def insertAux (s : String) (val : α) : Trie α → String.Pos → Trie α | Trie.Node v m, i => match s.atEnd i with | true => Trie.Node (some val) m -- overrides old value | false => let c := s.get i; let i := s.next i; let t := match RBNode.find Char.lt m c with | none => insertEmptyAux s val i | some t => insertAux t i; Trie.Node v (RBNode.insert Char.lt m c t) def insert (t : Trie α) (s : String) (val : α) : Trie α := insertAux s val t 0 private partial def findAux (s : String) : Trie α → String.Pos → Option α | Trie.Node val m, i => match s.atEnd i with | true => val | false => let c := s.get i; let i := s.next i; match RBNode.find Char.lt m c with | none => none | some t => findAux t i def find (t : Trie α) (s : String) : Option α := findAux s t 0 private def updtAcc (v : Option α) (i : String.Pos) (acc : String.Pos × Option α) : String.Pos × Option α := match v, acc with | some v, (j, w) => (i, some v) -- we pattern match on `acc` to enable memory reuse | none, acc => acc private partial def matchPrefixAux (s : String) : Trie α → String.Pos → (String.Pos × Option α) → String.Pos × Option α | Trie.Node v m, i, acc => match s.atEnd i with | true => updtAcc v i acc | false => let acc := updtAcc v i acc; let c := s.get i; let i := s.next i; match RBNode.find Char.lt m c with | some t => matchPrefixAux t i acc | none => acc def matchPrefix (s : String) (t : Trie α) (i : String.Pos) : String.Pos × Option α := matchPrefixAux s t i (i, none) private partial def toStringAux {α : Type} : Trie α → List Format | Trie.Node val map => map.fold (fun Fs c t => format (repr c) :: (Format.group $ Format.nest 2 $ flip Format.joinSep Format.line $ toStringAux t) :: Fs) [] instance {α : Type} : HasToString (Trie α) := ⟨fun t => (flip Format.joinSep Format.line $ toStringAux t).pretty⟩ end Trie end Parser end Lean