ddc-core-eval-0.2.0.1: DDC/Core/Eval/Store.hs
-- | Definition of the store.
---
-- This implements the store in terms of the operational semantics of the
-- core language, and isn't intended to be efficient in a practical sense.
-- If we cared about runtime performance we'd want to use an IOArray or
-- some other mutable structure to hold the bindings, instead of a Data.Map.
--
module DDC.Core.Eval.Store
( Store (..)
, Loc (..)
, Rgn (..)
, SBind (..)
-- * Operators
, empty
, newLoc, newLocs
, newRgn, newRgns
, delRgn
, hasRgn
, setGlobal
, addBind
, allocBind, allocBinds
, lookupBind
, lookupTypeOfLoc
, lookupRegionTypeBind)
where
import DDC.Core.Exp
import DDC.Core.Eval.Name
import Control.Monad
import DDC.Core.Pretty hiding (empty)
import Data.Map (Map)
import Data.Set (Set)
import qualified Data.Map as Map
import qualified Data.Set as Set
data Store
= Store
{ -- | Next store location to allocate.
storeNextLoc :: Int
-- | Next region handle to allocate.
, storeNextRgn :: Int
-- | Region handles already allocated.
, storeRegions :: Set Rgn
-- | Regions that are marked as global, and are not
-- deallocated with a stack discipline.
, storeGlobal :: Set Rgn
-- | Map of locations to store bindings,
-- their types,
-- and the handle for the regions they're in.
, storeBinds :: Map Loc (Rgn, Type Name, SBind) }
deriving Show
-- | Store binding.
-- These are naked objects that can be allocated directly into the heap.
data SBind
-- | An algebraic data constructor.
= SObj
{ sbindDataTag :: Name
, sbindDataArgs :: [Loc] }
-- | Lambda abstraction, used for recursive bindings.
-- The flag indicates whether each binder is level-1 (True) or level-0 (False).
| SLams
{ sbindLamBinds :: [(Bool, Bind Name)]
, sbindLamBody :: Exp () Name }
-- | A thunk, used for lazy evaluation.
| SThunk
{ sbindThunkExp :: Exp () Name }
deriving (Eq, Show)
-- Pretty ---------------------------------------------------------------------
instance Pretty Store where
ppr (Store nextLoc nextRgn regions global binds)
= vcat
[ text "* STORE"
, text " NextLoc: " <> text (show nextLoc)
, text " NextRgn: " <> text (show nextRgn)
, text " Regions: " <> braces (sep $ punctuate comma
$ map ppr $ Set.toList regions)
, text " Global: " <> braces (sep $ punctuate comma
$ map ppr $ Set.toList global)
, text ""
, text " Binds:"
, vcat $ [ text " " <> ppr l <> colon <> ppr r <> text " -> " <> ppr sbind
<> line
<> text " :: " <> ppr t
| (l, (r, t, sbind)) <- Map.toList binds] ]
instance Pretty SBind where
ppr (SObj tag [])
= text "OBJ" <+> ppr tag
ppr (SObj tag svs)
= text "OBJ" <+> ppr tag
<+> (sep $ map ppr svs)
ppr (SLams fbs x)
= text "LAMS" <+> sep (map (parens . ppr) fbs)
<> text "."
<> text (renderPlain $ ppr x)
ppr (SThunk x)
= text "THUNK" <+> text (renderPlain $ ppr x)
-- Constructors ---------------------------------------------------------------
-- | An empty store, with no bindings or regions.
empty :: Store
empty = Store
{ storeNextLoc = 1
, storeNextRgn = 1
, storeRegions = Set.empty
, storeGlobal = Set.empty
, storeBinds = Map.empty }
-- Locations ------------------------------------------------------------------
-- | Create a new location in the store.
newLoc :: Store -> (Store, Loc)
newLoc store
= let loc = storeNextLoc store
store' = store { storeNextLoc = loc + 1 }
in (store', Loc loc)
-- | Create several new locations in the store.
newLocs :: Int -> Store -> (Store, [Loc])
newLocs n store
= let lFirst = storeNextLoc store
lLast = lFirst + n
locs = [lFirst .. lLast]
store' = store { storeNextLoc = lLast + 1 }
in (store', map Loc locs)
-- Regions -------------------------------------------------------------------
-- | Create a new region in the store.
newRgn :: Store -> (Store, Rgn)
newRgn store
= let rgn = storeNextRgn store
store' = store { storeNextRgn = rgn + 1
, storeRegions = Set.insert (Rgn rgn) (storeRegions store) }
in (store', Rgn rgn)
-- | Create several new regions in the store
newRgns :: Int -> Store -> (Store, [Rgn])
newRgns 0 store = (store, [])
newRgns count store
= let rgns = map Rgn $ [ storeNextRgn store .. storeNextRgn store + count - 1]
store' = store { storeNextRgn = storeNextRgn store + count
, storeRegions = Set.union (Set.fromList rgns) (storeRegions store) }
in (store', rgns)
-- | Delete a region, removing all its bindings.
delRgn :: Rgn -> Store -> Store
delRgn rgn store
= let binds' = [x | x@(_, (r, _, _)) <- Map.toList $ storeBinds store
, r /= rgn ]
in store { storeBinds = Map.fromList binds'
, storeRegions = Set.delete rgn (storeRegions store)
, storeGlobal = Set.delete rgn (storeGlobal store) }
-- | Check whether a store contains the given region.
hasRgn :: Store -> Rgn -> Bool
hasRgn store rgn
= Set.member rgn (storeRegions store)
-- | Set a region as being global.
setGlobal :: Rgn -> Store -> Store
setGlobal rgn store
= store
{ storeGlobal = Set.insert rgn (storeGlobal store) }
-- Bindings -------------------------------------------------------------------
-- | Add a store binding to the store, at the given location.
addBind :: Loc -> Rgn -> Type Name -> SBind -> Store -> Store
addBind loc rgn t sbind store
= store
{ storeBinds = Map.insert loc (rgn, t, sbind) (storeBinds store) }
-- | Allocate a new binding into the given region,
-- returning the new location.
allocBind :: Rgn -> Type Name -> SBind -> Store -> (Store, Loc)
allocBind rgn t sbind store
= let (store1, loc) = newLoc store
store2 = addBind loc rgn t sbind store1
in (store2, loc)
-- | Alloc some recursive bindings into the given region,
-- returning the new locations.
allocBinds :: ([[Loc] -> (Rgn, Type Name, SBind)]) -> Store -> (Store, [Loc])
allocBinds mkSBinds store
= let n = length mkSBinds
(store1, locs) = newLocs n store
rgnBinds = map (\mk -> mk locs) mkSBinds
store2 = foldr (\(l, (r, t, b)) -> addBind l r t b) store1
$ zip locs rgnBinds
in (store2, locs)
-- | Lookup a the binding for a location.
lookupBind :: Loc -> Store -> Maybe SBind
lookupBind loc store
= liftM (\(_, _, sb) -> sb)
$ Map.lookup loc (storeBinds store)
-- | Lookup the type of a store location.
lookupTypeOfLoc :: Loc -> Store -> Maybe (Type Name)
lookupTypeOfLoc loc store
= case Map.lookup loc (storeBinds store) of
Nothing -> Nothing
Just (_, t, _) -> Just t
-- | Lookup the region handle, type and binding for a location.
lookupRegionTypeBind :: Loc -> Store -> Maybe (Rgn, Type Name, SBind)
lookupRegionTypeBind loc store
= Map.lookup loc (storeBinds store)