{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, OverloadedStrings,
Rank2Types, RecordWildCards, TypeFamilies #-}
module Data.Attoparsec.Internal.Types
(
Parser(..)
, State
, Failure
, Success
, Pos(..)
, IResult(..)
, More(..)
, (<>)
, Chunk(..)
) where
import Control.Applicative (Alternative(..), Applicative(..), (<$>))
import Control.DeepSeq (NFData(rnf))
import Control.Monad (MonadPlus(..))
import Data.Word (Word8)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.ByteString.Internal (w2c)
import Data.Monoid (Monoid(..))
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Text.Unsafe (Iter(..))
import Prelude hiding (getChar, succ)
import qualified Data.Attoparsec.ByteString.Buffer as B
import qualified Data.Attoparsec.Text.Buffer as T
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
show (Fail t stk msg) =
unwords [ "Fail", show t, show stk, show msg]
show (Partial _) = "Partial _"
show (Done t r) = unwords ["Done", show t, show r]
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 instance State Text = T.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 Monoid More where
mappend c@Complete _ = c
mappend _ m = m
mempty = Incomplete
instance Monad (Parser i) where
fail err = Parser $ \t pos more lose _succ -> lose t pos more [] msg
where msg = "Failed reading: " ++ err
{-# INLINE fail #-}
return v = Parser $ \t pos more _lose succ -> succ t pos more v
{-# 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 (>>=) #-}
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 = return
{-# INLINE pure #-}
(<*>) = apP
{-# INLINE (<*>) #-}
(*>) = (>>)
{-# INLINE (*>) #-}
x <* y = x >>= \a -> y >> return a
{-# INLINE (<*) #-}
instance Monoid (Parser i a) where
mempty = fail "mempty"
{-# INLINE mempty #-}
mappend = plus
{-# 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 = (:) <$> v <*> many_v
{-# INLINE many #-}
some v = some_v
where
many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
{-# INLINE some #-}
(<>) :: (Monoid m) => m -> m -> m
(<>) = mappend
{-# INLINE (<>) #-}
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 #-}
instance Chunk Text where
type ChunkElem Text = Char
nullChunk = Text.null
{-# INLINE nullChunk #-}
pappendChunk = T.pappend
{-# INLINE pappendChunk #-}
atBufferEnd _ = Pos . T.length
{-# INLINE atBufferEnd #-}
bufferElemAt _ (Pos i) buf
| i < T.length buf = let Iter c l = T.iter buf i in Just (c, l)
| otherwise = Nothing
{-# INLINE bufferElemAt #-}
chunkElemToChar _ = id
{-# INLINE chunkElemToChar #-}