{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, OverloadedStrings,
Rank2Types, RecordWildCards, TypeFamilies #-}
module Data.Attoparsec.Internal.Types
(
Parser(..)
, State
, Failure
, Success
, Pos(..)
, IResult(..)
, More(..)
, (<>)
, Chunk(..)
) where
import Control.Applicative as App (Applicative(..), (<$>))
import Control.Applicative (Alternative(..))
import Control.DeepSeq (NFData(rnf))
import Control.Monad (MonadPlus(..))
import qualified Control.Monad.Fail as Fail (MonadFail(..))
import Data.Monoid as Mon (Monoid(..))
import Data.Semigroup (Semigroup(..))
import Data.Word (Word8)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.ByteString.Internal (w2c)
import Prelude hiding (getChar, succ)
import qualified Data.Attoparsec.ByteString.Buffer as B
newtype Pos = Pos { fromPos :: Int }
deriving (Eq, Ord, Show, Num)
data IResult i r =
Fail i [String] String
| Partial (i -> IResult i r)
| Done i r
instance (Show i, Show r) => Show (IResult i r) where
showsPrec d ir = showParen (d > 10) $
case ir of
(Fail t stk msg) -> showString "Fail" . f t . f stk . f msg
(Partial _) -> showString "Partial _"
(Done t r) -> showString "Done" . f t . f r
where f :: Show a => a -> ShowS
f x = showChar ' ' . showsPrec 11 x
instance (NFData i, NFData r) => NFData (IResult i 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
{-# INLINE rnf #-}
instance Functor (IResult i) where
fmap _ (Fail t stk msg) = Fail t stk msg
fmap f (Partial k) = Partial (fmap f . k)
fmap f (Done t r) = Done t (f r)
newtype Parser i a = Parser {
runParser :: forall r.
State i -> Pos -> More
-> Failure i (State i) r
-> Success i (State i) a r
-> IResult i r
}
type family State i
type instance State ByteString = B.Buffer
type Failure i t r = t -> Pos -> More -> [String] -> String
-> IResult i r
type Success i t a r = t -> Pos -> More -> a -> IResult i r
data More = Complete | Incomplete
deriving (Eq, Show)
instance Semigroup More where
c@Complete <> _ = c
_ <> m = m
instance Mon.Monoid More where
mappend = (<>)
mempty = Incomplete
instance Monad (Parser i) where
fail = Fail.fail
{-# INLINE fail #-}
return = App.pure
{-# INLINE return #-}
m >>= k = Parser $ \t !pos more lose succ ->
let succ' t' !pos' more' a = runParser (k a) t' pos' more' lose succ
in runParser m t pos more lose succ'
{-# INLINE (>>=) #-}
(>>) = (*>)
{-# INLINE (>>) #-}
instance Fail.MonadFail (Parser i) where
fail err = Parser $ \t pos more lose _succ -> lose t pos more [] msg
where msg = "Failed reading: " ++ err
{-# INLINE fail #-}
plus :: Parser i a -> Parser i a -> Parser i a
plus f g = Parser $ \t pos more lose succ ->
let lose' t' _pos' more' _ctx _msg = runParser g t' pos more' lose succ
in runParser f t pos more lose' succ
instance MonadPlus (Parser i) where
mzero = fail "mzero"
{-# INLINE mzero #-}
mplus = plus
instance Functor (Parser i) where
fmap f p = Parser $ \t pos more lose succ ->
let succ' t' pos' more' a = succ t' pos' more' (f a)
in runParser p t pos more lose succ'
{-# INLINE fmap #-}
apP :: Parser i (a -> b) -> Parser i a -> Parser i b
apP d e = do
b <- d
a <- e
return (b a)
{-# INLINE apP #-}
instance Applicative (Parser i) where
pure v = Parser $ \t pos more _lose succ -> succ t pos more v
{-# INLINE pure #-}
(<*>) = apP
{-# INLINE (<*>) #-}
m *> k = m >>= \_ -> k
{-# INLINE (*>) #-}
x <* y = x >>= \a -> y >> pure a
{-# INLINE (<*) #-}
instance Semigroup (Parser i a) where
(<>) = plus
{-# INLINE (<>) #-}
instance Monoid (Parser i a) where
mempty = fail "mempty"
{-# INLINE mempty #-}
mappend = (<>)
{-# INLINE mappend #-}
instance Alternative (Parser i) where
empty = fail "empty"
{-# INLINE empty #-}
(<|>) = plus
{-# INLINE (<|>) #-}
many v = many_v
where many_v = some_v <|> pure []
some_v = (:) App.<$> v <*> many_v
{-# INLINE many #-}
some v = some_v
where
many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
{-# INLINE some #-}
class Monoid c => Chunk c where
type ChunkElem c
nullChunk :: c -> Bool
pappendChunk :: State c -> c -> State c
atBufferEnd :: c -> State c -> Pos
bufferElemAt :: c -> Pos -> State c -> Maybe (ChunkElem c, Int)
chunkElemToChar :: c -> ChunkElem c -> Char
instance Chunk ByteString where
type ChunkElem ByteString = Word8
nullChunk = BS.null
{-# INLINE nullChunk #-}
pappendChunk = B.pappend
{-# INLINE pappendChunk #-}
atBufferEnd _ = Pos . B.length
{-# INLINE atBufferEnd #-}
bufferElemAt _ (Pos i) buf
| i < B.length buf = Just (B.unsafeIndex buf i, 1)
| otherwise = Nothing
{-# INLINE bufferElemAt #-}
chunkElemToChar _ = w2c
{-# INLINE chunkElemToChar #-}