{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Text.Parser.Deterministic where
import Control.Applicative (Applicative ((<*>), pure), Alternative ((<|>), many, some), liftA2, optional)
import Control.Arrow (first)
import Control.Monad (MonadPlus, void)
import Control.Monad.Trans.Identity (IdentityT(..))
import Control.Monad.Trans.Reader (ReaderT(..), mapReaderT)
import qualified Control.Monad.Trans.Writer.Lazy as Lazy (WriterT(WriterT))
import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT(WriterT))
import qualified Control.Monad.Trans.State.Lazy as Lazy (StateT(StateT))
import qualified Control.Monad.Trans.State.Strict as Strict (StateT(StateT))
import qualified Control.Monad.Trans.RWS.Lazy as Lazy (RWST(RWST))
import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST(RWST))
import Data.Functor ((<$>))
import qualified Data.List as List
import Data.Monoid (Monoid, mappend, mempty)
import Data.String (IsString (fromString))
import Text.ParserCombinators.ReadP (ReadP)
import qualified Text.ParserCombinators.ReadP as ReadP
import Text.Parser.Char (CharParsing)
import Text.Parser.Combinators (Parsing, count, eof, notFollowedBy, try, unexpected)
import Text.Parser.LookAhead (LookAheadParsing, lookAhead)
import qualified Text.Parser.Char as Char
import Text.Parser.Internal (mapLazyWriterT, mapStrictWriterT,
mapLazyStateT, mapStrictStateT,
mapLazyRWST, mapStrictRWST)
import Text.Parser.Wrapper (Lazy(..), Strict(..))
#ifdef MIN_VERSION_attoparsec
import Data.ByteString (ByteString)
import Data.Text (Text)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as ByteString.Char8
import qualified Data.Text as Text
import qualified Data.Attoparsec.ByteString as Attoparsec
import qualified Data.Attoparsec.ByteString.Char8 as Attoparsec.Char8
import qualified Data.Attoparsec.Text as Attoparsec.Text
#endif
#ifdef MIN_VERSION_binary
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as Lazy
import qualified Data.Binary.Get as Binary
#endif
class Parsing m => DeterministicParsing m where
infixl 3 <<|>
(<<|>) :: m a -> m a -> m a
takeOptional :: m a -> m (Maybe a)
takeMany :: m a -> m [a]
takeSome :: m a -> m [a]
concatAll :: Monoid a => m a -> m a
skipAll :: m a -> m ()
p <<|> q = try p <|> notFollowedBy (void p) *> q
takeOptional p = Just <$> p <<|> pure Nothing
takeMany p = many p <* notFollowedBy (void p)
takeSome p = some p <* notFollowedBy (void p)
concatAll p = go
where go = liftA2 mappend p go <<|> pure mempty
skipAll p = p *> skipAll p <<|> pure ()
instance DeterministicParsing ReadP where
(<<|>) = (ReadP.<++)
instance (Monad m, DeterministicParsing m) => DeterministicParsing (IdentityT m) where
IdentityT p <<|> IdentityT q = IdentityT (p <<|> q)
takeOptional (IdentityT p) = IdentityT (takeOptional p)
takeMany (IdentityT p) = IdentityT (takeMany p)
takeSome (IdentityT p) = IdentityT (takeSome p)
concatAll (IdentityT p) = IdentityT (concatAll p)
skipAll (IdentityT p) = IdentityT (skipAll p)
instance (MonadPlus m, DeterministicParsing m) => DeterministicParsing (ReaderT e m) where
ReaderT p <<|> ReaderT q = ReaderT (\a-> p a <<|> q a)
takeOptional = mapReaderT takeOptional
takeMany = mapReaderT takeMany
takeSome = mapReaderT takeSome
concatAll = mapReaderT concatAll
skipAll = mapReaderT skipAll
instance (MonadPlus m, DeterministicParsing m, Monoid w) => DeterministicParsing (Lazy.WriterT w m) where
Lazy.WriterT p <<|> Lazy.WriterT q = Lazy.WriterT (p <<|> q)
takeOptional = mapLazyWriterT takeOptional
takeMany = mapLazyWriterT takeMany
takeSome = mapLazyWriterT takeSome
concatAll = mapLazyWriterT concatAll
skipAll = mapLazyWriterT skipAll
instance (MonadPlus m, DeterministicParsing m, Monoid w) => DeterministicParsing (Strict.WriterT w m) where
Strict.WriterT p <<|> Strict.WriterT q = Strict.WriterT (p <<|> q)
takeOptional = mapStrictWriterT takeOptional
takeMany = mapStrictWriterT takeMany
takeSome = mapStrictWriterT takeSome
concatAll = mapStrictWriterT concatAll
skipAll = mapStrictWriterT skipAll
instance (MonadPlus m, DeterministicParsing m, Monoid w) => DeterministicParsing (Lazy.StateT w m) where
Lazy.StateT p <<|> Lazy.StateT q = Lazy.StateT (\s-> p s <<|> q s)
takeOptional = mapLazyStateT takeOptional
takeMany = mapLazyStateT takeMany
takeSome = mapLazyStateT takeSome
concatAll = mapLazyStateT concatAll
skipAll = mapLazyStateT skipAll
instance (MonadPlus m, DeterministicParsing m, Monoid w) => DeterministicParsing (Strict.StateT w m) where
Strict.StateT p <<|> Strict.StateT q = Strict.StateT (\s-> p s <<|> q s)
takeOptional = mapStrictStateT takeOptional
takeMany = mapStrictStateT takeMany
takeSome = mapStrictStateT takeSome
concatAll = mapStrictStateT concatAll
skipAll = mapStrictStateT skipAll
instance (MonadPlus m, DeterministicParsing m, Monoid w) => DeterministicParsing (Lazy.RWST r w s m) where
Lazy.RWST p <<|> Lazy.RWST q = Lazy.RWST (\r s-> p r s <<|> q r s)
takeOptional = mapLazyRWST takeOptional
takeMany = mapLazyRWST takeMany
takeSome = mapLazyRWST takeSome
concatAll = mapLazyRWST concatAll
skipAll = mapLazyRWST skipAll
instance (MonadPlus m, DeterministicParsing m, Monoid w) => DeterministicParsing (Strict.RWST r w s m) where
Strict.RWST p <<|> Strict.RWST q = Strict.RWST (\r s-> p r s <<|> q r s)
takeOptional = mapStrictRWST takeOptional
takeMany = mapStrictRWST takeMany
takeSome = mapStrictRWST takeSome
concatAll = mapStrictRWST concatAll
skipAll = mapStrictRWST skipAll
#ifdef MIN_VERSION_attoparsec
instance DeterministicParsing Attoparsec.Parser where
(<<|>) = (<|>)
takeOptional = optional
takeMany = many
takeSome = some
skipAll = Attoparsec.skipMany
instance DeterministicParsing Attoparsec.Text.Parser where
(<<|>) = (<|>)
takeOptional = optional
takeMany = many
takeSome = some
skipAll = Attoparsec.Text.skipMany
#endif
#ifdef MIN_VERSION_binary
instance DeterministicParsing (Lazy Binary.Get) where
(<<|>) = (<|>)
takeOptional = optional
takeMany = many
takeSome = some
instance DeterministicParsing (Strict Binary.Get) where
(<<|>) = (<|>)
takeOptional = optional
takeMany = many
takeSome = some
#endif