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 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
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
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 Semigroup More where
c@Complete <> _ = c
_ <> m = m
instance Mon.Monoid More where
mappend = (<>)
mempty = Incomplete
instance Monad (Parser i) where
fail = Fail.fail
return = App.pure
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'
(>>) = (*>)
instance Fail.MonadFail (Parser i) where
fail err = Parser $ \t pos more lose _succ -> lose t pos more [] msg
where msg = "Failed reading: " ++ err
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"
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'
apP :: Parser i (a -> b) -> Parser i a -> Parser i b
apP d e = do
b <- d
a <- e
return (b a)
instance Applicative (Parser i) where
pure v = Parser $ \t pos more _lose succ -> succ t pos more v
(<*>) = apP
m *> k = m >>= \_ -> k
x <* y = x >>= \a -> y >> pure a
instance Semigroup (Parser i a) where
(<>) = plus
instance Monoid (Parser i a) where
mempty = fail "mempty"
mappend = (<>)
instance Alternative (Parser i) where
empty = fail "empty"
(<|>) = plus
many v = many_v
where many_v = some_v <|> pure []
some_v = (:) App.<$> v <*> many_v
some v = some_v
where
many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
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
pappendChunk = B.pappend
atBufferEnd _ = Pos . B.length
bufferElemAt _ (Pos i) buf
| i < B.length buf = Just (B.unsafeIndex buf i, 1)
| otherwise = Nothing
chunkElemToChar _ = w2c
instance Chunk Text where
type ChunkElem Text = Char
nullChunk = Text.null
pappendChunk = T.pappend
atBufferEnd _ = Pos . T.length
bufferElemAt _ (Pos i) buf
| i < T.length buf = let Iter c l = T.iter buf i in Just (c, l)
| otherwise = Nothing
chunkElemToChar _ = id