    {-# LANGUAGE PatternGuards #-}

    -- | A Ninja style environment, equivalent to a non-empty list of mutable hash tables.
    module Development.Ninja.Env(
        Env, newEnv, scopeEnv, addEnv, askEnv, fromEnv
        ) where

    import qualified Data.HashMap.Strict as Map
    import Data.Hashable
    import Data.IORef

    data Env k v = Env (IORef (Map.HashMap k v)) (Maybe (Env k v))

    instance Show (Env k v) where show :: Env k v -> String
    show Env k v
    _ = String
    "Env"

    newEnv :: IO (Env k v)
    newEnv :: forall k v. IO (Env k v)
    newEnv = do ref <- HashMap k v -> IO (IORef (HashMap k v))
    forall a. a -> IO (IORef a)
    newIORef HashMap k v
    forall k v. HashMap k v
    Map.empty; pure $ Env ref Nothing

    scopeEnv :: Env k v -> IO (Env k v)
    scopeEnv :: forall k v. Env k v -> IO (Env k v)
    scopeEnv Env k v
    e = do ref <- HashMap k v -> IO (IORef (HashMap k v))
    forall a. a -> IO (IORef a)
    newIORef HashMap k v
    forall k v. HashMap k v
    Map.empty; pure $ Env ref $ Just e

    addEnv :: (Eq k, Hashable k) => Env k v -> k -> v -> IO ()
    addEnv :: forall k v. (Eq k, Hashable k) => Env k v -> k -> v -> IO ()
    addEnv (Env IORef (HashMap k v)
    ref Maybe (Env k v)
    _) k
    k v
    v = IORef (HashMap k v) -> (HashMap k v -> HashMap k v) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef IORef (HashMap k v)
    ref ((HashMap k v -> HashMap k v) -> IO ())
    -> (HashMap k v -> HashMap k v) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ k -> v -> HashMap k v -> HashMap k v
    forall k v.
    (Eq k, Hashable k) =>
    k -> v -> HashMap k v -> HashMap k v
    Map.insert k
    k v
    v

    askEnv :: (Eq k, Hashable k) => Env k v -> k -> IO (Maybe v)
    askEnv :: forall k v. (Eq k, Hashable k) => Env k v -> k -> IO (Maybe v)
    askEnv (Env IORef (HashMap k v)
    ref Maybe (Env k v)
    e) k
    k = do
        mp <- IORef (HashMap k v) -> IO (HashMap k v)
    forall a. IORef a -> IO a
    readIORef IORef (HashMap k v)
    ref
        case Map.lookup k mp of
            Just v
    v -> Maybe v -> IO (Maybe v)
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Maybe v -> IO (Maybe v)) -> Maybe v -> IO (Maybe v)
    forall a b. (a -> b) -> a -> b
    $ v -> Maybe v
    forall a. a -> Maybe a
    Just v
    v
            Maybe v
    Nothing | Just Env k v
    e <- Maybe (Env k v)
    e -> Env k v -> k -> IO (Maybe v)
    forall k v. (Eq k, Hashable k) => Env k v -> k -> IO (Maybe v)
    askEnv Env k v
    e k
    k
            Maybe v
    _ -> Maybe v -> IO (Maybe v)
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure Maybe v
    forall a. Maybe a
    Nothing

    fromEnv :: Env k v -> IO (Map.HashMap k v)
    fromEnv :: forall k v. Env k v -> IO (HashMap k v)
    fromEnv (Env IORef (HashMap k v)
    ref Maybe (Env k v)
    _) = IORef (HashMap k v) -> IO (HashMap k v)
    forall a. IORef a -> IO a
    readIORef IORef (HashMap k v)
    ref