signals-0.2.0.1: src/Signal/Core/Reify.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Signal.Core.Reify
( Key (..)
, Node(..)
, Nodes
, reify
, freify
) where
import Signal.Core hiding (lift)
import Signal.Core.Witness
import Control.Monad.Operational.Higher
import Control.Applicative ((<$>))
import Control.Arrow (first, second)
import Control.Monad
import Control.Monad.State
import Data.Functor.Identity
import Data.Typeable (Typeable)
import Data.Dynamic (Dynamic, toDyn)
import Data.Ref
import Data.Ref.Map (Map, Name)
import Language.Embedded.VHDL (PredicateExp)
import System.Mem.StableName
import qualified Signal.Core as S
import qualified Data.Ref.Map as M
import Prelude hiding (Left, Right, join)
--------------------------------------------------------------------------------
-- * Reification of Signals
--------------------------------------------------------------------------------
{--- | Index type for names
type Ix i a = Name (S Symbol i a)
-}
-- | Index keys of a reification mapping
data Key (i :: (* -> *) -> * -> *) (a :: *) where
Key :: Name (S Symbol i a) -> Key i a
-- | Values of a reification mapping
data Node (i :: (* -> *) -> * -> *) (a :: *) where
Node :: Witness i a => S Key i a -> Node i (S Symbol i a)
-- | Short-hand for a node mapping
type Nodes i = Map (Node i)
--------------------------------------------------------------------------------
-- ** Reification functions
-- | Reification of a signal into a mapping over its nodes and root key
reify :: Sig i a -> IO (Key i (Identity a), Nodes i)
reify (Sig (Signal sym)) =
second fst <$> runStateT (reify' sym) (M.empty, M.empty)
-- | Reification of a signal function into a mapping over its nodes, root key and input key
freify
:: ( PredicateExp (IExp i) a
, Typeable i
, Typeable a
, Typeable b)
=> (Sig i a -> Sig i b)
-> IO (Key i (Identity b), Nodes i)
freify f =
do let (_, graph) = let a = Sig (S.variable (toDyn f)) in (a, f a)
reify graph
--------------------------------------------------------------------------------
-- ** ...
-- | ...
type Reify i = StateT (Nodes i, Map Name) IO
-- | Reification of a symbol tree
reify' :: forall i a. Symbol i a -> Reify i (Key i a)
reify' (Symbol ref@(Ref k node)) =
do name <- lookupName ref
case name of
Just old@(Key k') -> return old
Nothing -> do
insertName ref
case node of
(S.Var dyn) -> insertNode ref (Node (S.Var dyn))
(S.Repeat str) -> insertNode ref (Node (S.Repeat str))
(S.Map f sig) ->
do key <- reify' sig
insertNode ref (Node (S.Map f key))
(S.Join l r) ->
do lkey <- reify' l
rkey <- reify' r
insertNode ref (Node (S.Join lkey rkey))
(S.Left l) ->
do lkey <- reify' l
insertNode ref (Node (S.Left lkey))
(S.Right r) ->
do rkey <- reify' r
insertNode ref (Node (S.Right rkey))
(S.Delay v sig) ->
do key <- reify' sig
insertNode ref (Node (S.Delay v key))
(S.Mux sig choices) ->
do key <- reify' sig
keys <- forM choices $ \(c, s) ->
do s' <- reify' s
return (c, s')
insertNode ref (Node (S.Mux key keys))
--------------------------------------------------------------------------------
-- | Insert a signal node under the given reference name
insertNode :: Ref (S Symbol i a) -> Node i (S Symbol i a) -> Reify i (Key i a)
insertNode ref@(Ref name _) node = modify (first $ M.insert ref node) >> return (Key name)
-- | Insert a reference name
insertName :: Ref (S Symbol i a) -> Reify i ()
insertName ref@(Ref name _) = modify $ second $ M.insert ref name
-- | Tries to find a reference name
lookupName :: Ref (S Symbol i a) -> Reify i (Maybe (Key i a))
lookupName ref@(Ref name _) = do
node <- gets (M.lookup name . snd)
return $ case node of
Nothing -> Nothing
Just old -> Just (Key old)
--------------------------------------------------------------------------------
-- *
--------------------------------------------------------------------------------
debug :: (Key i (Identity a), Nodes i) -> IO ()
debug ((Key name), nodes) =
do let entries = M.elems nodes
putStrLn "========== Debug =========="
putStrLn $ "Input key: " ++ show (hashStableName name)
forM_ entries (putStrLn . apa)
putStrLn "==========================="
where
apa :: M.Entry (Node i) -> String
apa (M.Entry n (Node s)) = "Node (" ++ show (hashStableName n) ++ ") : " ++ print s
print :: S sym i a -> String
print node = case node of
Repeat {} -> "repeat"
Map {} -> "map"
Join {} -> "join"
Left {} -> "left"
Right {} -> "right"
Delay {} -> "delay"
Mux {} -> "mux"
Var {} -> "var"