0 | module Text.ILex.Char.Set
  1 |
  2 | import Data.Vect
  3 | import Derive.Prelude
  4 | import public Text.ILex.Char.Range
  5 |
  6 | %language ElabReflection
  7 | %default total
  8 |
  9 | --------------------------------------------------------------------------------
 10 | -- Sets
 11 | --------------------------------------------------------------------------------
 12 |
 13 | ||| A set of unicode points (actually, a set of 32-bit characters)
 14 | ||| represented internally as an ordered list of disjoint character
 15 | ||| ranges.
 16 | export
 17 | record SetOf t where
 18 |   constructor S
 19 |   ||| A list of ordered, non-overlapping, non-adjacent, and non-empty ranges
 20 |   ranges_ : List (RangeOf t)
 21 |
 22 | %runElab derive "SetOf" [Show,Eq,Ord]
 23 |
 24 | public export
 25 | 0 Set8 : Type
 26 | Set8 = SetOf Bits8
 27 |
 28 | public export
 29 | 0 Set32 : Type
 30 | Set32 = SetOf Bits32
 31 |
 32 | ||| Returns the inner list of ranges of a character set.
 33 | |||
 34 | ||| The returned list is sorted and the ranges it contains are disjoint
 35 | ||| and non-adjacent.
 36 | export %inline
 37 | ranges : SetOf t -> List (RangeOf t)
 38 | ranges = ranges_
 39 |
 40 | ||| The empty set of codepoints.
 41 | export
 42 | empty : SetOf t
 43 | empty = S []
 44 |
 45 | ||| The set holding only the given codepoint.
 46 | export
 47 | singleton : t -> SetOf t
 48 | singleton x = S [singleton x]
 49 |
 50 | ||| The set holding all characters in the given range.
 51 | export
 52 | range : RangeOf t -> SetOf t
 53 | range r = if isEmpty r then empty else S [r]
 54 |
 55 | ||| `True` if the character set is empty.
 56 | export %inline
 57 | isEmpty : SetOf t -> Bool
 58 | isEmpty (S []) = True
 59 | isEmpty _      = False
 60 |
 61 | ||| True if the value is within the set.
 62 | export %inline
 63 | has : Ord t => SetOf t -> t -> Bool
 64 | has (S rs) v = any (`has` v) rs
 65 |
 66 | parameters {0 t : Type}
 67 |            {auto ord : WithBounds t}
 68 |            {auto ng  : Neg t}
 69 |
 70 |   -- precondition: the list is already sorted
 71 |   normalise : SnocList (RangeOf t) -> Vect n (RangeOf t) -> List (RangeOf t)
 72 |   normalise sc []       = sc <>> []
 73 |   normalise sc [r]      = if isEmpty r then [] else sc <>> [r]
 74 |   normalise sc (r1 :: r2 :: t) =
 75 |     case union r1 r2 of
 76 |       Left r      => if isEmpty r then normalise sc t else normalise sc (r::t)
 77 |       Right (x,y) => normalise (sc:<x) (y::t)
 78 |
 79 |   ||| Creates a character set from the given list of ranges.
 80 |   |||
 81 |   ||| The ranges are first sorted and overlapping or adjacent ranges
 82 |   ||| are unified before wrapping them up.
 83 |   export
 84 |   rangeSet : List (RangeOf t) -> SetOf t
 85 |   rangeSet rs = S . normalise [<] $ fromList (sort rs)
 86 |
 87 |   ||| Set union.
 88 |   export
 89 |   union : SetOf t -> SetOf t -> SetOf t
 90 |   union (S rs) (S ss) = rangeSet (rs ++ ss)
 91 |
 92 |   appendNonEmpty : SnocList (RangeOf t) -> RangeOf t -> SnocList (RangeOf t)
 93 |   appendNonEmpty sr r = if isEmpty r then sr else sr :< r
 94 |
 95 |   inters :
 96 |        SnocList (RangeOf t)
 97 |     -> List (RangeOf t)
 98 |     -> List (RangeOf t)
 99 |     -> List (RangeOf t)
100 |   inters sr l@(x::xs) r@(y::ys) =
101 |     let sr2 := appendNonEmpty sr (intersection x y)
102 |      in case upperBound x < upperBound y of
103 |           True  => inters sr2 xs r
104 |           False => inters sr2 l  ys
105 |   inters sr _         _         = sr <>> []
106 |
107 |   ||| Set intersection.
108 |   export %inline
109 |   intersection : SetOf t -> SetOf t -> SetOf t
110 |   intersection (S rs) (S ss) = S (inters [<] rs ss)
111 |
112 |   ||| Set negation.
113 |   export
114 |   negation : SetOf t -> SetOf t
115 |   negation (S rs) = S $ go [<] 0 rs
116 |     where
117 |       go : SnocList (RangeOf t) -> t -> List (RangeOf t) -> List (RangeOf t)
118 |       go sx m []        = sx <>> [range m maxBound]
119 |       go sx m (x :: xs) =
120 |         case isEmpty x of
121 |           True  => go sx m xs
122 |           False =>
123 |            let l   := lowerBound x
124 |                u   := upperBound x
125 |                sx2 := if l > m then sx :< range m (l-1) else sx
126 |             in if u == maxBound then sx2 <>> [] else go sx2 (u+1) xs
127 |
128 |   ||| Set difference.
129 |   export
130 |   difference : SetOf t -> SetOf t -> SetOf t
131 |   difference x y = intersection x (negation y)
132 |
133 | export %inline
134 | FromChar Set32 where
135 |   fromChar = singleton . cast
136 |
137 | ||| The set holding the codepoints (characters) in the given
138 | ||| string.
139 | export
140 | chars : String -> Set32
141 | chars = rangeSet . map (singleton . cast) . unpack
142 |
143 | ||| The set holding all 32-bit values.
144 | export %inline
145 | fullSet : WithBounds t => SetOf t
146 | fullSet = range fullRange
147 |
148 | ||| `True` if this set holds all 32-bit values.
149 | export %inline
150 | isFull : WithBounds t => SetOf t -> Bool
151 | isFull = (== fullSet)
152 |
153 | --------------------------------------------------------------------------------
154 | -- Specific Char Sets
155 | --------------------------------------------------------------------------------
156 |
157 | ||| A range of unicode code points.
158 | export %inline
159 | charRange : Char -> Char -> Set32
160 | charRange x y = range $ charRange x y
161 |
162 | ||| The set of lower-case letters.
163 | export
164 | lower : Set32
165 | lower = charRange 'a' 'z'
166 |
167 | ||| The set of upper-case letters.
168 | export
169 | upper : Set32
170 | upper = charRange 'A' 'Z'
171 |
172 | ||| The set of letters.
173 | export
174 | alpha : Set32
175 | alpha = union lower upper
176 |
177 | ||| The set of digits.
178 | export
179 | digit : Set32
180 | digit = charRange '0' '9'
181 |
182 | ||| The set of positive digits.
183 | export
184 | posdigit : Set32
185 | posdigit = charRange '1' '9'
186 |
187 | ||| The set of digits and letters.
188 | export
189 | alphaNum : Set32
190 | alphaNum = union alpha digit
191 |
192 | ||| The set of control characters.
193 | export
194 | control : Set32
195 | control = charRange '\NUL' '\US' `union` charRange '\DEL' '\159'
196 |
197 | ||| The set of printable characters.
198 | |||
199 | ||| This is the negation of `control`.
200 | export
201 | printable : Set32
202 | printable = negation control
203 |
204 | ||| The set of ASCII characters.
205 | export
206 | ascii : Set32
207 | ascii = range $ range 0 127
208 |
209 | ||| The set of non-control ASCII characters.
210 | export
211 | printableAscii : Set32
212 | printableAscii = intersection ascii printable
213 |
214 | ||| The newline character ('\n')
215 | export
216 | nl : Set32
217 | nl = '\n'
218 |
219 | ||| The set of unicode code points (minus surrogate pairs).
220 | export
221 | unicode : Set32
222 | unicode = difference (range codepoint) (range surrogate)
223 |