{-# LANGUAGE DataKinds             #-}
# LANGUAGE FlexibleInstances      #
# LANGUAGE MultiParamTypeClasses #

| 
 Module       :  . Stmt 
 Description : Monadic wrapper for the Recipe language 
 Copyright    : ( c ) 2020   
 License      : MIT 
 Maintainer   :  
 Stability    : experimental 

Module      : Blarney.Stmt
Description : Monadic wrapper for the Recipe language
Copyright   : (c) 2020 Matthew Naylor
License     : MIT
Maintainer  : 
Stability   : experimental
-}
module Blarney.Stmt
  ( Stmt
  , tick
  , skip
  , action
  , wait
  , par
  , while
  , background
  , runStmt
  , runStmtOn
  ) where

-- Standard imports
import Prelude
import Control.Monad

-- Blarney imports
import Blarney.Core
import Blarney.Recipe

  |Statement monad , with mondic bind for sequential composition .
data Stmt a = Stmt Recipe a

instance Monad Stmt where
  return = pure
  Stmt r1 a >>= f = Stmt (Seq [r1, r2]) b
    where Stmt r2 b = f a

instance Functor Stmt where
  fmap = liftM

instance Applicative Stmt where
  pure a = Stmt Skip a
  (<*>) = ap

skip :: Stmt ()
skip = Stmt Skip ()

tick :: Stmt ()
tick = Stmt Tick ()

action :: Action () -> Stmt ()
action act = Stmt (Action act) ()

par :: [Stmt ()] -> Stmt ()
par stmts = Stmt (Par [r | Stmt r _ <- stmts]) ()

wait :: Bit 1 -> Stmt ()
wait c = Stmt (Wait c) ()

while :: Bit 1 -> Stmt () -> Stmt ()
while c (Stmt r _) = Stmt (While c r) ()

ifThenElseStmt :: Bit 1 -> Stmt () -> Stmt () -> Stmt ()
ifThenElseStmt c (Stmt r1 _) (Stmt r2 _) =
  Stmt (If c r1 r2) ()

instance IfThenElse (Bit 1) (Stmt ()) where
  ifThenElse = ifThenElseStmt

whenStmt :: Bit 1 -> Stmt () -> Stmt ()
whenStmt c s = ifThenElseStmt c s skip

instance When (Bit 1) Stmt where
  when = whenStmt

background :: Stmt () -> Stmt ()
background (Stmt r _) = Stmt (Background r) ()

  |Run a statement with a start pulse that is high only on the first
-- cycle of execution, and ignore the finish pulse.
runStmt :: Stmt () -> Module ()
runStmt (Stmt r _) = runRecipe r

-- |Run a statement, triggered by the given start pulse.
-- Returns the finish pulse.
runStmtOn :: Bit 1 -> Stmt () -> Module (Bit 1)
runStmtOn pulse (Stmt r _) = runRecipeOn pulse r

# LANGUAGE DataKinds             #
 Standard imports
 Blarney imports
 cycle of execution, and ignore the finish pulse.
 |Run a statement, triggered by the given start pulse.
 Returns the finish pulse.
# LANGUAGE FlexibleInstances      #
# LANGUAGE MultiParamTypeClasses #

| 
 Module       :  . Stmt 
 Description : Monadic wrapper for the Recipe language 
 Copyright    : ( c ) 2020   
 License      : MIT 
 Maintainer   :  
 Stability    : experimental 

Module      : Blarney.Stmt
Description : Monadic wrapper for the Recipe language
Copyright   : (c) 2020 Matthew Naylor
License     : MIT
Maintainer  : 
Stability   : experimental
-}
module Blarney.Stmt
  ( Stmt
  , tick
  , skip
  , action
  , wait
  , par
  , while
  , background
  , runStmt
  , runStmtOn
  ) where

import Prelude
import Control.Monad

import Blarney.Core
import Blarney.Recipe

  |Statement monad , with mondic bind for sequential composition .
data Stmt a = Stmt Recipe a

instance Monad Stmt where
  return = pure
  Stmt r1 a >>= f = Stmt (Seq [r1, r2]) b
    where Stmt r2 b = f a

instance Functor Stmt where
  fmap = liftM

instance Applicative Stmt where
  pure a = Stmt Skip a
  (<*>) = ap

skip :: Stmt ()
skip = Stmt Skip ()

tick :: Stmt ()
tick = Stmt Tick ()

action :: Action () -> Stmt ()
action act = Stmt (Action act) ()

par :: [Stmt ()] -> Stmt ()
par stmts = Stmt (Par [r | Stmt r _ <- stmts]) ()

wait :: Bit 1 -> Stmt ()
wait c = Stmt (Wait c) ()

while :: Bit 1 -> Stmt () -> Stmt ()
while c (Stmt r _) = Stmt (While c r) ()

ifThenElseStmt :: Bit 1 -> Stmt () -> Stmt () -> Stmt ()
ifThenElseStmt c (Stmt r1 _) (Stmt r2 _) =
  Stmt (If c r1 r2) ()

instance IfThenElse (Bit 1) (Stmt ()) where
  ifThenElse = ifThenElseStmt

whenStmt :: Bit 1 -> Stmt () -> Stmt ()
whenStmt c s = ifThenElseStmt c s skip

instance When (Bit 1) Stmt where
  when = whenStmt

background :: Stmt () -> Stmt ()
background (Stmt r _) = Stmt (Background r) ()

  |Run a statement with a start pulse that is high only on the first
runStmt :: Stmt () -> Module ()
runStmt (Stmt r _) = runRecipe r

runStmtOn :: Bit 1 -> Stmt () -> Module (Bit 1)
runStmtOn pulse (Stmt r _) = runRecipeOn pulse r
