circus-0.1.0.0: src/Circus/DSL.hs
{-# LANGUAGE DeriveGeneric #-}
module Circus.DSL where
import Circus.Types
import Control.Monad.State.Class
import Data.Map (Map)
import qualified Data.Map as M
import qualified Data.Text as T
import GHC.Generics
import Generics.SYB hiding (Generic)
data GraphState = GraphState
{ gs_next_port :: Bit
, gs_module :: Module
}
deriving stock (Generic)
instance Semigroup GraphState where
GraphState b1 m1 <> GraphState b2 m2
= GraphState
{ gs_next_port = b1 + b2
, gs_module = m1 <> m2
}
instance Monoid GraphState where
mempty = GraphState
{ gs_next_port = Bit 0
, gs_module = mempty
}
------------------------------------------------------------------------------
-- | Synthesize a fresh 'Bit', suitable for connecting 'Cell's
-- together.
freshBit :: MonadState GraphState m => m Bit
freshBit = do
p <- gets gs_next_port
modify $ \gs ->
gs { gs_next_port = gs_next_port gs + 1 }
pure p
------------------------------------------------------------------------------
-- | Add a 'Cell' to the 'Module' under construction.
addCell :: MonadState GraphState m => Cell -> m ()
addCell c = do
uniq <- freshBit
let name = CellName $ T.pack $ show $ getBit uniq
modify' $ \gs ->
gs { gs_module = gs_module gs
<> Module mempty (M.singleton name c)
}
------------------------------------------------------------------------------
-- | Like 'unifyBits', but works in pure contexts.
unifyBitsPure :: Data a => Map Bit Bit -> a -> a
unifyBitsPure rep = everywhere $ mkT $ \case
b | Just b' <- M.lookup b rep -> b'
| otherwise -> b
------------------------------------------------------------------------------
-- | Given a mapping from source 'Bit's to target 'Bit's, replace
-- all occurences of the source bits in the 'Module' with the target bits.
--
-- This function allows you to call 'addCell' as you go, and create
-- feedback loops later without needing to know about them in
-- advance.
unifyBits :: MonadState GraphState m => Map Bit Bit -> m ()
unifyBits rep =
modify' $ \gs -> gs
{ gs_module = unifyBitsPure rep $ gs_module gs
}