packages feed

asil-1.2: src/Env.hs

-- | Environments.
--   A 'dynamic' environment has a number of fixed bindings, and some new bindings.
--   The old bindings are preserved; the new ones added.
module Env(Env,StaticEnv,DynEnv,DynId,Subst,mappedTo,singleEnv,listEnv,lookupEnv,closeEnv,openEnv,mapEnv
          ,valuesEnv,assocsEnv,keysEnv) where

import Data.Map(Map)
import qualified Data.Map as Map
import Data.Monoid
import Data.Word

newtype Env key elem = Env (Map key elem)
type StaticEnv elem = Env Word32 elem
type DynEnv elem    = Env DynId elem


--
-- Instances for 'Env'
--

instance (Show k, Show a) => Show (Env k a) where
  show (Env env) = show $ Map.assocs env

instance Ord k => Monoid (Env k a) where
  mempty = Env Map.empty
  mappend (Env p) (Env q) = Env (Map.union p q)


-- | A dynamic key for some value in the environment.
--   Either the key is fixed, and relates to an already existing key,
--   or it is a fresh key, which means its added to the environment.
data DynId
  = FixedId !Word32
  | FreshId !Int
  deriving (Eq,Ord,Show)


-- | Wrapper around a substitution
newtype Subst = Subst (Map Int Word32)

-- | Obtains a substitution
mappedTo :: Int -> Subst -> Word32
mappedTo key (Subst subst) = Map.findWithDefault (error ("mappedTo: no such substitution for: " ++ show key ++ " in: " ++ show subst)) key subst

-- | Wrap an item into an environment
singleEnv :: Ord k => k -> a -> Env k a
singleEnv k v = Env $ Map.singleton k v

-- | Convert a list of pairs into a static environment
listEnv :: [(Word32,a)] -> StaticEnv a
listEnv = Env . Map.fromList

-- | Obtain he pairs in the environment
assocsEnv :: Env k a -> [(k,a)]
assocsEnv (Env m) = Map.assocs m

-- | Obtain the values in the environment
valuesEnv :: Env k a -> [a]
valuesEnv (Env m) = Map.elems m

-- | Obtain the keys in the environment
keysEnv :: Env k a -> [k]
keysEnv (Env m) = Map.keys m

-- | Lookup an item in the environment (that is supposed to be there)
lookupEnv :: (Ord k, Show k, Show a) => k -> Env k a -> a
lookupEnv key e@(Env env) = Map.findWithDefault (error ("lookupEnv: no key " ++ show key ++ " in: " ++ show e)) key env

-- | Closes a dynamic environment, turning it into a static environment, and a substitution for the
--   fresh identifiers in the environment.
closeEnv :: DynEnv a -> (StaticEnv a, Subst)
closeEnv (Env env) = (Env env', Subst subst) where
  ks     = Map.keys env
  newId  = 1 + maximum (0 : [ n | (FixedId n) <- ks ])
  newKs  = [ i | (FreshId i) <- ks ]
  subst  = Map.fromList $ zip newKs [newId..]
  env'   = Map.mapKeys fKeys env
  fKeys (FreshId i) = Map.findWithDefault undefined i subst
  fkeys k = k

-- | Turns a static environment back into a dynamic environment
openEnv :: StaticEnv a -> DynEnv a
openEnv (Env env) = Env $ Map.mapKeys FixedId env

-- | Map on env
mapEnv :: (k -> a -> b) -> Env k a -> Env k b
mapEnv f (Env env) = Env $ Map.mapWithKey f env