C.5 Simple Circus Laws
C.6.3 Translation
Here, we briefly explain the purpose and implementation details of each defined function as it appears in the translator code.
isCSPis a function which takes a Circus action and returns a boolean indicating if the particularCircusaction is aCSPone or not.
isCSP :: Circus -> Bool -- to be implemented later
C.6. SIMPLE CIRCUS TRANSLATION 159
action2cspis a high level function which takes a complete circus program and a defined action in it and returns its equivalent in theCSPworld. The implementation is achieved by making use ofmkCGraphap- pearing later in the implementation. After getting the graph of a particularCircusprogram usingmkCGraph, thetranslateCircfunction is used to do the actual translation based on the action name received and its corresponding variables and calls.
action2csp :: CircusProgram -> String -> CircusProgram action2csp prog aname
= let cgrf = mkCGraph prog in case alookup cgrf aname of
Nothing -> error ("No action ’"++aname++"’ found")
Just (vars,calls) -> translateCirc prog cgrf aname vars calls
The difference between high level functionscircus2cspandaction2cspis that the functioncircus2csp
maps a complete Circus program to its translated version while the latter works on an individual action inside the Circus program.
circus2csp :: CircusProgram -> CircusProgram circus2csp prog
= let cgrf = mkCGraph prog in prog
FunctiongetCircVarsCallstakes a complete Circus program and gets the information involved i.e. the definition name, the array of maintaining variables used in the definition and the array having the information of the calls of particular actions. This is achieved by using functionsactionVarsandactionCalls.
getCircVarsCalls :: CircusProgram
-> [ ( String -- definition name
, ( [String] -- variables used in definition (sorted) , [String] -- actions called
) ) ] getCircVarsCalls defs = alnorm $ gCVC defs where gCVC [] = [] gCVC ((aname,(aparam,abody)):rest) = (aname,(avars,acalls)):gCVC rest where
avars = lnorm $ actionVars abody acalls = lnorm $ actionCalls abody
160 APPENDIX C. HASKELL IMPLEMENTATION variables used in a particular action.
actionVars :: Circus -> [String]
actionVars (x := e) = [x] ++ exprVars e actionVars (Call act _) = []
actionVars ((x,_) ::-> circ) = x : actionVars circ
actionVars (INT x _ circ) = x : actionVars circ actionVars (SEQ x _ circ) = x : actionVars circ actionVars (EXT x _ circ) = x : actionVars circ actionVars (ILV x _ circ) = x : actionVars circ actionVars (IPAR _ x _ circ) = x : actionVars circ actionVars (APAR x _ _ circ) = x : actionVars circ
actionVars (a :-> circ) = actionVars circ
actionVars (c1 ::: c2) = actionVars c1 ++ actionVars c2 actionVars (IntChoice c1 c2) = actionVars c1 ++ actionVars c2 actionVars (ExtChoice c1 c2) = actionVars c1 ++ actionVars c2 actionVars (Hide circ _) = actionVars circ
actionVars (IPar _ c1 c2) = actionVars c1 ++ actionVars c2 actionVars (APar _ _ c1 c2) = actionVars c1 ++ actionVars c2 actionVars (Ilv c1 c2) = actionVars c1 ++ actionVars c2
actionVars (Cond e c1 c2) = exprVars e ++ actionVars c1 ++ actionVars c2 actionVars (Guard e circ) = exprVars e ++ actionVars circ
actionVars (Mu _ circ) = actionVars circ actionVars _ = []
The functionactionCallstakes a particular Circus action and generates an array for gathering names of the calls to particular actions.
actionCalls :: Circus -> [String]
actionCalls (Call a _) = [a] actionCalls (n := e) = []
actionCalls (c1 ::: c2) = actionCalls c1 ++ actionCalls c2 actionCalls (a :-> circ) = actionCalls circ
actionCalls ((x,xs) ::-> circ) = actionCalls circ
actionCalls (IntChoice c1 c2) = actionCalls c1 ++ actionCalls c2 actionCalls (ExtChoice c1 c2) = actionCalls c1 ++ actionCalls c2 actionCalls (Hide circ a) = actionCalls circ
actionCalls (IPar a c1 c2) = actionCalls c1 ++ actionCalls c2 actionCalls (APar a b c1 c2) = actionCalls c1 ++ actionCalls c2 actionCalls (Ilv c1 c2) = actionCalls c1 ++ actionCalls c2 actionCalls (Cond e c1 c2) = actionCalls c1 ++ actionCalls c2 actionCalls (Guard e circ) = actionCalls circ
actionCalls (INT x a circ) = actionCalls circ actionCalls (SEQ x a circ) = actionCalls circ actionCalls (EXT x a circ) = actionCalls circ actionCalls (ILV x a circ) = actionCalls circ
C.6. SIMPLE CIRCUS TRANSLATION 161
actionCalls (IPAR _ x _ circ) = actionCalls circ actionCalls (APAR x _ _ circ) = actionCalls circ actionCalls (Mu x circ) = actionCalls circ \\ [x] actionCalls _ = []
To gather information on the variables used in a particular expression, the functionexprVarsis defined.
exprVars (Var v) = [v]
exprVars (Agg _ _ es) = concat $ map exprVars es exprVars (App _ es) = concat $ map exprVars es exprVars (Bin _ e1 e2) = exprVars e1 ++ exprVars e2 exprVars _ = []
The important function here isdetCircDepswhich manages the record of the dependencies for the final translated version of the Circus program. It determines the dependencies by analysing the calls to particular actions by usinggetCallsfunction.
detCircDeps :: [(String,([String],[String]))] -> [(String,([String],[String]))] detCircDeps deps
= dCP deps [] False deps where
dCP deps0 deps’ chgd []
| chgd = dCP deps’ [] False deps’
| otherwise = deps’ -- should equal deps0 !
dCP deps0 deps’ chgd (dep@(name,(vars,calls)):rest)
| calls’ == calls = dCP deps0 (dep:deps’) chgd rest
| otherwise = dCP deps0 ((name,(vars,calls’)):deps’) True rest
where calls’ = getCalls deps0 calls calls
getCalls :: [(String,([String],[String]))] -> [String] -> [String] -> [String] getCalls deps0 calls’ [] = lnorm calls’
getCalls deps0 calls’ (call:calls) = case alookup deps0 call of
Nothing -> error ("Action ’"++call++"’ is undefined")
Just (_,subcalls) -> getCalls deps0 (subcalls++calls’) calls
As mentioned earlier,mkCGraphandtranslateCircare used by the high level functions of translator calledaction2csp andcircus2csp. After getting the graph of a particular Circus program through
mkCGraph, thetranslateCircfunction is used to do the actual translation based on the action name received and its corresponding variables and calls.
mkCGraph :: CircusProgram -> [(String,([String],[String]))] mkCGraph = detCircDeps . getCircVarsCalls
162 APPENDIX C. HASKELL IMPLEMENTATION
translateCirc :: CircusProgram -> [(String,([String],[String]))]
-> String -> [String] -> [String] -> CircusProgram translateCirc prog cgrf aname vars calls
= let usedActionNames = lnorm (aname:calls) isUsed (nm,_) = nm ‘elem‘ usedActionNames
rprog = filter isUsed prog
newplist = lnorm (vars ++ getParams cgrf calls) plistvars = map Var newplist
addpars (nm,(pars,body))
= (nm,(pars++newplist,addParams nm plistvars body))
pprog = map addpars rprog
in pprog
The purpose of theaddParamsfunction is to attach the list of parameters to aCircusaction. This is required because in the CSP world the variables of the Circus world turn into parameters and a particular action is invoked using parametric calls. While dealing with the assignment commands of the Circusworld, the expression assigned to a particular variable is substituted in the parameter list.
addParams :: String -> [Expr] -> Circus -> Circus
addParams nm plist (Call cnm pars) = (Call cnm (pars++plist)) addParams nm plist Skip = (Call (nm++"_CONT") plist)
addParams nm plist (c1 ::: c2) = (addParams nm plist c1 ::: addParams nm plist c2) addParams nm plist (a :-> circ) = (a :-> (addParams nm plist circ))
addParams nm plist ((x,xs) ::-> circ) = ((x,xs) ::-> addParams nm plist circ) addParams nm plist (IntChoice c1 c2) = (IntChoice (addParams nm plist c1)
(addParams nm plist c2)) addParams nm plist (ExtChoice c1 c2) = (ExtChoice (addParams nm plist c1)
(addParams nm plist c2)) addParams nm plist (Hide circ a) = (Hide (addParams nm plist circ) a) addParams nm plist (IPar a c1 c2) = (IPar a (addParams nm plist c1)
(addParams nm plist c2)) addParams nm plist (APar a b c1 c2) = (APar a b (addParams nm plist c1)
(addParams nm plist c2)) addParams nm plist (Ilv c1 c2) = (Ilv (addParams nm plist c1)
(addParams nm plist c2)) addParams nm plist (Cond e c1 c2) = (Cond e (addParams nm plist c1)
(addParams nm plist c2)) addParams nm plist (Guard e circ) = (Guard e (addParams nm plist circ)) addParams nm plist (INT x a circ) = (INT x a (addParams nm plist circ)) addParams nm plist (SEQ x a circ) = (SEQ x a (addParams nm plist circ)) addParams nm plist (EXT x a circ) = (EXT x a (addParams nm plist circ)) addParams nm plist (ILV x a circ) = (ILV x a (addParams nm plist circ)) addParams nm plist (IPAR a x b circ) = (IPAR a x b (addParams nm plist circ)) addParams nm plist (APAR x a b circ) = (APAR x a b (addParams nm plist circ)) addParams nm plist body = body
C.6. SIMPLE CIRCUS TRANSLATION 163
-- extract part of prog of interest - all definitions aname:calls (rprog) -- add newplist to extend plist of every call (pprog)
-- return pprog
getParams :: [(String,([String],[String]))] -> [String] -> [String]
getParams cgrf calls = concat $ map (fst . fromJust . alookup cgrf) calls
getCallChains :: CircusProgram -> [ [ [String] ] ]
getCallChains defs = gCC defs where
gCC [] = []
gCC ((aname,(aparam,abody)):rest)
| aname == "MAIN" = (normTreeSt):gCC rest | otherwise = gCC rest
where
normTreeSt = normTree abody
normTree :: Circus -> [[String]]
normTree (ExtChoice c1 c2) = [[ecName]] ++ [actionCallChains c1] ++ [actionCallChains c2] normTree (IntChoice c1 c2) = [[icName]] ++ [actionCallChains c1] ++ [actionCallChains c2] normTree (c1 ::: c2) = [[seqName]] ++ [actionCallChains c1 ++ actionCallChains c2]
normTree _ = [[]]
actionCallChains :: Circus -> [String]
actionCallChains (Call a _) = [a]
actionCallChains (c1 ::: c2) = actionCallChains c1 ++ actionCallChains c2
actionCallChains _ = []
The functiongetCallTreeis defined here to create the call tree after analysing the MAIN action. It is assumed here that theCircusmain is constituted only of calls to actions, internal choice and external choice.
class Functor1 f where
fmap1 :: (a -> b) -> f a -> f b
data Tree a = Empty | Node (Tree a) String (Tree a) | Leaf a deriving (Eq, Ord, Show)
instance Functor1 Tree where
fmap1 f (Node l m r) = Node (fmap1 f l) m (fmap1 f r) fmap1 f (Leaf x) = Leaf (f x)
getCallTree :: CircusProgram -> [ Tree String ] getCallTree defs
164 APPENDIX C. HASKELL IMPLEMENTATION
where
gCT [] = []
gCT ((aname,(aparam,abody)):rest)
| aname == "MAIN" = (callTreeSt):gCT rest | otherwise = gCT rest
where
callTreeSt = callTree abody
callTree :: Circus -> Tree String
callTree (Call a _) = Leaf a
callTree (ExtChoice c1 c2) = (Node (callTree c1) ecName (callTree c2))
callTree (IntChoice c1 c2) = (Node (callTree c1) icName (callTree c2))
callTree (c1 ::: c2) = (Node (callTree c1) seqName (callTree c2))
callTree _ = Empty
The functionextractSeqis defined here to generate fresh names for the Circus actions on the left and right side of the sequential composition. Each leading node from the tree of sequential composition is given a fresh name to make the circus action compositions a sequential one. For example:
(A[]B);(C[]D) =>N1; N2whereN1= (A[]B)andN2= (C[]D).
getExtractSeq :: CircusProgram -> [ (Circus, [(String, Circus)]) ] getExtractSeq defs
= gES defs where
gES [] = []
gES ((aname,(aparam,abody)):rest)
| aname == "MAIN" = (extractSeqSt):gES rest | otherwise = gES rest
where
extractSeqSt = extractSeq abody
extractSeq :: Circus -> (Circus, [(String,Circus)]) extractSeq circ = (circ, newNamedActs circ)
newNamedActs :: Circus -> [(String, Circus)]
newNamedActs (ExtChoice c1 c2) = [(newActNameGen c1, c1)] ++ [(newActNameGen c2, c2)] newNamedActs (IntChoice c1 c2) = [(newActNameGen c1, c1)] ++ [(newActNameGen c2, c2)] newNamedActs (c1 ::: c2) = (newNamedActs c1) ++ (newNamedActs c2)
newNamedActs _ = []
newActNameGen :: Circus -> String