module Data.Attoparsec.Internal.Types
(
Parser(..)
, Failure
, Success
, IResult(..)
, Input(..)
, Added(..)
, More(..)
, addS
, (<>)
, Chunk(..)
) where
import Control.Applicative (Alternative(..), Applicative(..), (<$>))
import Control.DeepSeq (NFData(rnf))
import Control.Monad (MonadPlus(..))
import Data.ByteString (ByteString)
import Data.ByteString.Internal (w2c)
import Data.Monoid (Monoid(..))
import Data.Text (Text)
import Data.Word (Word8)
import Prelude hiding (getChar, take, takeWhile)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BS
import qualified Data.Text as T
import qualified Data.Text.Unsafe as T
data IResult t r = Fail t [String] String
| Partial (t -> IResult t r)
| Done t r
instance (Show t, Show r) => Show (IResult t r) where
show (Fail t stk msg) =
"Fail " ++ show t ++ " " ++ show stk ++ " " ++ show msg
show (Partial _) = "Partial _"
show (Done t r) = "Done " ++ show t ++ " " ++ show r
instance (NFData t, NFData r) => NFData (IResult t r) where
rnf (Fail t stk msg) = rnf t `seq` rnf stk `seq` rnf msg
rnf (Partial _) = ()
rnf (Done t r) = rnf t `seq` rnf r
fmapR :: (a -> b) -> IResult t a -> IResult t b
fmapR _ (Fail t stk msg) = Fail t stk msg
fmapR f (Partial k) = Partial (fmapR f . k)
fmapR f (Done t r) = Done t (f r)
instance Functor (IResult t) where
fmap = fmapR
newtype Input t = I {unI :: t} deriving (Monoid)
newtype Added t = A {unA :: t} deriving (Monoid)
newtype Parser t a = Parser {
runParser :: forall r. Input t -> Added t -> More
-> Failure t r
-> Success t a r
-> IResult t r
}
type Failure t r = Input t -> Added t -> More -> [String] -> String
-> IResult t r
type Success t a r = Input t -> Added t -> More -> a -> IResult t r
data More = Complete | Incomplete
deriving (Eq, Show)
instance Monoid More where
mappend c@Complete _ = c
mappend _ m = m
mempty = Incomplete
addS :: (Monoid t) =>
Input t -> Added t -> More
-> Input t -> Added t -> More
-> (Input t -> Added t -> More -> r) -> r
addS i0 a0 m0 _i1 a1 m1 f =
let !i = i0 <> I (unA a1)
a = a0 <> a1
!m = m0 <> m1
in f i a m
bindP :: Parser t a -> (a -> Parser t b) -> Parser t b
bindP m g =
Parser $ \i0 a0 m0 kf ks -> runParser m i0 a0 m0 kf $
\i1 a1 m1 a -> runParser (g a) i1 a1 m1 kf ks
returnP :: a -> Parser t a
returnP a = Parser (\i0 a0 m0 _kf ks -> ks i0 a0 m0 a)
instance Monad (Parser t) where
return = returnP
(>>=) = bindP
fail = failDesc
noAdds :: (Monoid t) =>
Input t -> Added t -> More
-> (Input t -> Added t -> More -> r) -> r
noAdds i0 _a0 m0 f = f i0 mempty m0
plus :: (Monoid t) => Parser t a -> Parser t a -> Parser t a
plus a b = Parser $ \i0 a0 m0 kf ks ->
let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $
\ i2 a2 m2 -> runParser b i2 a2 m2 kf ks
ks' i1 a1 m1 = ks i1 (a0 <> a1) m1
in noAdds i0 a0 m0 $ \i2 a2 m2 -> runParser a i2 a2 m2 kf' ks'
instance (Monoid t) => MonadPlus (Parser t) where
mzero = failDesc "mzero"
mplus = plus
fmapP :: (a -> b) -> Parser t a -> Parser t b
fmapP p m = Parser $ \i0 a0 m0 f k ->
runParser m i0 a0 m0 f $ \i1 a1 s1 a -> k i1 a1 s1 (p a)
instance Functor (Parser t) where
fmap = fmapP
apP :: Parser t (a -> b) -> Parser t a -> Parser t b
apP d e = do
b <- d
a <- e
return (b a)
instance Applicative (Parser t) where
pure = returnP
(<*>) = apP
#if MIN_VERSION_base(4,2,0)
(*>) = (>>)
x <* y = x >>= \a -> y >> return a
#endif
instance (Monoid t) => Monoid (Parser t a) where
mempty = failDesc "mempty"
mappend = plus
instance (Monoid t) => Alternative (Parser t) where
empty = failDesc "empty"
(<|>) = plus
#if MIN_VERSION_base(4,2,0)
many v = many_v
where many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
some v = some_v
where
many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
#endif
failDesc :: String -> Parser t a
failDesc err = Parser (\i0 a0 m0 kf _ks -> kf i0 a0 m0 [] msg)
where msg = "Failed reading: " ++ err
(<>) :: (Monoid m) => m -> m -> m
(<>) = mappend
class Monoid c => Chunk c where
type ChunkElem c
nullChunk :: c -> Bool
unsafeChunkHead :: c -> ChunkElem c
unsafeChunkTail :: c -> c
chunkLengthAtLeast :: c -> Int -> Bool
chunkElemToChar :: c -> ChunkElem c -> Char
instance Chunk ByteString where
type ChunkElem ByteString = Word8
nullChunk = BS.null
unsafeChunkHead = BS.unsafeHead
unsafeChunkTail = BS.unsafeTail
chunkLengthAtLeast bs n = BS.length bs >= n
chunkElemToChar = const w2c
instance Chunk Text where
type ChunkElem Text = Char
nullChunk = T.null
unsafeChunkHead = T.unsafeHead
unsafeChunkTail = T.unsafeTail
chunkLengthAtLeast t n = T.lengthWord16 t `quot` 2 >= n || T.length t >= n
chunkElemToChar = const id