content: {-# LANGUAGE CPP #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE TypeFamilies #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Text.Parser.LookAhead
  -- Copyright   :  (c) Edward Kmett 2011-2013
  -- License     :  BSD3
  --
  -- Maintainer  :  ekmett@gmail.com
  -- Stability   :  experimental
  -- Portability :  non-portable
  --
  -- Parsers that can 'lookAhead'.
  -----------------------------------------------------------------------------
  module Text.Parser.LookAhead
    (
    -- * Parsing Combinators
      LookAheadParsing(..)
    ) where
  
  import Control.Monad (MonadPlus(..))
  import Control.Monad.Trans.State.Lazy as Lazy
  import Control.Monad.Trans.State.Strict as Strict
  import Control.Monad.Trans.Writer.Lazy as Lazy
  import Control.Monad.Trans.Writer.Strict as Strict
  import Control.Monad.Trans.RWS.Lazy as Lazy
  import Control.Monad.Trans.RWS.Strict as Strict
  import Control.Monad.Trans.Reader
  import Control.Monad.Trans.Identity
  import qualified Text.ParserCombinators.ReadP as ReadP
  import Text.Parser.Combinators
  
  #ifdef MIN_VERSION_parsec
  import qualified Text.Parsec as Parsec
  #endif
  
  #ifdef MIN_VERSION_attoparsec
  import qualified Data.Attoparsec.Types as Att
  import qualified Data.Attoparsec.Combinator as Att
  #endif
  
  #ifdef MIN_VERSION_binary
  import qualified Data.Binary.Get as B
  #endif
  
  -- | Additional functionality needed to describe parsers independent of input type.
  class Parsing m => LookAheadParsing m where
    -- | @lookAhead p@ parses @p@ without consuming any input.
    lookAhead :: m a -> m a
  
  instance (LookAheadParsing m, MonadPlus m) => LookAheadParsing (Lazy.StateT s m) where
    lookAhead (Lazy.StateT m) = Lazy.StateT $ lookAhead . m
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, MonadPlus m) => LookAheadParsing (Strict.StateT s m) where
    lookAhead (Strict.StateT m) = Strict.StateT $ lookAhead . m
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, MonadPlus m) => LookAheadParsing (ReaderT e m) where
    lookAhead (ReaderT m) = ReaderT $ lookAhead . m
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Strict.WriterT w m) where
    lookAhead (Strict.WriterT m) = Strict.WriterT $ lookAhead m
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Lazy.WriterT w m) where
    lookAhead (Lazy.WriterT m) = Lazy.WriterT $ lookAhead m
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Lazy.RWST r w s m) where
    lookAhead (Lazy.RWST m) = Lazy.RWST $ \r s -> lookAhead (m r s)
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, MonadPlus m, Monoid w) => LookAheadParsing (Strict.RWST r w s m) where
    lookAhead (Strict.RWST m) = Strict.RWST $ \r s -> lookAhead (m r s)
    {-# INLINE lookAhead #-}
  
  instance (LookAheadParsing m, Monad m) => LookAheadParsing (IdentityT m) where
    lookAhead = IdentityT . lookAhead . runIdentityT
    {-# INLINE lookAhead #-}
  
  #ifdef MIN_VERSION_parsec
  instance (Parsec.Stream s m t, Show t) => LookAheadParsing (Parsec.ParsecT s u m) where
    lookAhead = Parsec.lookAhead
  #endif
  
  #ifdef MIN_VERSION_attoparsec
  instance Att.Chunk i => LookAheadParsing (Att.Parser i) where
    lookAhead = Att.lookAhead
  #endif
  
  #ifdef MIN_VERSION_binary
  instance LookAheadParsing B.Get where
    lookAhead = B.lookAhead
  #endif
  
  instance LookAheadParsing ReadP.ReadP where
    lookAhead p = ReadP.look >>= \s ->
                  ReadP.choice $ map (return . fst) $ ReadP.readP_to_S p s
  