0 | module Text.ParseError
3 | import Derive.Prelude
8 | %language ElabReflection
11 | data DigitType : Type where
17 | %runElab derive "DigitType" [Show,Eq,Ord]
20 | Interpolation DigitType where
21 | interpolate Bin = "a binary digit ('0' or '1')"
22 | interpolate Oct = "an octal digit ('0' to '7')"
23 | interpolate Dec = "a decimal digit ('0' to '9')"
24 | interpolate Hex = "a hexadecimal digit ('0' to '9' or 'a' to 'f')"
27 | data CharClass : Type where
32 | Digit : DigitType -> CharClass
44 | AlphaNum : CharClass
46 | %runElab derive "CharClass" [Show,Eq,Ord]
49 | Interpolation CharClass where
50 | interpolate Space = "a space character"
51 | interpolate (Digit x) = interpolate x
52 | interpolate Upper = "an upper-case letter"
53 | interpolate Lower = "a lower-case letter"
54 | interpolate Alpha = "a letter ('a' to 'z' or 'A' to 'Z')"
55 | interpolate AlphaNum = "a letter or a digit"
62 | data InnerError : (err : Type) -> Type where
64 | Custom : (err : e) -> InnerError e
70 | Expected : List String -> String -> InnerError e
73 | ExpectedChar : CharClass -> InnerError e
76 | ExpectedEOI : InnerError e
79 | InvalidControl : Char -> InnerError e
82 | InvalidEscape : InnerError e
85 | OutOfBounds : String -> InnerError e
88 | Unclosed : String -> InnerError e
91 | Unknown : String -> InnerError e
96 | InvalidByte : Bits8 -> InnerError e
98 | %runElab derive "InnerError" [Show,Eq]
102 | 0 BoundedErr : Type -> Type
103 | BoundedErr = Bounded . InnerError
106 | Functor InnerError where
107 | map f (Custom err) = Custom $
f err
109 | map f (Expected xs x) = Expected xs x
110 | map f (ExpectedChar x) = ExpectedChar x
111 | map f ExpectedEOI = ExpectedEOI
112 | map f (InvalidControl c1) = InvalidControl c1
113 | map f InvalidEscape = InvalidEscape
114 | map f (OutOfBounds x) = OutOfBounds x
115 | map f (Unclosed x) = Unclosed x
116 | map f (Unknown x) = Unknown x
117 | map f (InvalidByte x) = InvalidByte x
119 | uncontrol : Char -> String
120 | uncontrol c = if isControl c then adj (unpack $
show c) else singleton c
122 | adj : List Char -> String
123 | adj = pack . filter ('\'' /=)
125 | quote : String -> String
127 | case map uncontrol (unpack s) of
129 | cs => "\"\{concat cs}\""
131 | quotes : String -> List String -> String
132 | quotes x [] = quote x
133 | quotes x [y] = "\{quote x} or \{quote y}"
134 | quotes x xs = go x xs
136 | go : String -> List String -> String
137 | go s [] = "or \{quote s}"
138 | go s (y :: ys) = "\{quote s}, " ++ go y ys
146 | hexChar : Bits8 -> Char
168 | toHex : Bits8 -> String
169 | toHex x = pack [hexChar (shiftR x 4), hexChar (x .&. 15)]
172 | Interpolation e => Interpolation (InnerError e) where
173 | interpolate EOI = "Unexpected end of input"
174 | interpolate (Expected [] x) = "Unexpected \{quote x}"
175 | interpolate (Expected (s::ss) x) = "Expected \{quotes s ss}, but got \{quote x}"
176 | interpolate (ExpectedChar x) = "Expected \{x}"
177 | interpolate ExpectedEOI = "Expected end of input"
178 | interpolate (InvalidControl c) = "Invalid control character: '\{uncontrol c}'"
179 | interpolate InvalidEscape = "Invalid escape sequence"
180 | interpolate (OutOfBounds x) = "Value out of bounds: \{x}"
181 | interpolate (Unclosed x) = "Unclosed \{quote x}"
182 | interpolate (Unknown x) = "Unknown or invalid token: \{x}"
183 | interpolate (Custom err) = interpolate err
184 | interpolate (InvalidByte x) = "Unexpected or invalid byte: 0x\{toHex x}"
191 | interface FailParse (0 m : Type -> Type) (0 e : Type) | m where
192 | parseFail : Bounds -> InnerError e -> m a
194 | public export %inline
195 | FailParse (Either $
Bounded $
InnerError e) e where
196 | parseFail b err = Left (B err b)
198 | public export %inline
199 | custom : FailParse m e => Bounds -> e -> m a
200 | custom b = parseFail b . Custom
202 | public export %inline
203 | expected : Interpolation t => FailParse m e => Bounds -> t -> String -> m a
204 | expected b v s = parseFail b $
Expected [interpolate v] s
206 | public export %inline
207 | unclosed : Interpolation t => FailParse m e => Bounds -> t -> m a
208 | unclosed b = parseFail b . Unclosed . interpolate
210 | public export %inline
211 | unexpected : Interpolation t => FailParse m e => Bounded t -> m a
212 | unexpected v = parseFail v.bounds (Expected [] . interpolate $
v.val)
214 | public export %inline
215 | eoi : FailParse m e => m a
216 | eoi = parseFail NoBounds EOI
218 | public export %inline
219 | expectedEOI : FailParse m e => Bounds -> m a
220 | expectedEOI b = parseFail b ExpectedEOI
227 | fromVoid : InnerError Void -> InnerError e
229 | fromVoid (Expected xs x) = Expected xs x
230 | fromVoid (ExpectedChar x) = ExpectedChar x
231 | fromVoid ExpectedEOI = ExpectedEOI
232 | fromVoid (InvalidControl c) = InvalidControl c
233 | fromVoid InvalidEscape = InvalidEscape
234 | fromVoid (OutOfBounds x) = OutOfBounds x
235 | fromVoid (Unclosed x) = Unclosed x
236 | fromVoid (Unknown x) = Unknown x
237 | fromVoid (InvalidByte b) = InvalidByte b
246 | record ParseError e where
261 | content : Maybe String
264 | error : InnerError e
266 | %runElab derive "ParseError" [Show,Eq]
271 | toParseError : Origin -> String -> Bounded (InnerError e) -> ParseError e
272 | toParseError o s (B err bs) = PE o bs bs (Just s) err
275 | Interpolation e => Interpolation (ParseError e) where
276 | interpolate (PE origin bounds relbs cont err) =
277 | let fc := FC origin bounds
279 | Just c => unlines $
"Error: \{err}" :: printFC fc relbs (lines c)
280 | Nothing => unlines ["Error: \{err}", interpolate fc]
286 | -> Either (Bounded (InnerError e)) a
287 | -> Either (ParseError e) a
288 | leftErr o = mapFst . toParseError o