@@ -20,6 +20,9 @@ module Parsing
2020 , fail
2121 , failWithPosition
2222 , region
23+ , liftMaybe
24+ , liftEither
25+ , liftExceptT
2326 , ParseState (..)
2427 , stateParserT
2528 , getParserT
@@ -33,6 +36,7 @@ import Control.Alt (class Alt)
3336import Control.Apply (lift2 )
3437import Control.Lazy (class Lazy )
3538import Control.Monad.Error.Class (class MonadError , class MonadThrow , catchError , throwError )
39+ import Control.Monad.Except (ExceptT , runExceptT )
3640import Control.Monad.Reader.Class (class MonadAsk , class MonadReader , ask , local )
3741import Control.Monad.Rec.Class (class MonadRec , Step (..), tailRecM )
3842import Control.Monad.State.Class (class MonadState , state )
@@ -43,6 +47,7 @@ import Data.Function.Uncurried (Fn2, Fn5, mkFn2, mkFn3, mkFn5, runFn2, runFn3, r
4347import Data.Generic.Rep (class Generic )
4448import Data.Identity (Identity )
4549import Data.Lazy as Lazy
50+ import Data.Maybe (Maybe (..))
4651import Data.Newtype (unwrap )
4752import Data.Show.Generic (genericShow )
4853import Data.Tuple (Tuple (..), fst )
@@ -467,4 +472,61 @@ instance Ord Position where
467472-- |
468473-- | `{ index: 0, line: 1, column: 1 }`
469474initialPos :: Position
470- initialPos = Position { index: 0 , line: 1 , column: 1 }
475+ initialPos = Position { index: 0 , line: 1 , column: 1 }
476+
477+ -- | Lift a `Maybe a` computation into a `ParserT`, with a note for
478+ -- | the `ParseError` message in case of `Nothing`.
479+ -- |
480+ -- | Consumes no parsing input, does not change the parser state at all.
481+ -- | If the `Maybe` computation is `Nothing`, then this will `fail` in the
482+ -- | `ParserT` monad with the given error message `String` at the current input
483+ -- | `Position`.
484+ -- |
485+ -- | This is a “validation” function, for when we want to produce some
486+ -- | data from the parsing input or fail at the current
487+ -- | parsing position if that’s impossible.
488+ -- |
489+ -- | For example, parse an integer
490+ -- | [`BoundedEnum`](https://pursuit.purescript.org/packages/purescript-enums/docs/Data.Enum#t:BoundedEnum)
491+ -- | code and validate it by turning it
492+ -- | into a `MyEnum`. Use `tryRethrow` to position the parse error at the
493+ -- | beginning of the integer in the input `String` if the `toEnum` fails.
494+ -- |
495+ -- | ```
496+ -- | runParser "3" do
497+ -- | myenum :: MyEnum <- tryRethrow do
498+ -- | x <- intDecimal
499+ -- | liftMaybe (\_ -> "Bad MyEnum " <> show x) $ toEnum x
500+ -- | ```
501+ liftMaybe :: forall s m a . Monad m => (Unit -> String ) -> Maybe a -> ParserT s m a
502+ liftMaybe message f = case f of
503+ Nothing -> fail (message unit)
504+ Just x -> pure x
505+
506+ -- | Lift an `Either String a` computation into a `ParserT`.
507+ -- |
508+ -- | Consumes no parsing input, does not change the parser state at all.
509+ -- | If the `Either` computation is `Left String`, then this will `fail` in the
510+ -- | `ParserT` monad at the current input `Position`.
511+ -- |
512+ -- | This is a “validation” function, for when we want to produce some
513+ -- | data from the parsing input or fail at the current
514+ -- | parsing position if that’s impossible.
515+ liftEither :: forall s m a . Monad m => Either String a -> ParserT s m a
516+ liftEither f = case f of
517+ Left err -> fail err
518+ Right x -> pure x
519+
520+ -- | Lift an `ExceptT String m a` computation into a `ParserT`.
521+ -- |
522+ -- | Consumes no parsing input, does not change the parser state at all.
523+ -- | If the `ExceptT` computation is `Left String`, then this will `fail` in the
524+ -- | `ParserT` monad at the current input `Position`.
525+ -- |
526+ -- | This is a “validation” function, for when we want to produce some
527+ -- | data from the parsing input or fail at the current
528+ -- | parsing position if that’s impossible.
529+ liftExceptT :: forall s m a . (Monad m ) => ExceptT String m a -> ParserT s m a
530+ liftExceptT f = lift (runExceptT f) >>= case _ of
531+ Left err -> fail err
532+ Right x -> pure x
0 commit comments