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