1 | module Data.String.Parser
2 | import public Control.Monad.Identity
3 | import Control.Monad.Trans
6 | import Data.String.Extra
9 | import Data.List.Alternating
11 | import Data.SnocList
25 | show s = "(" ++ show s.input ++ ", " ++ show s.pos ++ ", " ++ show s.maxPos ++ ")"
29 | data Result a = Fail Int String | OK a State
31 | Functor Result where
32 | map f (Fail i err) = Fail i err
33 | map f (OK r s) = OK (f r) s
36 | record ParseT (m : Type -> Type) (a : Type) where
38 | runParser : State -> m (Result a)
41 | Parser : Type -> Type
42 | Parser = ParseT Identity
45 | Functor m => Functor (ParseT m) where
46 | map f p = P $
\s => map (map f) (p.runParser s)
49 | Monad m => Applicative (ParseT m) where
50 | pure x = P $
\s => pure $
OK x s
51 | f <*> x = P $
\s => case !(f.runParser s) of
52 | OK f' s' => map (map f') (x.runParser s')
53 | Fail i err => pure $
Fail i err
56 | Monad m => Alternative (ParseT m) where
57 | empty = P $
\s => pure $
Fail s.pos "no alternative left"
58 | a <|> b = P $
\s => case !(a.runParser s) of
59 | OK r s' => pure $
OK r s'
60 | Fail _ _ => b.runParser s
63 | Monad m => Monad (ParseT m) where
64 | m >>= k = P $
\s => case !(m.runParser s) of
65 | OK a s' => (k a).runParser s'
66 | Fail i err => pure $
Fail i err
69 | MonadTrans ParseT where
70 | lift x = P $
\s => map (flip OK s) x
76 | parseT : Functor m => ParseT m a -> String -> m (Either String (a, Int))
77 | parseT p str = map (\case
78 | OK r s => Right (r, s.pos)
79 | Fail i err => Left $
let (line, col) = computePos i str in "Parse failed at position \{show line}-\{show col}: \{err}")
80 | (p.runParser (S str 0 (strLength str)))
82 | computePosAcc : Int -> List Char -> (Int, Int) -> (Int, Int)
83 | computePosAcc 0 input acc = acc
84 | computePosAcc n [] acc = acc
85 | computePosAcc n ('\n' :: is) (line, col) = computePosAcc (n - 1) is (line + 1, 0)
86 | computePosAcc n (i :: is) (line, col) = computePosAcc (n - 1) is (line, col + 1)
89 | computePos : Int -> String -> (Int, Int)
90 | computePos pos input = computePosAcc pos (fastUnpack input) (0,0)
96 | parse : Parser a -> String -> Either String (a, Int)
97 | parse p str = runIdentity $
parseT p str
102 | (<?>) : Functor m => ParseT m a -> String -> ParseT m a
103 | (<?>) p msg = P $
\s => map (\case
105 | Fail i _ => Fail i msg)
108 | export infixl 0 <?>
112 | skip : Functor m => ParseT m a -> ParseT m ()
117 | optionMap : Functor m => b -> (a -> b) -> ParseT m a -> ParseT m b
118 | optionMap def f p = P $
\s => map (\case
119 | OK r s' => OK (f r) s'
120 | Fail _ _ => OK def s)
125 | option : Functor m => a -> ParseT m a -> ParseT m a
126 | option def = optionMap def id
130 | succeeds : Functor m => ParseT m a -> ParseT m Bool
131 | succeeds = optionMap False (const True)
135 | optional : Functor m => ParseT m a -> ParseT m (Maybe a)
136 | optional = optionMap Nothing Just
142 | requireFailure : Functor m => ParseT m a -> ParseT m ()
143 | requireFailure (P runParser) = P $
\s => reverseResult s <$> runParser s
145 | reverseResult : State -> Result a -> Result ()
146 | reverseResult s (Fail _ _) = OK () s
147 | reverseResult s (OK _ _) = Fail (pos s) "Purposefully changed OK to Fail"
151 | fail : Applicative m => String -> ParseT m a
152 | fail x = P $
\s => pure $
Fail s.pos x
156 | satisfy : Applicative m => (Char -> Bool) -> ParseT m Char
157 | satisfy f = P $
\s => pure $
if s.pos < s.maxPos
158 | then let ch = assert_total $
strIndex s.input s.pos in
160 | then OK ch (S s.input (s.pos + 1) s.maxPos)
161 | else Fail s.pos "could not satisfy predicate"
162 | else Fail s.pos "could not satisfy predicate"
166 | string : Applicative m => String -> ParseT m String
167 | string str = P $
\s => pure $
let len = strLength str in
168 | if s.pos+len <= s.maxPos
169 | then let head = strSubstr s.pos len s.input in
171 | then OK str (S s.input (s.pos + len) s.maxPos)
172 | else Fail s.pos ("string " ++ show str)
173 | else Fail s.pos ("string " ++ show str)
177 | eos : Applicative m => ParseT m ()
178 | eos = P $
\s => pure $
if s.pos == s.maxPos
180 | else Fail s.pos "expected the end of the string"
184 | char : Applicative m => Char -> ParseT m Char
185 | char c = satisfy (== c) <?> "expected \{show c}"
189 | space : Applicative m => ParseT m Char
190 | space = satisfy isSpace <?> "expected space"
195 | alphaNum : Applicative m => ParseT m Char
196 | alphaNum = satisfy isAlphaNum <?> "expected letter or digit"
201 | letter : Applicative m => ParseT m Char
202 | letter = satisfy isAlpha <?> "expected letter"
209 | some : Monad m => ParseT m a -> ParseT m (List a)
217 | many : Monad m => ParseT m a -> ParseT m (List a)
218 | many p = some p <|> pure []
223 | hchainl : Monad m => ParseT m init -> ParseT m (init -> arg -> init) -> ParseT m arg -> ParseT m init
224 | hchainl pini pop parg = pini >>= go
227 | go : init -> ParseT m init
228 | go x = (do op <- pop
230 | go $
op x arg) <|> pure x
235 | hchainr : Monad m => ParseT m arg -> ParseT m (arg -> end -> end) -> ParseT m end -> ParseT m end
236 | hchainr parg pop pend = go id <*> pend
239 | go : (end -> end) -> ParseT m (end -> end)
240 | go f = (do arg <- parg
242 | go $
f . op arg) <|> pure f
248 | takeWhile : Monad m => (Char -> Bool) -> ParseT m String
249 | takeWhile f = pack <$> many (satisfy f)
254 | takeWhile1 : Monad m => (Char -> Bool) -> ParseT m String
255 | takeWhile1 f = pack <$> some (satisfy f)
261 | takeUntil : Monad m => (stop : String) -> ParseT m String
262 | takeUntil stop = do
263 | let StrCons s top = strM stop
264 | | StrNil => pure ""
265 | takeUntil' s top [<]
267 | takeUntil' : Monad m' => (s : Char) -> (top : String) -> (acc : SnocList String) -> ParseT m' String
268 | takeUntil' s top acc = do
269 | init <- takeWhile (/= s)
270 | skip $
char s <?> "end of string reached - \{show stop} not found"
271 | case !(succeeds $
string top) of
272 | False => takeUntil' s top $
acc :< (init +> s)
273 | True => pure $
concat $
acc :< init
278 | spaces : Monad m => ParseT m ()
279 | spaces = skip (many space)
284 | spaces1 : Monad m => ParseT m ()
285 | spaces1 = skip (some space) <?> "whitespaces"
291 | between : Monad m => ParseT m o -> ParseT m c -> ParseT m p -> ParseT m p
292 | between o c p = id <$ o <*> p <* c
296 | parens : Monad m => ParseT m a -> ParseT m a
297 | parens p = between (char '(') (char ')') p
302 | lexeme : Monad m => ParseT m a -> ParseT m a
303 | lexeme p = p <* spaces
308 | token : Monad m => String -> ParseT m ()
309 | token s = lexeme (skip $
string s) <?> "expected token " ++ show s
313 | digit : Monad m => ParseT m (Fin 10)
314 | digit = do x <- satisfy isDigit
315 | case lookup x digits of
316 | Nothing => fail "not a digit"
319 | digits : List (Char, Fin 10)
320 | digits = [ ('0', 0)
332 | fromDigits : Num a => (Fin 10 -> a) -> List (Fin 10) -> a
333 | fromDigits f xs = foldl addDigit 0 xs
335 | addDigit : a -> Fin 10 -> a
336 | addDigit num d = 10*num + f d
338 | intFromDigits : List (Fin 10) -> Integer
339 | intFromDigits = fromDigits finToInteger
341 | natFromDigits : List (Fin 10) -> Nat
342 | natFromDigits = fromDigits finToNat
347 | natural : Monad m => ParseT m Nat
348 | natural = natFromDigits <$> some digit
353 | integer : Monad m => ParseT m Integer
354 | integer = do minus <- succeeds (char '-')
356 | pure $
if minus then (intFromDigits x)*(-
1) else intFromDigits x
366 | sepBy1 : Monad m => (p : ParseT m a)
367 | -> (s : ParseT m b)
368 | -> ParseT m (List1 a)
369 | sepBy1 p s = [| p ::: many (s *> p) |]
378 | sepBy : Monad m => (p : ParseT m a)
379 | -> (s : ParseT m b)
380 | -> ParseT m (List a)
381 | sepBy p s = optionMap [] forget (p `sepBy1` s)
386 | commaSep1 : Monad m => ParseT m a -> ParseT m (List1 a)
387 | commaSep1 p = p `sepBy1` (char ',')
392 | commaSep : Monad m => ParseT m a -> ParseT m (List a)
393 | commaSep p = p `sepBy` (char ',')
402 | alternating : Monad m
405 | -> ParseT m (Odd a b)
406 | alternating x y = do vx <- x
407 | (vx ::) <$> [| y :: alternating x y |] <|> pure [vx]
412 | ntimes : Monad m => (n : Nat) -> ParseT m a -> ParseT m (Vect n a)
413 | ntimes Z p = pure Vect.Nil
414 | ntimes (S n) p = [| p :: (ntimes n p) |]