module Tahoe.CHK.Parsing where

import qualified Data.Set as Set
import Text.Megaparsec (ErrorFancy (ErrorFail), MonadParsec, fancyFailure)

-- | Parse an integral with lower and upper value constraints.
bounded ::
    (MonadParsec e s m, Ord n, Integral n) =>
    -- | A parser for an arbitrarily large integral value.
    m Integer ->
    -- | The smallest allowed value.
    n ->
    -- | The largest allowed value.
    n ->
    -- | A parser that succeeds only for integers within the given bounds.
    m n
bounded :: m Integer -> n -> n -> m n
bounded m Integer
decimal n
low n
high = do
    -- Parse into an integer so there's no wrap-around
    Integer
v <- m Integer
decimal
    if Integer
v Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< n -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral n
low
        then Set (ErrorFancy e) -> m n
forall e s (m :: * -> *) a.
MonadParsec e s m =>
Set (ErrorFancy e) -> m a
fancyFailure (ErrorFancy e -> Set (ErrorFancy e)
forall a. a -> Set a
Set.singleton (String -> ErrorFancy e
forall e. String -> ErrorFancy e
ErrorFail String
"below minimum allowed value"))
        else
            if Integer
v Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> n -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral n
high
                then Set (ErrorFancy e) -> m n
forall e s (m :: * -> *) a.
MonadParsec e s m =>
Set (ErrorFancy e) -> m a
fancyFailure (ErrorFancy e -> Set (ErrorFancy e)
forall a. a -> Set a
Set.singleton (String -> ErrorFancy e
forall e. String -> ErrorFancy e
ErrorFail String
"above maximum allowed value"))
                else n -> m n
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Integer -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
v)