module Text.ParserCombinators.Poly.ByteString
(
Parser(P)
, Result(..)
, runParser
, next
, eof
, satisfy
, onFail
, manySatisfy
, many1Satisfy
, reparse
, module Text.ParserCombinators.Poly.Base
) where
import Text.ParserCombinators.Poly.Base
import Text.ParserCombinators.Poly.Result
import qualified Data.ByteString.Lazy as BS
import Data.ByteString.Lazy (ByteString)
import Control.Applicative
import qualified Control.Monad.Fail as Fail
import Data.Word
newtype Parser a = P (ByteString -> Result ByteString a)
runParser :: Parser a -> ByteString -> (Either String a, ByteString)
runParser (P p) = resultToEither . p
instance Functor Parser where
fmap f (P p) = P (fmap f . p)
instance Monad Parser where
return = pure
fail = Fail.fail
(P f) >>= g = P (continue . f)
where
continue (Success ts x) = let (P g') = g x in g' ts
continue (Committed r) = Committed (continue r)
continue (Failure ts e) = Failure ts e
instance Fail.MonadFail Parser where
fail e = P (\ts-> Failure ts e)
instance Commitment Parser where
commit (P p) = P (Committed . squash . p)
where
squash (Committed r) = squash r
squash r = r
(P p) `adjustErr` f = P (adjust . p)
where
adjust (Failure z e) = Failure z (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 (\ts-> case p ts of
Failure _ err ->
let (P p') = accum ((e,err):errs) ps
in p' ts
r@(Success _ _) -> r
r@(Committed _) -> r )
showErr (name,err) = name++":\n"++indent 2 err
instance Applicative Parser where
pure x = P (\ts-> Success ts x)
pf <*> px = do { f <- pf; x <- px; return (f x) }
#if defined(GLASGOW_HASKELL) && GLASGOW_HASKELL > 610
p <* q = p `discard` q
#endif
instance Alternative Parser where
empty = fail "no parse"
p <|> q = p `onFail` q
instance PolyParse Parser
next :: Parser Word8
next = P (\bs-> case BS.uncons bs of
Nothing -> Failure bs "Ran out of input (EOF)"
Just (h, t) -> Success t h )
eof :: Parser ()
eof = P (\bs -> if BS.null bs
then Success bs ()
else Failure bs "Expected end of input (EOF)" )
satisfy :: (Word8 -> Bool) -> Parser Word8
satisfy f = do { x <- next
; if f x then return x else fail "Parse.satisfy: failed"
}
onFail :: Parser a -> Parser a -> Parser a
(P p) `onFail` (P q) = P (\ts-> continue ts $ p ts)
where continue ts (Failure _ _) = q ts
continue _ r = r
manySatisfy :: (Word8->Bool) -> Parser ByteString
manySatisfy f = P (\bs-> let (pre,suf) = BS.span f bs in Success suf pre)
many1Satisfy :: (Word8->Bool) -> Parser ByteString
many1Satisfy f = do x <- manySatisfy f
if BS.null x then fail "Parse.many1Satisfy: failed"
else return x
reparse :: ByteString -> Parser ()
reparse ts = P (\inp-> Success (ts `BS.append` inp) ())