module Data.JustParse.Internal (
    Stream (..),
    Parser (..),
    Result (..),
    isDone,
    isPartial,
    toPartial,
    finalize,
    extend,
    streamAppend
) where
import Prelude hiding ( length )
import Control.Monad ( MonadPlus, mzero, mplus, (>=>), ap )
import Control.Applicative ( Alternative, Applicative, pure, (<*>), empty, (<|>) )
import Data.Monoid ( Monoid, mempty, mappend )
import Data.List ( intercalate )
class (Eq s, Monoid s) => Stream s t | s -> t where
    
    
    
    uncons :: Stream s t => s -> Maybe (t, s)
    
    
    
    
    length :: Stream s t => s -> Int
    length s = 
        case uncons s of
            Nothing -> 0
            Just (x, xs) -> 1 + length xs
newtype Parser s a = 
    Parser { 
        parse :: Maybe s -> [Result s a]
    }
instance Stream s t => Monoid (Parser s a) where
    mempty = mzero
    mappend = mplus
instance Functor (Parser s) where
    fmap f (Parser p) = Parser $ map (fmap f) . p 
instance Applicative (Parser s) where
    pure = return 
    (<*>) = ap
instance Stream s t => Alternative (Parser s) where
    empty = mzero
    (<|>) = mplus
instance Monad (Parser s) where
    return v = Parser $ \s -> [Done v s] 
    (Parser p) >>= f = Parser $ p >=> g
        where
            g (Done a s) = parse (f a) s 
            g (Partial p) = [Partial $ p >=> g] 
instance Stream s t => MonadPlus (Parser s) where
    mzero = Parser $ const []
    mplus a b = Parser $ \s ->
        let
            g [] = parse b s
            g xs 
                | any isDone xs = xs
                | otherwise = [Partial $ \s' -> 
                    
                    case s' of
                        
                        Nothing -> 
                            case finalize (parse a s) of
                                
                                [] -> finalize (parse b s)
                                
                                r -> r
                        
                        _ -> parse (mplus a b) (streamAppend s s')]
        in
            g (parse a s) 
data Result s a 
    
    
    
    
    =
    Partial {
        continue    :: Maybe s -> [Result s a]
    } |
    
    
    Done {
        value       :: a,
        leftover    :: Maybe s
    } 
isDone :: Result s a -> Bool
isDone (Done _ _) = True
isDone _ = False
isPartial :: Result s a -> Bool
isPartial (Partial _) = True
isPartial _ = False
toPartial :: Parser s a -> [Result s a]
toPartial (Parser p) = [Partial p]
instance Functor (Result s) where
    fmap f (Partial p) = Partial $ map (fmap f) . p
    fmap f (Done a s) = Done (f a) s
instance Show a => Show (Result s a) where
    show (Partial _) = "Partial"
    show (Done a _) = show a
finalize :: (Eq s, Monoid s) => [Result s a] -> [Result s a]
finalize = extend Nothing
extend :: (Eq s, Monoid s) => Maybe s -> [Result s a] -> [Result s a]
extend s rs = rs >>= g 
    where
        g (Partial p) = p s
        g (Done a s') = [Done a (streamAppend s' s)]
streamAppend :: (Eq s, Monoid s) => Maybe s -> Maybe s -> Maybe s
streamAppend Nothing _ = Nothing 
streamAppend (Just s) Nothing = if s == mempty then Nothing else Just s 
streamAppend s s' = mappend s s'