packages feed

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
    }