{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveFunctor #-}
module IOEnv (
IOEnv,
module MonadUtils,
failM, failWithM,
IOEnvFailure(..),
getEnv, setEnv, updEnv,
runIOEnv, unsafeInterleaveM, uninterruptibleMaskM_,
tryM, tryAllM, tryMostM, fixM,
IORef, newMutVar, readMutVar, writeMutVar, updMutVar,
atomicUpdMutVar, atomicUpdMutVar'
) where
import GhcPrelude
import DynFlags
import Exception
import Module
import Panic
import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef,
atomicModifyIORef, atomicModifyIORef' )
import System.IO.Unsafe ( unsafeInterleaveIO )
import System.IO ( fixIO )
import Control.Monad
import qualified Control.Monad.Fail as MonadFail
import MonadUtils
import Control.Applicative (Alternative(..))
newtype IOEnv env a = IOEnv (env -> IO a) deriving (a -> IOEnv env b -> IOEnv env a
(a -> b) -> IOEnv env a -> IOEnv env b
(forall a b. (a -> b) -> IOEnv env a -> IOEnv env b)
-> (forall a b. a -> IOEnv env b -> IOEnv env a)
-> Functor (IOEnv env)
forall a b. a -> IOEnv env b -> IOEnv env a
forall a b. (a -> b) -> IOEnv env a -> IOEnv env b
forall env a b. a -> IOEnv env b -> IOEnv env a
forall env a b. (a -> b) -> IOEnv env a -> IOEnv env b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> IOEnv env b -> IOEnv env a
$c<$ :: forall env a b. a -> IOEnv env b -> IOEnv env a
fmap :: (a -> b) -> IOEnv env a -> IOEnv env b
$cfmap :: forall env a b. (a -> b) -> IOEnv env a -> IOEnv env b
Functor)
unIOEnv :: IOEnv env a -> (env -> IO a)
unIOEnv :: IOEnv env a -> env -> IO a
unIOEnv (IOEnv env -> IO a
m) = env -> IO a
m
instance Monad (IOEnv m) where
>>= :: IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
(>>=) = IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
forall m a b. IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
thenM
>> :: IOEnv m a -> IOEnv m b -> IOEnv m b
(>>) = IOEnv m a -> IOEnv m b -> IOEnv m b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
(*>)
#if !MIN_VERSION_base(4,13,0)
fail = MonadFail.fail
#endif
instance MonadFail.MonadFail (IOEnv m) where
fail :: String -> IOEnv m a
fail String
_ = IOEnv m a
forall env a. IOEnv env a
failM
instance Applicative (IOEnv m) where
pure :: a -> IOEnv m a
pure = a -> IOEnv m a
forall a env. a -> IOEnv env a
returnM
IOEnv m -> IO (a -> b)
f <*> :: IOEnv m (a -> b) -> IOEnv m a -> IOEnv m b
<*> IOEnv m -> IO a
x = (m -> IO b) -> IOEnv m b
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ m
env -> m -> IO (a -> b)
f m
env IO (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m -> IO a
x m
env )
*> :: IOEnv m a -> IOEnv m b -> IOEnv m b
(*>) = IOEnv m a -> IOEnv m b -> IOEnv m b
forall m a b. IOEnv m a -> IOEnv m b -> IOEnv m b
thenM_
returnM :: a -> IOEnv env a
returnM :: a -> IOEnv env a
returnM a
a = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
_ -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a)
thenM :: IOEnv env a -> (a -> IOEnv env b) -> IOEnv env b
thenM :: IOEnv env a -> (a -> IOEnv env b) -> IOEnv env b
thenM (IOEnv env -> IO a
m) a -> IOEnv env b
f = (env -> IO b) -> IOEnv env b
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> do { a
r <- env -> IO a
m env
env ;
IOEnv env b -> env -> IO b
forall env a. IOEnv env a -> env -> IO a
unIOEnv (a -> IOEnv env b
f a
r) env
env })
thenM_ :: IOEnv env a -> IOEnv env b -> IOEnv env b
thenM_ :: IOEnv env a -> IOEnv env b -> IOEnv env b
thenM_ (IOEnv env -> IO a
m) IOEnv env b
f = (env -> IO b) -> IOEnv env b
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> do { a
_ <- env -> IO a
m env
env ; IOEnv env b -> env -> IO b
forall env a. IOEnv env a -> env -> IO a
unIOEnv IOEnv env b
f env
env })
failM :: IOEnv env a
failM :: IOEnv env a
failM = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
_ -> IOEnvFailure -> IO a
forall e a. Exception e => e -> IO a
throwIO IOEnvFailure
IOEnvFailure)
failWithM :: String -> IOEnv env a
failWithM :: String -> IOEnv env a
failWithM String
s = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
_ -> IOError -> IO a
forall a. IOError -> IO a
ioError (String -> IOError
userError String
s))
data IOEnvFailure = IOEnvFailure
instance Show IOEnvFailure where
show :: IOEnvFailure -> String
show IOEnvFailure
IOEnvFailure = String
"IOEnv failure"
instance Exception IOEnvFailure
instance ExceptionMonad (IOEnv a) where
gcatch :: IOEnv a a -> (e -> IOEnv a a) -> IOEnv a a
gcatch IOEnv a a
act e -> IOEnv a a
handle =
(a -> IO a) -> IOEnv a a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv ((a -> IO a) -> IOEnv a a) -> (a -> IO a) -> IOEnv a a
forall a b. (a -> b) -> a -> b
$ \a
s -> IOEnv a a -> a -> IO a
forall env a. IOEnv env a -> env -> IO a
unIOEnv IOEnv a a
act a
s IO a -> (e -> IO a) -> IO a
forall (m :: * -> *) e a.
(ExceptionMonad m, Exception e) =>
m a -> (e -> m a) -> m a
`gcatch` \e
e -> IOEnv a a -> a -> IO a
forall env a. IOEnv env a -> env -> IO a
unIOEnv (e -> IOEnv a a
handle e
e) a
s
gmask :: ((IOEnv a a -> IOEnv a a) -> IOEnv a b) -> IOEnv a b
gmask (IOEnv a a -> IOEnv a a) -> IOEnv a b
f =
(a -> IO b) -> IOEnv a b
forall env a. (env -> IO a) -> IOEnv env a
IOEnv ((a -> IO b) -> IOEnv a b) -> (a -> IO b) -> IOEnv a b
forall a b. (a -> b) -> a -> b
$ \a
s -> ((IO a -> IO a) -> IO b) -> IO b
forall (m :: * -> *) a b.
ExceptionMonad m =>
((m a -> m a) -> m b) -> m b
gmask (((IO a -> IO a) -> IO b) -> IO b)
-> ((IO a -> IO a) -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \IO a -> IO a
io_restore ->
let
g_restore :: IOEnv env a -> IOEnv env a
g_restore (IOEnv env -> IO a
m) = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv ((env -> IO a) -> IOEnv env a) -> (env -> IO a) -> IOEnv env a
forall a b. (a -> b) -> a -> b
$ \env
s -> IO a -> IO a
io_restore (env -> IO a
m env
s)
in
IOEnv a b -> a -> IO b
forall env a. IOEnv env a -> env -> IO a
unIOEnv ((IOEnv a a -> IOEnv a a) -> IOEnv a b
f IOEnv a a -> IOEnv a a
forall env. IOEnv env a -> IOEnv env a
g_restore) a
s
instance ContainsDynFlags env => HasDynFlags (IOEnv env) where
getDynFlags :: IOEnv env DynFlags
getDynFlags = do env
env <- IOEnv env env
forall env. IOEnv env env
getEnv
DynFlags -> IOEnv env DynFlags
forall (m :: * -> *) a. Monad m => a -> m a
return (DynFlags -> IOEnv env DynFlags) -> DynFlags -> IOEnv env DynFlags
forall a b. (a -> b) -> a -> b
$! env -> DynFlags
forall t. ContainsDynFlags t => t -> DynFlags
extractDynFlags env
env
instance ContainsModule env => HasModule (IOEnv env) where
getModule :: IOEnv env Module
getModule = do env
env <- IOEnv env env
forall env. IOEnv env env
getEnv
Module -> IOEnv env Module
forall (m :: * -> *) a. Monad m => a -> m a
return (Module -> IOEnv env Module) -> Module -> IOEnv env Module
forall a b. (a -> b) -> a -> b
$ env -> Module
forall t. ContainsModule t => t -> Module
extractModule env
env
runIOEnv :: env -> IOEnv env a -> IO a
runIOEnv :: env -> IOEnv env a -> IO a
runIOEnv env
env (IOEnv env -> IO a
m) = env -> IO a
m env
env
{-# NOINLINE fixM #-}
fixM :: (a -> IOEnv env a) -> IOEnv env a
fixM :: (a -> IOEnv env a) -> IOEnv env a
fixM a -> IOEnv env a
f = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> (a -> IO a) -> IO a
forall a. (a -> IO a) -> IO a
fixIO (\ a
r -> IOEnv env a -> env -> IO a
forall env a. IOEnv env a -> env -> IO a
unIOEnv (a -> IOEnv env a
f a
r) env
env))
tryM :: IOEnv env r -> IOEnv env (Either IOEnvFailure r)
tryM :: IOEnv env r -> IOEnv env (Either IOEnvFailure r)
tryM (IOEnv env -> IO r
thing) = (env -> IO (Either IOEnvFailure r))
-> IOEnv env (Either IOEnvFailure r)
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> IO r -> IO (Either IOEnvFailure r)
forall a. IO a -> IO (Either IOEnvFailure a)
tryIOEnvFailure (env -> IO r
thing env
env))
tryIOEnvFailure :: IO a -> IO (Either IOEnvFailure a)
tryIOEnvFailure :: IO a -> IO (Either IOEnvFailure a)
tryIOEnvFailure = IO a -> IO (Either IOEnvFailure a)
forall e a. Exception e => IO a -> IO (Either e a)
try
tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r)
tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r)
tryAllM (IOEnv env -> IO r
thing) = (env -> IO (Either SomeException r))
-> IOEnv env (Either SomeException r)
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> IO r -> IO (Either SomeException r)
forall e a. Exception e => IO a -> IO (Either e a)
try (env -> IO r
thing env
env))
tryMostM :: IOEnv env r -> IOEnv env (Either SomeException r)
tryMostM :: IOEnv env r -> IOEnv env (Either SomeException r)
tryMostM (IOEnv env -> IO r
thing) = (env -> IO (Either SomeException r))
-> IOEnv env (Either SomeException r)
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> IO r -> IO (Either SomeException r)
forall a. IO a -> IO (Either SomeException a)
tryMost (env -> IO r
thing env
env))
unsafeInterleaveM :: IOEnv env a -> IOEnv env a
unsafeInterleaveM :: IOEnv env a -> IOEnv env a
unsafeInterleaveM (IOEnv env -> IO a
m) = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> IO a -> IO a
forall a. IO a -> IO a
unsafeInterleaveIO (env -> IO a
m env
env))
uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a
uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a
uninterruptibleMaskM_ (IOEnv env -> IO a
m) = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> IO a -> IO a
forall a. IO a -> IO a
uninterruptibleMask_ (env -> IO a
m env
env))
instance Alternative (IOEnv env) where
empty :: IOEnv env a
empty = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (IO a -> env -> IO a
forall a b. a -> b -> a
const IO a
forall (f :: * -> *) a. Alternative f => f a
empty)
IOEnv env a
m <|> :: IOEnv env a -> IOEnv env a -> IOEnv env a
<|> IOEnv env a
n = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\env
env -> IOEnv env a -> env -> IO a
forall env a. IOEnv env a -> env -> IO a
unIOEnv IOEnv env a
m env
env IO a -> IO a -> IO a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> IOEnv env a -> env -> IO a
forall env a. IOEnv env a -> env -> IO a
unIOEnv IOEnv env a
n env
env)
instance MonadPlus (IOEnv env)
instance MonadIO (IOEnv env) where
liftIO :: IO a -> IOEnv env a
liftIO IO a
io = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
_ -> IO a
io)
newMutVar :: a -> IOEnv env (IORef a)
newMutVar :: a -> IOEnv env (IORef a)
newMutVar a
val = IO (IORef a) -> IOEnv env (IORef a)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (a -> IO (IORef a)
forall a. a -> IO (IORef a)
newIORef a
val)
writeMutVar :: IORef a -> a -> IOEnv env ()
writeMutVar :: IORef a -> a -> IOEnv env ()
writeMutVar IORef a
var a
val = IO () -> IOEnv env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IORef a -> a -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef a
var a
val)
readMutVar :: IORef a -> IOEnv env a
readMutVar :: IORef a -> IOEnv env a
readMutVar IORef a
var = IO a -> IOEnv env a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IORef a -> IO a
forall a. IORef a -> IO a
readIORef IORef a
var)
updMutVar :: IORef a -> (a -> a) -> IOEnv env ()
updMutVar :: IORef a -> (a -> a) -> IOEnv env ()
updMutVar IORef a
var a -> a
upd = IO () -> IOEnv env ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IORef a -> (a -> a) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef IORef a
var a -> a
upd)
atomicUpdMutVar :: IORef a -> (a -> (a, b)) -> IOEnv env b
atomicUpdMutVar :: IORef a -> (a -> (a, b)) -> IOEnv env b
atomicUpdMutVar IORef a
var a -> (a, b)
upd = IO b -> IOEnv env b
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IORef a -> (a -> (a, b)) -> IO b
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef a
var a -> (a, b)
upd)
atomicUpdMutVar' :: IORef a -> (a -> (a, b)) -> IOEnv env b
atomicUpdMutVar' :: IORef a -> (a -> (a, b)) -> IOEnv env b
atomicUpdMutVar' IORef a
var a -> (a, b)
upd = IO b -> IOEnv env b
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IORef a -> (a -> (a, b)) -> IO b
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef a
var a -> (a, b)
upd)
getEnv :: IOEnv env env
{-# INLINE getEnv #-}
getEnv :: IOEnv env env
getEnv = (env -> IO env) -> IOEnv env env
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> env -> IO env
forall (m :: * -> *) a. Monad m => a -> m a
return env
env)
setEnv :: env' -> IOEnv env' a -> IOEnv env a
{-# INLINE setEnv #-}
setEnv :: env' -> IOEnv env' a -> IOEnv env a
setEnv env'
new_env (IOEnv env' -> IO a
m) = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
_ -> env' -> IO a
m env'
new_env)
updEnv :: (env -> env') -> IOEnv env' a -> IOEnv env a
{-# INLINE updEnv #-}
updEnv :: (env -> env') -> IOEnv env' a -> IOEnv env a
updEnv env -> env'
upd (IOEnv env' -> IO a
m) = (env -> IO a) -> IOEnv env a
forall env a. (env -> IO a) -> IOEnv env a
IOEnv (\ env
env -> env' -> IO a
m (env -> env'
upd env
env))