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
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
return v = Parser $ \t pos more _lose succ -> succ t pos more v
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'
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 = return
(<*>) = apP
(*>) = (>>)
x <* y = x >>= \a -> y >> return a
instance Monoid (Parser i a) where
mempty = fail "mempty"
mappend = plus
instance Alternative (Parser i) where
empty = fail "empty"
(<|>) = plus
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
(<>) :: (Monoid m) => m -> m -> m
(<>) = mappend
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