module Pipes.Attoparsec (
parse
, parsed
, parseL
, parsedL
, isEndOfParserInput
, ParserInput
, ParsingError(..)
) where
import Control.Exception (Exception)
import Control.Monad.Trans.Error (Error)
import qualified Control.Monad.Trans.State.Strict as S
import qualified Data.Attoparsec.ByteString
import qualified Data.Attoparsec.Text
import Data.Attoparsec.Types (IResult (..))
import qualified Data.Attoparsec.Types as Attoparsec
import Data.ByteString (ByteString)
import qualified Data.ByteString
import Data.Data (Data, Typeable)
import Data.Monoid (Monoid (mempty))
import Data.Text (Text)
import qualified Data.Text
import Pipes
import qualified Pipes.Parse as Pipes (Parser)
import qualified Pipes.Prelude as P
parse
:: (Monad m, ParserInput a)
=> Attoparsec.Parser a b
-> Pipes.Parser a m (Either ParsingError b)
parse parser = do
x <- parseL parser
return (case x of
Left e -> Left e
Right (_, a) -> Right a)
parsed
:: (Monad m, ParserInput a)
=> Attoparsec.Parser a b
-> Producer a m r
-> Producer b m (Either (ParsingError, Producer a m r) r)
parsed parser p = for (parsedL parser p) (\(_, a) -> yield a)
parseL
:: (Monad m, ParserInput a)
=> Attoparsec.Parser a b
-> Pipes.Parser a m (Either ParsingError (Int, b))
parseL parser = S.StateT $ \p0 -> do
x <- next (p0 >-> P.filter (/= mempty))
case x of
Left e -> go id (_parse parser mempty) (return e) 0
Right (t, p1) -> go (yield t >>) (_parse parser t) p1 $! _length t
where
go diffP iResult p0 len = case iResult of
Fail _ c m -> return (Left (ParsingError c m) , diffP p0)
Done t r -> return (Right (len _length t, r), yield t >> p0)
Partial k -> do
x <- next p0
case x of
Left e -> go diffP (k mempty) (return e) len
Right (t, p1) -> go (diffP . (yield t >>)) (k t) p1 $! len + _length t
parsedL
:: (Monad m, ParserInput a)
=> Attoparsec.Parser a b
-> Producer a m r
-> Producer (Int, b) m (Either (ParsingError, Producer a m r) r)
parsedL parser = go where
go p0 = do
mr <- lift $ S.evalStateT atEndOfParserInput p0
case mr of
Just r -> return (Right r)
Nothing -> do
(x, p1) <- lift $ S.runStateT (parseL parser) p0
case x of
Left e -> return (Left (e, p1))
Right a -> yield a >> go p1
isEndOfParserInput :: (Monad m, ParserInput a) => Pipes.Parser a m Bool
isEndOfParserInput = do
mr <- atEndOfParserInput
return (case mr of
Nothing -> False
Just _ -> True)
class (Eq a, Monoid a) => ParserInput a where
_parse :: Attoparsec.Parser a b -> a -> IResult a b
_length :: a -> Int
instance ParserInput ByteString where
_parse = Data.Attoparsec.ByteString.parse
_length = Data.ByteString.length
instance ParserInput Text where
_parse = Data.Attoparsec.Text.parse
_length = Data.Text.length
data ParsingError = ParsingError
{ peContexts :: [String]
, peMessage :: String
} deriving (Show, Read, Eq, Data, Typeable)
instance Exception ParsingError
instance Error ParsingError
instance Error (ParsingError, Producer a m r)
atEndOfParserInput
:: (Monad m, ParserInput a) => S.StateT (Producer a m r) m (Maybe r)
atEndOfParserInput = go =<< S.get where
go p0 = do
x <- lift (next p0)
case x of
Left r -> S.put (return r) >> return (Just r)
Right (a,p1)
| a == mempty -> go p1
| otherwise -> S.put (yield a >> p1) >> return Nothing