iterIO-0.2: Data/IterIO/Atto.hs
-- | This module contains an adapter function to run attoparsec
-- 'Parser's from within the 'Iter' monad.
module Data.IterIO.Atto where
import Data.Attoparsec as A
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as S
import Data.IterIO
-- | Class of types whose 'Iter's can be converted to strict
-- 'S.ByteString's. Basically just strict 'S.ByteString's and lazy
-- 'L.ByteString's. This class mostly exists so that the 'atto'
-- function can work with either type of ByteString.
class (ChunkData t) => IterStrictByteString t where
fromIterStrictByteString :: (Monad m) => Iter S.ByteString m a -> Iter t m a
instance IterStrictByteString S.ByteString where
{-# INLINE fromIterStrictByteString #-}
fromIterStrictByteString = id
instance IterStrictByteString L.ByteString where
{-# INLINE fromIterStrictByteString #-}
fromIterStrictByteString = (inumLtoS .|)
-- | Run an attoparsec parser in an 'Iter' monad. Throws an
-- 'IterFail' exception with constructor 'IterParseErr' if the parse
-- fails. (This exception can be handled with 'multiParse' and
-- 'ifParse'.)
atto :: (IterStrictByteString t, Monad m) =>
A.Parser a -> Iter t m a
atto parser = fromIterStrictByteString $
data0I >>= A.parseWith data0I parser >>= check
where check (A.Done t a) = ungetI t >> return a
check (A.Fail t _ e) = ungetI t >> throwParseI e
check _ = error $ "atto: Partial"
-- | Try running an attoparsec parser. Returns @'Right' a@ if the
-- parser succeeds with result @a@. Returns @'Left' err@ where @err@
-- is an error message otherwise. Note that the input stream will be
-- in an indeterminate state should the parser fail. (If you need to
-- keep parsing input from some known state, it may be better to use
-- 'atto' in conjunction with 'multiParse'.)
tryAtto :: (IterStrictByteString t, Monad m) =>
A.Parser a -> Iter t m (Either String a)
tryAtto parser = either check Right `fmap` tryFI (atto parser)
where check (IterParseErr e) = Left e
check _ = error "tryAtto"