{-# 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 IORef (HashMap k v)
ref <- forall a. a -> IO (IORef a)
newIORef forall k v. HashMap k v
Map.empty; forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall k v. IORef (HashMap k v) -> Maybe (Env k v) -> Env k v
Env IORef (HashMap k v)
ref forall a. Maybe a
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 IORef (HashMap k v)
ref <- forall a. a -> IO (IORef a)
newIORef forall k v. HashMap k v
Map.empty; forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall k v. IORef (HashMap k v) -> Maybe (Env k v) -> Env k v
Env IORef (HashMap k v)
ref forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just Env k v
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 = forall a. IORef a -> (a -> a) -> IO ()
modifyIORef IORef (HashMap k v)
ref forall a b. (a -> b) -> a -> b
$ 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
    HashMap k v
mp <- forall a. IORef a -> IO a
readIORef IORef (HashMap k v)
ref
    case forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookup k
k HashMap k v
mp of
        Just v
v -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just v
v
        Maybe v
Nothing | Just Env k v
e <- Maybe (Env k v)
e -> forall k v. (Eq k, Hashable k) => Env k v -> k -> IO (Maybe v)
askEnv Env k v
e k
k
        Maybe v
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure 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)
_) = forall a. IORef a -> IO a
readIORef IORef (HashMap k v)
ref