simple-parser-0.2.2: src/SimpleParser/Parser.hs
-- | 'ParserT' is the core monad transformer for parsing.
module SimpleParser.Parser
( ParserT (..)
, Parser
, runParser
, filterParser
, reflectParser
, branchParser
, suppressParser
, isolateParser
, defaultParser
, optionalParser
, silenceParser
, greedyStarParser
, greedyStarParser_
, greedyPlusParser
, greedyPlusParser_
, lookAheadParser
) where
import Control.Applicative (Alternative (..), liftA2)
import Control.Monad (MonadPlus (..), ap, (>=>))
import Control.Monad.Except (MonadError (..))
import Control.Monad.Identity (Identity (..))
import Control.Monad.Morph (MFunctor (..))
import Control.Monad.State (MonadState (..))
import Control.Monad.Trans (MonadTrans (..))
import Data.Foldable (toList)
import ListT (ListT (..))
import qualified ListT
import SimpleParser.Result (ParseResult (..), ParseValue (..))
-- | A 'ParserT' is a state/error/list transformer useful for parsing.
-- All MTL instances are for this transformer only. If, for example, your effect
-- has its own 'MonadState' instance, you'll have to use 'lift get' instead of 'get'.
newtype ParserT e s m a = ParserT { runParserT :: s -> ListT m (ParseResult e s a) }
deriving (Functor)
-- | Use 'Parser' if you have no need for other monadic effects.
type Parser e s a = ParserT e s Identity a
instance Monad m => Applicative (ParserT e s m) where
pure a = ParserT (pure . ParseResult (ParseSuccess a))
(<*>) = ap
instance Monad m => Monad (ParserT e s m) where
return = pure
parser >>= f = ParserT (runParserT parser >=> go) where
go (ParseResult v t) =
case v of
ParseError e -> pure (ParseResult (ParseError e) t)
ParseSuccess a -> runParserT (f a) t
instance Monad m => Alternative (ParserT e s m) where
empty = ParserT (const empty)
first <|> second = ParserT (\s -> runParserT first s <|> runParserT second s)
instance Monad m => MonadPlus (ParserT e s m) where
mzero = empty
mplus = (<|>)
instance Monad m => MonadError e (ParserT e s m) where
throwError e = ParserT (pure . ParseResult (ParseError e))
-- TODO(ejconlon) Implement directly by unwrapping?
catchError parser handler = do
r <- reflectParser parser
case r of
ParseError e -> handler e
ParseSuccess a -> pure a
instance Monad m => MonadState s (ParserT e s m) where
get = ParserT (\s -> pure (ParseResult (ParseSuccess s) s))
put t = ParserT (const (pure (ParseResult (ParseSuccess ()) t)))
state f = ParserT (\s -> let (a, t) = f s in pure (ParseResult (ParseSuccess a) t))
instance MonadTrans (ParserT e s) where
lift ma = ParserT (\s -> lift (fmap (\a -> ParseResult (ParseSuccess a) s) ma))
instance MFunctor (ParserT e s) where
hoist trans (ParserT f) = ParserT (hoist trans . f)
-- | Runs a non-effectful parser from an inital state and collects all results.
runParser :: Parser e s a -> s -> [ParseResult e s a]
runParser m s = runIdentity (ListT.toList (runParserT m s))
-- | Filters parse results
filterParser :: Monad m => (a -> Bool) -> ParserT e s m a -> ParserT e s m a
filterParser f parser = ParserT (ListT . go . runParserT parser) where
go listt = do
m <- ListT.uncons listt
case m of
Nothing -> pure Nothing
Just (r@(ParseResult v _), rest) ->
case v of
ParseSuccess a | not (f a) -> go rest
_ -> pure (Just (r, ListT (go rest)))
-- | A kind of "catch" that returns all results, success and failure.
reflectParser :: Monad m => ParserT e s m a -> ParserT e s m (ParseValue e a)
reflectParser parser = ParserT (ListT . go . runParserT parser) where
go listt = do
m <- ListT.uncons listt
case m of
Nothing -> pure Nothing
Just (ParseResult v t, rest) ->
pure (Just (ParseResult (ParseSuccess v) t, ListT (go rest)))
-- | Combines the results of many parsers.
-- Equvalent to 'asum'.
branchParser :: (Foldable f, Monad m) => f (ParserT e s m a) -> ParserT e s m a
branchParser = start . toList where
start ps =
case ps of
[] -> empty
q:qs -> ParserT (\s -> ListT (run s q qs))
run s q qs = do
m <- ListT.uncons (runParserT q s)
case m of
Nothing ->
case qs of
[] -> pure Nothing
r:rs -> run s r rs
Just (a, rest) -> pure (Just (a, rest))
gatherParser :: Monad m => Bool -> ParserT e s m a -> ParserT e s m a
gatherParser single parser = ParserT (ListT . go [] . runParserT parser) where
go !acc listt = do
m <- ListT.uncons listt
case m of
Nothing -> returnErr (reverse acc)
Just (r@(ParseResult v _), rest) ->
case v of
ParseError _ -> go (r:acc) rest
ParseSuccess _ ->
let t = if single then empty else ListT (filterOk rest)
in pure (Just (r, t))
returnErr racc =
case racc of
[] -> pure Nothing
r:rs -> pure (Just (r, ListT (returnErr rs)))
filterOk listt = do
m <- ListT.uncons listt
case m of
Nothing -> pure Nothing
Just (r@(ParseResult v _), rest) ->
let nextListt = filterOk rest
in case v of
ParseError _ -> nextListt
ParseSuccess _ -> pure (Just (r, ListT nextListt))
-- | If the parse results in ANY successes, keep only those. Otherwise return all failures.
-- This may block indefinitely as it awaits either the end of the parser or its first success.
-- See 'isolateParser' if you want only one success.
suppressParser :: Monad m => ParserT e s m a -> ParserT e s m a
suppressParser = gatherParser False
-- | If the parse results in ANY successes, keep only THE FIRST. Otherwise return all failures.
-- This may block indefinitely as it awaits either the end of the parser or its first success.
-- See 'suppressParser' if you want all successes.
isolateParser :: Monad m => ParserT e s m a -> ParserT e s m a
isolateParser = gatherParser True
-- | If the parser yields no results (success or failure), yield a given value.
defaultParser :: Monad m => a -> ParserT e s m a -> ParserT e s m a
defaultParser def parser = ParserT (\s -> ListT (go s (runParserT parser s))) where
go s listt = do
m <- ListT.uncons listt
case m of
Nothing -> pure (Just (ParseResult (ParseSuccess def) s, empty))
Just _ -> pure m
-- | A parser that yields 'Nothing' if there are no results (success or failure),
-- otherwise wrapping successes in 'Just'.
optionalParser :: Monad m => ParserT e s m a -> ParserT e s m (Maybe a)
optionalParser parser = defaultParser Nothing (fmap Just parser)
-- | Removes all failures from the parse results.
-- Equivalent to 'catchError (const empty)'.
silenceParser :: Monad m => ParserT e s m a -> ParserT e s m a
silenceParser parser = ParserT (ListT . go . runParserT parser) where
go listt = do
m <- ListT.uncons listt
case m of
Nothing -> pure Nothing
Just (r@(ParseResult v _), rest) ->
let nextListt = go rest
in case v of
ParseError _ -> nextListt
ParseSuccess _ -> pure (Just (r, ListT nextListt))
-- | Yields the LONGEST string of 0 or more successes of the given parser (and passes through failures).
greedyStarParser :: Monad m => ParserT e s m a -> ParserT e s m [a]
greedyStarParser parser = go [] where
opt = optionalParser parser
go !acc = do
res <- opt
case res of
Nothing -> pure (reverse acc)
Just a -> go (a:acc)
-- | Same as 'greedyStarParser' but discards the result.
greedyStarParser_ :: Monad m => ParserT e s m a -> ParserT e s m ()
greedyStarParser_ parser = go where
opt = optionalParser parser
go = do
res <- opt
case res of
Nothing -> pure ()
Just _ -> go
-- | Yields the LONGEST string of 1 or more successes of the given parser (and passes through failures).
greedyPlusParser :: Monad m => ParserT e s m a -> ParserT e s m [a]
greedyPlusParser parser = liftA2 (:) parser (greedyStarParser parser)
-- | Same as 'greedyPlusParser' but discards the result.
greedyPlusParser_ :: Monad m => ParserT e s m a -> ParserT e s m ()
greedyPlusParser_ parser = parser *> greedyStarParser_ parser
-- | Yield the results of the given parser, but rewind back to the starting state.
-- Note that these results may contain errors, so you may want to stifle them with 'silenceParser', for example.
lookAheadParser :: Monad m => ParserT e s m a -> ParserT e s m a
lookAheadParser parser = do
s <- get
flip catchError (\e -> put s *> throwError e) $ do
v <- parser
put s
pure v