Skip to content

Commit

Permalink
Even more documentation strings.
Browse files Browse the repository at this point in the history
  • Loading branch information
tilk committed Jul 19, 2022
1 parent a838ede commit bf86708
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 76 deletions.
18 changes: 17 additions & 1 deletion src/FSM.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
Copyright : (C) 2022 Marek Materzok
License : BSD2 (see the file LICENSE)
Maintainer : Marek Materzok <tilk@tilk.eu>
|-}
The YieldFSM compiler.
-}
module FSM(fsm) where

import FSM.Lang
Expand Down Expand Up @@ -64,6 +66,20 @@ mkFSM str = do
hFlush stderr
fail "FAIL"

{-|
The YieldFSM compiler as a Template Haskell quasiquoter.
It compiles YieldFSM programs to Clash definitions.
Example use:
> [fsm|countFSM :: (CP.HiddenClockResetEnable dom)
> => CP.Signal dom Integer
> fun f i:
> yield i
> ret call f (i+1)
> ret call f 0
> |]
-}
fsm :: THQ.QuasiQuoter
fsm = THQ.QuasiQuoter undefined undefined undefined mkFSM

48 changes: 31 additions & 17 deletions src/FSM/Desc.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,44 @@ import qualified Language.Haskell.TH as TH
import qualified Data.Map.Strict as M
import Prelude

{-|
Encodes a Mealy machine transition.
-}
data Transition = Transition {
transOutput :: TH.Exp,
transNextState :: TH.Name,
transNextStateParams :: TH.Exp
transOutput :: TH.Exp, -- ^ Output value on this transition.
transNextState :: TH.Name, -- ^ The name of the next state.
transNextStateParams :: TH.Exp -- ^ Parameters of the next state.
}

data DecisionTree a = DTIf TH.Exp (DecisionTree a) (DecisionTree a)
| DTLet TH.Pat TH.Exp (DecisionTree a)
| DTCase TH.Exp [(TH.Pat, DecisionTree a)]
| DTLeaf a
{-|
Decision trees. Used to represent conditions on which the next
transition is selected.
-}
data DecisionTree a = DTIf TH.Exp (DecisionTree a) (DecisionTree a) -- ^ Boolean condition.
| DTLet TH.Pat TH.Exp (DecisionTree a) -- ^ Let definition.
| DTCase TH.Exp [(TH.Pat, DecisionTree a)] -- ^ Case (pattern-matching) condition.
| DTLeaf a -- ^ Leaf of the decision tree.

{-|
Encodes a Mealy machine state. A state can be parametrized, and it has
a number of transitions, encoded using a decision tree.
-}
data FSMState = FSMState {
fsmStateParams :: TH.Pat,
fsmStateTrans :: DecisionTree Transition
fsmStateParams :: TH.Pat, -- ^ State parameters.
fsmStateTrans :: DecisionTree Transition -- ^ State transitions.
}

{-|
Encodes a Mealy machine.
-}
data FSM = FSM {
fsmName :: TH.Name,
fsmType :: TH.Type,
fsmParams :: [TH.Pat],
fsmStates :: M.Map TH.Name FSMState,
fsmInputs :: Maybe TH.Pat,
fsmInitState :: TH.Name,
fsmInitStateParam :: TH.Exp,
fsmConts :: M.Map TH.Name (M.Map TH.Name [TH.Name])
fsmName :: TH.Name, -- ^ Machine name.
fsmType :: TH.Type, -- ^ Clash type of the machine.
fsmParams :: [TH.Pat], -- ^ Machine parameters.
fsmStates :: M.Map TH.Name FSMState, -- ^ Machine states.
fsmInputs :: Maybe TH.Pat, -- ^ Machine inputs.
fsmInitState :: TH.Name, -- ^ Machine initial state.
fsmInitStateParam :: TH.Exp, -- ^ Parameters of the initial state.
fsmConts :: M.Map TH.Name (M.Map TH.Name [TH.Name]) -- ^ Continuation data types.
}

4 changes: 4 additions & 0 deletions src/FSM/DescGenADT.hs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ wildUnused s (TH.ListP ps) = TH.ListP $ wildUnused s <$> ps
wildUnused s (TH.SigP p t) = TH.SigP (wildUnused s p) t
wildUnused s (TH.ViewP e p) = TH.ViewP e $ wildUnused s p

{-|
Compiles the automata descriptions in the target language to Mealy machines
defined in Clash. This is the final stage of YieldFSM compilation.
-}
compileFSM :: FSM -> TH.Q [TH.Dec]
compileFSM fsm = do
let nm = TH.nameBase $ fsmName fsm
Expand Down
41 changes: 39 additions & 2 deletions src/FSM/FreeVars.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ Maintainer : Marek Materzok <tilk@tilk.eu>
Defines helper functions related to free variables and substitutions.
-}
module FSM.FreeVars where
module FSM.FreeVars(
FreeVars(..), FreeVarsPat(..), PatFV(..),
patSingleton, patFreeSingleton, patFreeVars, underPat,
boundVars, freeVarsFunMap,
Subst(..), substSingle, rename, renameSingle, boundAsVars, substPat,
isConstantExpr
) where

import qualified Language.Haskell.TH as TH
import qualified Data.Set as S
Expand All @@ -16,29 +22,46 @@ import FSM.Desc
import Control.Arrow
import qualified FSM.Util.SetClass as SC

-- | Things that have free variables.
class FreeVars a where
freeVars :: SC.SetClass s => a -> s TH.Name

-- | Things that have bound and free variables.
class FreeVarsPat a where
freeVarsPat :: SC.SetClass s => a -> PatFV s

data PatFV s = PatFV { patBound :: s TH.Name, patFree :: s TH.Name }
{-|
Represents bound and free variables (e.g. for a pattern).
A Haskell pattern can both bind variables, and have free variables (e.g.
in view patterns).
-}
data PatFV s = PatFV {
patBound :: s TH.Name, -- ^ Bound variables.
patFree :: s TH.Name -- ^ Free variables.
}

instance SC.SetClass s => Semigroup (PatFV s) where
PatFV s1 s2 <> PatFV t1 t2 = PatFV (s1 `SC.union` t1) (s2 `SC.union` t2)

instance SC.SetClass s => Monoid (PatFV s) where
mempty = PatFV mempty mempty

-- | A single bound variable.
patSingleton :: SC.SetClass s => TH.Name -> PatFV s
patSingleton n = PatFV (SC.singleton n) mempty

-- | A single free variable.
patFreeSingleton :: SC.SetClass s => TH.Name -> PatFV s
patFreeSingleton n = PatFV mempty (SC.singleton n)

-- | Free variables of something, as a 'PatFV'.
patFreeVars :: (SC.SetClass s, FreeVars a) => a -> PatFV s
patFreeVars e = PatFV mempty (freeVars e)

{-|
Free variables under a pattern. The pattern's bound variables
reduce the set of free variables; its free variables extend it.
-}
underPat :: SC.SetClass s => s TH.Name -> PatFV s -> s TH.Name
underPat s (PatFV bs fs) = fs <> (s `SC.difference` bs)

Expand All @@ -48,6 +71,7 @@ underPatFV (PatFV bs1 fs1) (PatFV bs2 fs2) = PatFV (bs1 <> bs2) (fs2 <> (fs1 `SC
freeVarsUnderPat :: (SC.SetClass s, FreeVarsPat a) => s TH.Name -> a -> s TH.Name
freeVarsUnderPat s p = s `underPat` freeVarsPat p

-- | Bound vars of something.
boundVars :: (SC.SetClass s, FreeVarsPat a) => a -> s TH.Name
boundVars = patBound . freeVarsPat

Expand All @@ -57,6 +81,7 @@ instance FreeVars a => FreeVars (Maybe a) where
instance FreeVarsPat a => FreeVarsPat (Maybe a) where
freeVarsPat = maybe mempty id . fmap freeVarsPat

-- | Free variables of a function set.
freeVarsFunMap :: (IsDesugared l, SC.SetClass s) => FunMap l -> s TH.Name
freeVarsFunMap = mconcat . map (\(_, (p, s)) -> freeVars s `freeVarsUnderPat` p) . M.toList

Expand Down Expand Up @@ -199,7 +224,9 @@ substName :: M.Map TH.Name TH.Exp -> TH.Name -> TH.Exp
substName s n | Just e <- M.lookup n s = e
| otherwise = TH.VarE n

-- | Things that can have expressions substituted for variables.
class Subst a where
-- | Variable substitution.
subst :: M.Map TH.Name TH.Exp -> a -> a

instance Subst TH.Exp where
Expand Down Expand Up @@ -323,19 +350,23 @@ instance Subst a => Subst [a] where
instance Subst a => Subst (Maybe a) where
subst s = fmap (subst s)

-- | Perform a single variable substitution.
substSingle :: Subst a => TH.Name -> TH.Exp -> a -> a
substSingle n e = subst (M.singleton n e)

instance Subst VStmt where
subst su (VExp e) = VExp (subst su e)
subst su (VCall n e) = VCall n (subst su e)

-- | Rename variables (substitute variables for variables).
rename :: Subst a => M.Map TH.Name TH.Name -> a -> a
rename su = subst (M.map TH.VarE su)

-- | Rename a single variable.
renameSingle :: Subst a => TH.Name -> TH.Name -> a -> a
renameSingle n n' = substSingle n (TH.VarE n')

-- | Variables bound in @as@ patterns.
boundAsVars :: TH.Pat -> S.Set TH.Name
boundAsVars (TH.LitP _) = mempty
boundAsVars (TH.VarP _) = mempty
Expand All @@ -355,6 +386,7 @@ boundAsVars (TH.ListP ps) = mconcat $ map boundAsVars ps
boundAsVars (TH.SigP p _) = boundAsVars p
boundAsVars (TH.ViewP _ p) = boundAsVars p

-- | Substitute a pattern for a bound variable in a pattern.
substPat :: M.Map TH.Name TH.Pat -> TH.Pat -> TH.Pat
substPat _ p@(TH.LitP _) = p
substPat s p@(TH.VarP n) | Just p' <- M.lookup n s = p'
Expand Down Expand Up @@ -407,6 +439,11 @@ isConstructorExpr (TH.UnboundVarE _) = False
isConstructorExpr (TH.LabelE _) = False
isConstructorExpr (TH.ImplicitParamVarE _) = False

{-|
Expressions that can be substituted without duplicating circuits.
In digital circuits, constructors are represented as bundles of wires,
and therefore can be duplicated without a performance penalty.
-}
isConstantExpr :: TH.Exp -> Bool
isConstantExpr (TH.VarE _) = True
isConstantExpr e = isConstructorExpr e
Expand Down
Loading

0 comments on commit bf86708

Please sign in to comment.