• No results found

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