module Text.ParserCombinators.Poly.StateParser
(
Parser(P)
, Result(..)
, next
, eof
, satisfy
, onFail
, stUpdate
, stQuery
, stGet
, reparse
) where
import Text.ParserCombinators.Poly.Base
import Text.ParserCombinators.Poly.Result
newtype Parser s t a = P (s -> [t] -> Result ([t],s) a)
instance Functor (Parser s t) where
fmap f (P p) = P (\s-> fmap f . p s)
instance Monad (Parser s t) where
return x = P (\s ts-> Success (ts,s) x)
fail e = P (\s ts-> Failure (ts,s) e)
(P f) >>= g = P (\s-> continue . f s)
where
continue (Success (ts,s) x) = let (P g') = g x in g' s ts
continue (Committed r) = Committed (continue r)
continue (Failure tss e) = Failure tss e
instance Commitment (Parser s t) where
commit (P p) = P (\s-> Committed . squash . p s)
where
squash (Committed r) = squash r
squash r = r
(P p) `adjustErr` f = P (\s-> adjust . p s)
where
adjust (Failure zs e) = Failure zs (f e)
adjust (Committed r) = Committed (adjust r)
adjust good = good
oneOf' = accum []
where accum errs [] =
fail ("failed to parse any of the possible choices:\n"
++indent 2 (concatMap showErr (reverse errs)))
accum errs ((e,P p):ps) =
P (\s ts-> case p s ts of
Failure _ err ->
let (P p) = accum ((e,err):errs) ps
in p s ts
r@(Success _ a) -> r
r@(Committed _) -> r )
showErr (name,err) = name++":\n"++indent 2 err
infixl 6 `onFail`
onFail :: Parser s t a -> Parser s t a -> Parser s t a
(P p) `onFail` (P q) = P (\s ts-> continue s ts $ p s ts)
where
continue s ts (Failure _ _) = q s ts
continue _ _ r = r
next :: Parser s t t
next = P (\s ts-> case ts of
[] -> Failure ([],s) "Ran out of input (EOF)"
(t:ts') -> Success (ts',s) t )
eof :: Parser s t ()
eof = P (\s ts-> case ts of
[] -> Success ([],s) ()
(t:ts') -> Failure (ts,s) "Expected end of input (eof)" )
satisfy :: (t->Bool) -> Parser s t t
satisfy pred = do { x <- next
; if pred x then return x else fail "Parse.satisfy: failed"
}
stUpdate :: (s->s) -> Parser s t ()
stUpdate f = P (\s ts-> Success (ts, f s) ())
stQuery :: (s->a) -> Parser s t a
stQuery f = P (\s ts-> Success (ts,s) (f s))
stGet :: Parser s t s
stGet = P (\s ts-> Success (ts,s) s)
reparse :: [t] -> Parser s t ()
reparse ts = P (\s inp-> Success ((ts++inp),s) ())