{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}
module Text.ParserCombinators.Poly.Lazy
  ( 
    Parser(P)   
  , Result(..)  
  , runParser   
    
  , next        
  , eof         
  , satisfy     
  , satisfyMsg  
  , onFail      
    
  , reparse     
    
  , module Text.ParserCombinators.Poly.Base
  , module Control.Applicative
  ) where
import Text.ParserCombinators.Poly.Base
import Text.ParserCombinators.Poly.Result
import qualified Text.ParserCombinators.Poly.Parser as P
import Control.Applicative
import qualified Control.Monad.Fail as Fail
#if __GLASGOW_HASKELL__
import Control.Exception hiding (bracket)
throwE :: String -> a
throwE msg = throw (ErrorCall msg)
#else
throwE :: String -> a
throwE msg = error msg
#endif
newtype Parser t a = P (P.Parser t a)
#ifdef __GLASGOW_HASKELL__
        deriving (Functor,Monad,Fail.MonadFail,Commitment)
#else
instance Functor (Parser t) where
    fmap f (P p) = P (fmap f p)
instance Monad (Parser t) where
    return x  = P (return x)
    fail      = Fail.fail
    (P f) >>= g = P (f >>= (\(P g')->g') . g)
instance Fail.MonadFail (Parser t) where
    fail e    = P (fail e)
instance Commitment (Parser t) where
    commit (P p)   = P (commit p)
    (P p) `adjustErr` f  = P (p `adjustErr` f)
#endif
runParser :: Parser t a -> [t] -> (a, [t])
runParser (P (P.P p)) = fromResult . p
  where
    fromResult :: Result z a -> (a, z)
    fromResult (Success z a)  =  (a, z)
    fromResult (Failure z e)  =  throwE e
    fromResult (Committed r)  =  fromResult r
instance Applicative (Parser t) where
    pure f    = return f
    
    
    
    
    (P (P.P pf)) <*> px = P (P.P (continue . pf))
      where
        continue (Success z f)  = let (x,z') = runParser px z
                                  in Success z' (f x)
        continue (Committed r)  = Committed (continue r)
        continue (Failure z e)  = Failure z e
#if defined(GLASGOW_HASKELL) && GLASGOW_HASKELL > 610
    p  <*  q  = p `discard` q
#endif
instance Alternative (Parser t) where
    empty             = fail "no parse"
    (P p) <|> (P q)   = P (p `P.onFail` q)
instance PolyParse (Parser t)
next    ::  Parser t t
next    = P P.next
eof     :: Parser t ()
eof     = P P.eof
satisfy :: (t->Bool) -> Parser t t
satisfy = P . P.satisfy
satisfyMsg :: Show t => (t->Bool) -> String -> Parser t t
satisfyMsg p s = P (P.satisfyMsg p s)
onFail  :: Parser t a -> Parser t a -> Parser t a
onFail (P a) (P b) = P (a `P.onFail` b)
reparse :: [t] -> Parser t ()
reparse = P . P.reparse