trifecta-0.29: Text/Trifecta/Parser/Class.hs
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances, FlexibleInstances, FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : Text.Trifecta.Parser.Class
-- Copyright : (c) Edward Kmett 2011
-- License : BSD3
--
-- Maintainer : ekmett@gmail.com
-- Stability : experimental
-- Portability : non-portable
--
-----------------------------------------------------------------------------
module Text.Trifecta.Parser.Class
( MonadParser(..)
, satisfyAscii
, restOfLine
, (<?>)
, skipping
, slicedWith
, sliced
, rend
) where
import Control.Applicative
import Control.Monad (MonadPlus(..))
import Control.Monad.Trans.Class
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 Data.Monoid
import Data.Word
-- import Control.Monad.Trans.Maybe.Strict as Strict
-- import Control.Monad.Trans.Either.Strict as Strict
import Data.ByteString as Strict
import Data.ByteString.Internal (w2c)
import Data.Semigroup
import Data.Set as Set
import Text.Trifecta.Rope.Delta
import Text.Trifecta.Rope.Prim
import Text.Trifecta.Parser.It
import Text.Trifecta.Diagnostic.Rendering.Prim
infix 0 <?>
class ( Alternative m, MonadPlus m) => MonadParser m where
-- non-committal actions
try :: m a -> m a
labels :: m a -> Set String -> m a
liftIt :: It Rope a -> m a
mark :: m Delta
unexpected :: MonadParser m => String -> m a
line :: m ByteString
skipMany :: m a -> m ()
skipMany p = () <$ many p
-- actions that definitely commit
release :: Delta -> m ()
satisfy :: (Char -> Bool) -> m Char
satisfy8 :: (Word8 -> Bool) -> m Word8
instance MonadParser m => MonadParser (Lazy.StateT s m) where
try (Lazy.StateT m) = Lazy.StateT $ try . m
labels (Lazy.StateT m) ss = Lazy.StateT $ \s -> labels (m s) ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance MonadParser m => MonadParser (Strict.StateT s m) where
try (Strict.StateT m) = Strict.StateT $ try . m
labels (Strict.StateT m) ss = Strict.StateT $ \s -> labels (m s) ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance MonadParser m => MonadParser (ReaderT e m) where
try (ReaderT m) = ReaderT $ try . m
labels (ReaderT m) ss = ReaderT $ \s -> labels (m s) ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance (MonadParser m, Monoid w) => MonadParser (Strict.WriterT w m) where
try (Strict.WriterT m) = Strict.WriterT $ try m
labels (Strict.WriterT m) ss = Strict.WriterT $ labels m ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance (MonadParser m, Monoid w) => MonadParser (Lazy.WriterT w m) where
try (Lazy.WriterT m) = Lazy.WriterT $ try m
labels (Lazy.WriterT m) ss = Lazy.WriterT $ labels m ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance (MonadParser m, Monoid w) => MonadParser (Lazy.RWST r w s m) where
try (Lazy.RWST m) = Lazy.RWST $ \r s -> try (m r s)
labels (Lazy.RWST m) ss = Lazy.RWST $ \r s -> labels (m r s) ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance (MonadParser m, Monoid w) => MonadParser (Strict.RWST r w s m) where
try (Strict.RWST m) = Strict.RWST $ \r s -> try (m r s)
labels (Strict.RWST m) ss = Strict.RWST $ \r s -> labels (m r s) ss
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
instance MonadParser m => MonadParser (IdentityT m) where
try (IdentityT m) = IdentityT $ try m
labels (IdentityT m) = IdentityT . labels m
line = lift line
liftIt = lift . liftIt
mark = lift mark
release = lift . release
unexpected = lift . unexpected
satisfy = lift . satisfy
satisfy8 = lift . satisfy8
satisfyAscii :: MonadParser m => (Char -> Bool) -> m Char
satisfyAscii p = w2c <$> satisfy8 (\w -> w <= 0x7f && p (w2c w))
{-# INLINE satisfyAscii #-}
-- instance (MonadParser m, Monoid w) => MonadParser (MaybeT m) where
-- instance (Error e, MonadParser m, Monoid w) => MonadParser (ErrorT e m) where
-- useful when we've just recognized something out of band using access to the current line
skipping :: MonadParser m => Delta -> m ()
skipping d = do
m <- mark
release (m <> d)
{-# INLINE skipping #-}
-- | grab the remainder of the current line
restOfLine :: MonadParser m => m ByteString
restOfLine = do
m <- mark
Strict.drop (columnByte m) <$> line
{-# INLINE restOfLine #-}
-- | label a parser with a name
(<?>) :: MonadParser m => m a -> String -> m a
p <?> msg = labels p (Set.singleton msg)
-- | run a parser, grabbing all of the text between its start and end points
slicedWith :: MonadParser m => (a -> Strict.ByteString -> r) -> m a -> m r
slicedWith f pa = do
m <- mark
a <- pa
r <- mark
liftIt $ f a <$> sliceIt m r
{-# INLINE slicedWith #-}
-- | run a parser, grabbing all of the text between its start and end points and discarding the original result
sliced :: MonadParser m => m a -> m ByteString
sliced = slicedWith (\_ bs -> bs)
rend :: MonadParser m => m Rendering
rend = rendering <$> mark <*> line
{-# INLINE rend #-}