Rearranged FlowGraph and fixed the tests
Previously, most of the flow-graph building functions were inside the where clause of buildFlowGraph. They have been moved to the top-level (with only a few small changes to make this possible - the main one being to store the labelling functions in a reader monad, which only required changing a couple of lines) and used by an additional buildFlowGraphP function, that is now used by the tests to make them work simply. None of the new top-level functions except buildFlowGraphP are exported from FlowGraph.
This commit is contained in:
parent
acd57d74de
commit
fa1e9a6a08
|
@ -41,12 +41,13 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-- * If statements, on the other hand, have to be chained together. Each expression is connected
|
-- * If statements, on the other hand, have to be chained together. Each expression is connected
|
||||||
-- to its body, but also to the next expression. There is no link between the last expression
|
-- to its body, but also to the next expression. There is no link between the last expression
|
||||||
-- and the end of the if; if statements behave like STOP if nothing is matched.
|
-- and the end of the if; if statements behave like STOP if nothing is matched.
|
||||||
module FlowGraph (AlterAST(..), EdgeLabel(..), FNode, FlowGraph, FlowGraph', GraphLabelFuncs(..), buildFlowGraph, getNodeData, getNodeFunc, getNodeMeta, joinLabelFuncs, makeFlowGraphInstr, makeTestNode, mkLabelFuncsConst, mkLabelFuncsGeneric) where
|
module FlowGraph (AlterAST(..), EdgeLabel(..), FNode, FlowGraph, FlowGraph', GraphLabelFuncs(..), buildFlowGraph, buildFlowGraphP, getNodeData, getNodeFunc, getNodeMeta, joinLabelFuncs, makeFlowGraphInstr, makeTestNode, mkLabelFuncsConst, mkLabelFuncsGeneric) where
|
||||||
|
|
||||||
import Control.Monad.Error
|
import Control.Monad.Error
|
||||||
|
import Control.Monad.Reader
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import Data.Generics
|
import Data.Generics
|
||||||
import Data.Graph.Inductive
|
import Data.Graph.Inductive hiding (run)
|
||||||
|
|
||||||
import qualified AST as A
|
import qualified AST as A
|
||||||
import Metadata
|
import Metadata
|
||||||
|
@ -114,7 +115,7 @@ type NodesEdges m a b = ([LNode (FNode' m a b)],[LEdge EdgeLabel])
|
||||||
-- * The list of root nodes thus far (those with no links to them)
|
-- * The list of root nodes thus far (those with no links to them)
|
||||||
type GraphMakerState mAlter a b = (Node, Int, NodesEdges mAlter a b, [Node])
|
type GraphMakerState mAlter a b = (Node, Int, NodesEdges mAlter a b, [Node])
|
||||||
|
|
||||||
type GraphMaker mLabel mAlter a b c = ErrorT String (StateT (GraphMakerState mAlter a b) mLabel) c
|
type GraphMaker mLabel mAlter a b c = ErrorT String (ReaderT (GraphLabelFuncs mLabel a) (StateT (GraphMakerState mAlter a b) mLabel)) c
|
||||||
|
|
||||||
-- | The GraphLabelFuncs type. These are a group of functions
|
-- | The GraphLabelFuncs type. These are a group of functions
|
||||||
-- used to provide labels for different elements of AST.
|
-- used to provide labels for different elements of AST.
|
||||||
|
@ -178,93 +179,77 @@ mkLabelFuncsConst v = GLF (const v) (const v) (const v) (const v) (const v) (con
|
||||||
mkLabelFuncsGeneric :: Monad m => (forall t. Data t => t -> m label) -> GraphLabelFuncs m label
|
mkLabelFuncsGeneric :: Monad m => (forall t. Data t => t -> m label) -> GraphLabelFuncs m label
|
||||||
mkLabelFuncsGeneric f = GLF f f f f f f f f
|
mkLabelFuncsGeneric f = GLF f f f f f f f f
|
||||||
|
|
||||||
-- | Builds a control-flow-graph. The mAlter monad is the monad in which
|
|
||||||
-- AST alterations would take place. Note that mAlter does not feature in
|
|
||||||
-- the parameters, only in the result. The mLabel monad is the monad in
|
|
||||||
-- which the labelling must be done; hence the flow-graph is returned inside
|
|
||||||
-- the label monad.
|
|
||||||
buildFlowGraph :: forall mLabel mAlter label structType. (Monad mLabel, Monad mAlter, Data structType) =>
|
|
||||||
GraphLabelFuncs mLabel label ->
|
|
||||||
A.Structured structType ->
|
|
||||||
mLabel (Either String (FlowGraph' mAlter label structType, [Node]))
|
|
||||||
buildFlowGraph funcs s
|
|
||||||
= do res <- runStateT (runErrorT $ buildStructured (\_ _ _ -> throwError "Did not expect outer-most node to exist in AST") ONone s id) (0, 0, ([],[]), [])
|
|
||||||
return $ case res of
|
|
||||||
(Left err,_) -> Left err
|
|
||||||
(Right (Left {}),(_,_,(nodes, edges),roots)) -> Right (mkGraph nodes edges, roots)
|
|
||||||
(Right (Right (root,_)),(_,_,(nodes, edges),roots)) -> Right (mkGraph nodes edges, root : roots)
|
|
||||||
where
|
|
||||||
-- All the functions return the new graph, and the identifier of the node just added
|
|
||||||
|
|
||||||
run :: (GraphLabelFuncs mLabel label -> (b -> mLabel label)) -> b -> mLabel label
|
run :: forall mLabel mAlter label structType b. (Monad mLabel, Monad mAlter) => (GraphLabelFuncs mLabel label -> (b -> mLabel label)) -> b -> GraphMaker mLabel mAlter label structType label
|
||||||
run func = func funcs
|
run func x = do f <- asks func
|
||||||
|
lift . lift .lift $ f x
|
||||||
|
|
||||||
addNode :: (Meta, label, AlterAST mAlter structType) -> GraphMaker mLabel mAlter label structType Node
|
addNode :: (Monad mLabel, Monad mAlter) => (Meta, label, AlterAST mAlter structType) -> GraphMaker mLabel mAlter label structType Node
|
||||||
addNode x = do (n,pi,(nodes, edges), rs) <- get
|
addNode x = do (n,pi,(nodes, edges), rs) <- get
|
||||||
put (n+1, pi,((n, Node x):nodes, edges), rs)
|
put (n+1, pi,((n, Node x):nodes, edges), rs)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
denoteRootNode :: Node -> GraphMaker mLabel mAlter label structType ()
|
denoteRootNode :: (Monad mLabel, Monad mAlter) => Node -> GraphMaker mLabel mAlter label structType ()
|
||||||
denoteRootNode root = do (n, pi, nes, roots) <- get
|
denoteRootNode root = do (n, pi, nes, roots) <- get
|
||||||
put (n, pi, nes, root : roots)
|
put (n, pi, nes, root : roots)
|
||||||
|
|
||||||
addEdge :: EdgeLabel -> Node -> Node -> GraphMaker mLabel mAlter label structType ()
|
addEdge :: (Monad mLabel, Monad mAlter) => EdgeLabel -> Node -> Node -> GraphMaker mLabel mAlter label structType ()
|
||||||
addEdge label start end = do (n, pi, (nodes, edges), rs) <- get
|
addEdge label start end = do (n, pi, (nodes, edges), rs) <- get
|
||||||
-- Edges should only be added after the nodes, so
|
-- Edges should only be added after the nodes, so
|
||||||
-- for safety here we can check that the nodes exist:
|
-- for safety here we can check that the nodes exist:
|
||||||
if (notElem start $ map fst nodes) || (notElem end $ map fst nodes)
|
if (notElem start $ map fst nodes) || (notElem end $ map fst nodes)
|
||||||
then throwError "Could not add edge between non-existent nodes"
|
then throwError "Could not add edge between non-existent nodes"
|
||||||
else put (n + 1, pi, (nodes,(start, end, label):edges), rs)
|
else put (n + 1, pi, (nodes,(start, end, label):edges), rs)
|
||||||
|
|
||||||
-- It is important for the flow-graph tests that the Meta tag passed in is the same as the
|
-- It is important for the flow-graph tests that the Meta tag passed in is the same as the
|
||||||
-- result of calling findMeta on the third parameter
|
-- result of calling findMeta on the third parameter
|
||||||
addNode' :: Meta -> (GraphLabelFuncs mLabel label -> (b -> mLabel label)) -> b -> AlterAST mAlter structType -> GraphMaker mLabel mAlter label structType Node
|
addNode' :: (Monad mLabel, Monad mAlter) => Meta -> (GraphLabelFuncs mLabel label -> (b -> mLabel label)) -> b -> AlterAST mAlter structType -> GraphMaker mLabel mAlter label structType Node
|
||||||
addNode' m f t r = do val <- (lift . lift) (run f t)
|
addNode' m f t r = do val <- run f t
|
||||||
addNode (m, val, r)
|
addNode (m, val, r)
|
||||||
|
|
||||||
addNodeExpression :: Meta -> A.Expression -> (ASTModifier mAlter A.Expression structType) -> GraphMaker mLabel mAlter label structType Node
|
addNodeExpression :: (Monad mLabel, Monad mAlter) => Meta -> A.Expression -> (ASTModifier mAlter A.Expression structType) -> GraphMaker mLabel mAlter label structType Node
|
||||||
addNodeExpression m e r = addNode' m labelExpression e (AlterExpression r)
|
addNodeExpression m e r = addNode' m labelExpression e (AlterExpression r)
|
||||||
|
|
||||||
addNodeExpressionList :: Meta -> A.ExpressionList -> (ASTModifier mAlter A.ExpressionList structType) -> GraphMaker mLabel mAlter label structType Node
|
addNodeExpressionList :: (Monad mLabel, Monad mAlter) => Meta -> A.ExpressionList -> (ASTModifier mAlter A.ExpressionList structType) -> GraphMaker mLabel mAlter label structType Node
|
||||||
addNodeExpressionList m e r = addNode' m labelExpressionList e (AlterExpressionList r)
|
addNodeExpressionList m e r = addNode' m labelExpressionList e (AlterExpressionList r)
|
||||||
|
|
||||||
addDummyNode :: Meta -> GraphMaker mLabel mAlter label structType Node
|
addDummyNode :: (Monad mLabel, Monad mAlter) => Meta -> GraphMaker mLabel mAlter label structType Node
|
||||||
addDummyNode m = addNode' m labelDummy m AlterNothing
|
addDummyNode m = addNode' m labelDummy m AlterNothing
|
||||||
|
|
||||||
getNextParEdgeId :: GraphMaker mLabel mAlter label structType Int
|
getNextParEdgeId :: (Monad mLabel, Monad mAlter) => GraphMaker mLabel mAlter label structType Int
|
||||||
getNextParEdgeId = do (a, pi, b, c) <- get
|
getNextParEdgeId = do (a, pi, b, c) <- get
|
||||||
put (a, pi + 1, b, c)
|
put (a, pi + 1, b, c)
|
||||||
return pi
|
return pi
|
||||||
|
|
||||||
addParEdges :: Int -> (Node,Node) -> [(Node,Node)] -> GraphMaker mLabel mAlter label structType ()
|
addParEdges :: (Monad mLabel, Monad mAlter) => Int -> (Node,Node) -> [(Node,Node)] -> GraphMaker mLabel mAlter label structType ()
|
||||||
addParEdges usePI (s,e) pairs
|
addParEdges usePI (s,e) pairs
|
||||||
= do (n,pi,(nodes,edges),rs) <- get
|
= do (n,pi,(nodes,edges),rs) <- get
|
||||||
put (n,pi,(nodes,edges ++ (concatMap (parEdge usePI) pairs)),rs)
|
put (n,pi,(nodes,edges ++ (concatMap (parEdge usePI) pairs)),rs)
|
||||||
where
|
where
|
||||||
parEdge :: Int -> (Node, Node) -> [LEdge EdgeLabel]
|
parEdge :: Int -> (Node, Node) -> [LEdge EdgeLabel]
|
||||||
parEdge id (a,z) = [(s,a,(EStartPar id)),(z,e,(EEndPar id))]
|
parEdge id (a,z) = [(s,a,(EStartPar id)),(z,e,(EEndPar id))]
|
||||||
|
|
||||||
-- The build-up functions are all of type (innerType -> m innerType) -> outerType -> m outerType
|
-- The build-up functions are all of type (innerType -> m innerType) -> outerType -> m outerType
|
||||||
-- which has the synonym Route m innerType outerType
|
-- which has the synonym Route m innerType outerType
|
||||||
|
|
||||||
getN :: Int -> [a] -> ([a],a,[a])
|
getN :: Int -> [a] -> ([a],a,[a])
|
||||||
getN n xs = let (f,(m:e)) = splitAt n xs in (f,m,e)
|
getN n xs = let (f,(m:e)) = splitAt n xs in (f,m,e)
|
||||||
|
|
||||||
routeList :: Monad m => Int -> (a -> m a) -> ([a] -> m [a])
|
routeList :: Monad m => Int -> (a -> m a) -> ([a] -> m [a])
|
||||||
routeList n f xs
|
routeList n f xs
|
||||||
= do let (pre,x,suf) = getN n xs
|
= do let (pre,x,suf) = getN n xs
|
||||||
x' <- f x
|
x' <- f x
|
||||||
return (pre ++ [x'] ++ suf)
|
return (pre ++ [x'] ++ suf)
|
||||||
|
|
||||||
mapMR :: forall inner. ASTModifier mAlter [inner] structType -> (inner -> ASTModifier mAlter inner structType -> GraphMaker mLabel mAlter label structType (Node,Node)) -> [inner] -> GraphMaker mLabel mAlter label structType [(Node,Node)]
|
mapMR :: forall inner mAlter mLabel label structType. (Monad mLabel, Monad mAlter) => ASTModifier mAlter [inner] structType -> (inner -> ASTModifier mAlter inner structType -> GraphMaker mLabel mAlter label structType (Node,Node)) -> [inner] -> GraphMaker mLabel mAlter label structType [(Node,Node)]
|
||||||
mapMR outerRoute func xs = mapM funcAndRoute (zip [0..] xs)
|
mapMR outerRoute func xs = mapM funcAndRoute (zip [0..] xs)
|
||||||
where
|
where
|
||||||
funcAndRoute :: (Int, inner) -> GraphMaker mLabel mAlter label structType (Node,Node)
|
funcAndRoute :: (Int, inner) -> GraphMaker mLabel mAlter label structType (Node,Node)
|
||||||
funcAndRoute (ind,x) = func x (outerRoute @-> routeList ind)
|
funcAndRoute (ind,x) = func x (outerRoute @-> routeList ind)
|
||||||
|
|
||||||
|
|
||||||
mapMRE :: forall inner. ASTModifier mAlter [inner] structType -> (inner -> ASTModifier mAlter inner structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node,Node))) -> [inner] -> GraphMaker mLabel mAlter label structType (Either Bool [(Node,Node)])
|
mapMRE :: forall inner mAlter mLabel label structType. (Monad mLabel, Monad mAlter) => ASTModifier mAlter [inner] structType -> (inner -> ASTModifier mAlter inner structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node,Node))) -> [inner] -> GraphMaker mLabel mAlter label structType (Either Bool [(Node,Node)])
|
||||||
mapMRE outerRoute func xs = mapM funcAndRoute (zip [0..] xs) >>* foldl foldEither (Left False)
|
mapMRE outerRoute func xs = mapM funcAndRoute (zip [0..] xs) >>* foldl foldEither (Left False)
|
||||||
where
|
where
|
||||||
foldEither :: Either Bool [(Node,Node)] -> Either Bool (Node,Node) -> Either Bool [(Node,Node)]
|
foldEither :: Either Bool [(Node,Node)] -> Either Bool (Node,Node) -> Either Bool [(Node,Node)]
|
||||||
foldEither (Left _) (Right n) = Right [n]
|
foldEither (Left _) (Right n) = Right [n]
|
||||||
|
@ -276,25 +261,32 @@ buildFlowGraph funcs s
|
||||||
funcAndRoute (ind,x) = func x (outerRoute @-> routeList ind)
|
funcAndRoute (ind,x) = func x (outerRoute @-> routeList ind)
|
||||||
|
|
||||||
|
|
||||||
nonEmpty :: Either Bool [(Node,Node)] -> Bool
|
nonEmpty :: Either Bool [(Node,Node)] -> Bool
|
||||||
nonEmpty (Left hadNodes) = hadNodes
|
nonEmpty (Left hadNodes) = hadNodes
|
||||||
nonEmpty (Right nodes) = not (null nodes)
|
nonEmpty (Right nodes) = not (null nodes)
|
||||||
|
|
||||||
joinPairs :: Meta -> [(Node, Node)] -> GraphMaker mLabel mAlter label structType (Node, Node)
|
joinPairs :: (Monad mLabel, Monad mAlter) => Meta -> [(Node, Node)] -> GraphMaker mLabel mAlter label structType (Node, Node)
|
||||||
joinPairs m [] = addDummyNode m >>* mkPair
|
joinPairs m [] = addDummyNode m >>* mkPair
|
||||||
joinPairs m nodes = do sequence_ $ mapPairs (\(_,s) (e,_) -> addEdge ESeq s e) nodes
|
joinPairs m nodes = do sequence_ $ mapPairs (\(_,s) (e,_) -> addEdge ESeq s e) nodes
|
||||||
return (fst (head nodes), snd (last nodes))
|
return (fst (head nodes), snd (last nodes))
|
||||||
|
|
||||||
|
|
||||||
buildStructuredP = buildStructured (\_ r p -> buildProcess p r)
|
buildStructuredP :: (Monad mLabel, Monad mAlter) =>
|
||||||
buildStructuredC = buildStructured buildOnlyChoice
|
OuterType -> A.Structured A.Process -> ASTModifier mAlter (A.Structured A.Process) structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node, Node))
|
||||||
buildStructuredO = buildStructured buildOnlyOption
|
buildStructuredP = buildStructured (\_ r p -> buildProcess p r)
|
||||||
|
buildStructuredC :: (Monad mLabel, Monad mAlter) =>
|
||||||
|
OuterType -> A.Structured A.Choice -> ASTModifier mAlter (A.Structured A.Choice) structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node, Node))
|
||||||
|
buildStructuredC = buildStructured buildOnlyChoice
|
||||||
|
buildStructuredO :: (Monad mLabel, Monad mAlter) =>
|
||||||
|
OuterType -> A.Structured A.Option -> ASTModifier mAlter (A.Structured A.Option) structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node, Node))
|
||||||
|
buildStructuredO = buildStructured buildOnlyOption
|
||||||
|
|
||||||
-- Returns a pair of beginning-node, end-node
|
-- Returns a pair of beginning-node, end-node
|
||||||
-- Bool indicates emptiness (False = empty, True = there was something)
|
-- Bool indicates emptiness (False = empty, True = there was something)
|
||||||
buildStructured :: forall a. Data a => (OuterType -> ASTModifier mAlter a structType -> a -> GraphMaker mLabel mAlter label structType (Node, Node)) ->
|
buildStructured :: forall a mAlter mLabel label structType. (Monad mLabel, Monad mAlter, Data a) =>
|
||||||
|
(OuterType -> ASTModifier mAlter a structType -> a -> GraphMaker mLabel mAlter label structType (Node, Node)) ->
|
||||||
OuterType -> A.Structured a -> ASTModifier mAlter (A.Structured a) structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node, Node))
|
OuterType -> A.Structured a -> ASTModifier mAlter (A.Structured a) structType -> GraphMaker mLabel mAlter label structType (Either Bool (Node, Node))
|
||||||
buildStructured f outer (A.Several m ss) route
|
buildStructured f outer (A.Several m ss) route
|
||||||
= do case outer of
|
= do case outer of
|
||||||
ONone -> -- If there is no context, they should be left as disconnected graphs.
|
ONone -> -- If there is no context, they should be left as disconnected graphs.
|
||||||
do nodes <- mapMRE decompSeveral (buildStructured f outer) ss
|
do nodes <- mapMRE decompSeveral (buildStructured f outer) ss
|
||||||
|
@ -322,7 +314,7 @@ buildFlowGraph funcs s
|
||||||
decompSeveral :: ASTModifier mAlter [A.Structured a] structType
|
decompSeveral :: ASTModifier mAlter [A.Structured a] structType
|
||||||
decompSeveral = route22 route A.Several
|
decompSeveral = route22 route A.Several
|
||||||
|
|
||||||
buildStructured f outer (A.Spec m spec str) route
|
buildStructured f outer (A.Spec m spec str) route
|
||||||
= do n <- addNode' (findMeta spec) labelScopeIn spec (AlterSpec $ route23 route A.Spec)
|
= do n <- addNode' (findMeta spec) labelScopeIn spec (AlterSpec $ route23 route A.Spec)
|
||||||
n' <- addNode' (findMeta spec) labelScopeOut spec (AlterSpec $ route23 route A.Spec)
|
n' <- addNode' (findMeta spec) labelScopeOut spec (AlterSpec $ route23 route A.Spec)
|
||||||
|
|
||||||
|
@ -347,7 +339,7 @@ buildFlowGraph funcs s
|
||||||
Right (s,e) -> do addEdge ESeq n s
|
Right (s,e) -> do addEdge ESeq n s
|
||||||
addEdge ESeq e n'
|
addEdge ESeq e n'
|
||||||
return $ Right (n,n')
|
return $ Right (n,n')
|
||||||
buildStructured f outer (A.Rep m rep str) route
|
buildStructured f outer (A.Rep m rep str) route
|
||||||
= do let alter = AlterReplicator $ route23 route A.Rep
|
= do let alter = AlterReplicator $ route23 route A.Rep
|
||||||
case outer of
|
case outer of
|
||||||
OSeq -> do n <- addNode' (findMeta rep) labelReplicator rep alter
|
OSeq -> do n <- addNode' (findMeta rep) labelReplicator rep alter
|
||||||
|
@ -372,10 +364,10 @@ buildFlowGraph funcs s
|
||||||
return $ Right (s,e)
|
return $ Right (s,e)
|
||||||
_ -> throwError $ "Cannot have replicators inside context: " ++ show outer
|
_ -> throwError $ "Cannot have replicators inside context: " ++ show outer
|
||||||
|
|
||||||
buildStructured f outer (A.Only _ o) route = f outer (route22 route A.Only) o >>* Right
|
buildStructured f outer (A.Only _ o) route = f outer (route22 route A.Only) o >>* Right
|
||||||
buildStructured _ _ s _ = return $ Left False
|
buildStructured _ _ s _ = return $ Left False
|
||||||
|
|
||||||
buildOnlyChoice outer route (A.Choice m exp p)
|
buildOnlyChoice outer route (A.Choice m exp p)
|
||||||
= do nexp <- addNodeExpression (findMeta exp) exp $ route23 route A.Choice
|
= do nexp <- addNodeExpression (findMeta exp) exp $ route23 route A.Choice
|
||||||
(nbodys, nbodye) <- buildProcess p $ route33 route A.Choice
|
(nbodys, nbodye) <- buildProcess p $ route33 route A.Choice
|
||||||
addEdge ESeq nexp nbodys
|
addEdge ESeq nexp nbodys
|
||||||
|
@ -385,7 +377,7 @@ buildFlowGraph funcs s
|
||||||
addEdge ESeq nbodye cEnd
|
addEdge ESeq nbodye cEnd
|
||||||
_ -> throwError "Choice found outside IF statement"
|
_ -> throwError "Choice found outside IF statement"
|
||||||
return (nexp,nbodye)
|
return (nexp,nbodye)
|
||||||
buildOnlyOption outer route opt
|
buildOnlyOption outer route opt
|
||||||
= do (s,e) <-
|
= do (s,e) <-
|
||||||
case opt of
|
case opt of
|
||||||
(A.Option m es p) -> do
|
(A.Option m es p) -> do
|
||||||
|
@ -402,9 +394,10 @@ buildFlowGraph funcs s
|
||||||
_ -> throwError "Option found outside CASE statement"
|
_ -> throwError "Option found outside CASE statement"
|
||||||
return (s,e)
|
return (s,e)
|
||||||
|
|
||||||
addNewSubProcFunc :: Meta -> [A.Formal] -> Either (A.Process, ASTModifier mAlter A.Process structType) (A.Structured A.ExpressionList, ASTModifier mAlter (A.Structured A.ExpressionList) structType) ->
|
addNewSubProcFunc :: (Monad mLabel, Monad mAlter) =>
|
||||||
|
Meta -> [A.Formal] -> Either (A.Process, ASTModifier mAlter A.Process structType) (A.Structured A.ExpressionList, ASTModifier mAlter (A.Structured A.ExpressionList) structType) ->
|
||||||
ASTModifier mAlter [A.Formal] structType -> GraphMaker mLabel mAlter label structType ()
|
ASTModifier mAlter [A.Formal] structType -> GraphMaker mLabel mAlter label structType ()
|
||||||
addNewSubProcFunc m args body argsRoute
|
addNewSubProcFunc m args body argsRoute
|
||||||
= do root <- addNode' m labelStartNode (m, args) (AlterArguments argsRoute)
|
= do root <- addNode' m labelStartNode (m, args) (AlterArguments argsRoute)
|
||||||
denoteRootNode root
|
denoteRootNode root
|
||||||
bodyNode <- case body of
|
bodyNode <- case body of
|
||||||
|
@ -418,15 +411,15 @@ buildFlowGraph funcs s
|
||||||
where
|
where
|
||||||
buildEL m _ r el = addNodeExpressionList m el r >>* mkPair
|
buildEL m _ r el = addNodeExpressionList m el r >>* mkPair
|
||||||
|
|
||||||
buildProcess :: A.Process -> ASTModifier mAlter A.Process structType -> GraphMaker mLabel mAlter label structType (Node, Node)
|
buildProcess :: (Monad mLabel, Monad mAlter) => A.Process -> ASTModifier mAlter A.Process structType -> GraphMaker mLabel mAlter label structType (Node, Node)
|
||||||
buildProcess (A.Seq m s) route
|
buildProcess (A.Seq m s) route
|
||||||
= do s <- buildStructuredP OSeq s (route22 route A.Seq)
|
= do s <- buildStructuredP OSeq s (route22 route A.Seq)
|
||||||
case s of
|
case s of
|
||||||
Left True -> throwError $ show m ++ " SEQ had non-joined up body when building flow-graph"
|
Left True -> throwError $ show m ++ " SEQ had non-joined up body when building flow-graph"
|
||||||
Left False -> do n <- addDummyNode m
|
Left False -> do n <- addDummyNode m
|
||||||
return (n, n)
|
return (n, n)
|
||||||
Right ns -> return ns
|
Right ns -> return ns
|
||||||
buildProcess (A.Par m _ s) route
|
buildProcess (A.Par m _ s) route
|
||||||
= do nStart <- addDummyNode m
|
= do nStart <- addDummyNode m
|
||||||
nEnd <- addDummyNode m
|
nEnd <- addDummyNode m
|
||||||
pId <- getNextParEdgeId
|
pId <- getNextParEdgeId
|
||||||
|
@ -438,23 +431,53 @@ buildFlowGraph funcs s
|
||||||
do addEdge (EStartPar pId) nStart start
|
do addEdge (EStartPar pId) nStart start
|
||||||
addEdge (EEndPar pId) end nEnd
|
addEdge (EEndPar pId) end nEnd
|
||||||
return (nStart, nEnd)
|
return (nStart, nEnd)
|
||||||
buildProcess (A.While _ e p) route
|
buildProcess (A.While _ e p) route
|
||||||
= do n <- addNodeExpression (findMeta e) e (route23 route A.While)
|
= do n <- addNodeExpression (findMeta e) e (route23 route A.While)
|
||||||
(start, end) <- buildProcess p (route33 route A.While)
|
(start, end) <- buildProcess p (route33 route A.While)
|
||||||
addEdge ESeq n start
|
addEdge ESeq n start
|
||||||
addEdge ESeq end n
|
addEdge ESeq end n
|
||||||
return (n, n)
|
return (n, n)
|
||||||
buildProcess (A.Case m e s) route
|
buildProcess (A.Case m e s) route
|
||||||
= do nStart <- addNodeExpression (findMeta e) e (route23 route A.Case)
|
= do nStart <- addNodeExpression (findMeta e) e (route23 route A.Case)
|
||||||
nEnd <- addDummyNode m
|
nEnd <- addDummyNode m
|
||||||
buildStructuredO (OCase (nStart,nEnd)) s (route33 route A.Case)
|
buildStructuredO (OCase (nStart,nEnd)) s (route33 route A.Case)
|
||||||
return (nStart, nEnd)
|
return (nStart, nEnd)
|
||||||
buildProcess (A.If m s) route
|
buildProcess (A.If m s) route
|
||||||
= do nStart <- addDummyNode m
|
= do nStart <- addDummyNode m
|
||||||
nEnd <- addDummyNode m
|
nEnd <- addDummyNode m
|
||||||
buildStructuredC (OIf nStart nEnd) s (route22 route A.If)
|
buildStructuredC (OIf nStart nEnd) s (route22 route A.If)
|
||||||
return (nStart, nEnd)
|
return (nStart, nEnd)
|
||||||
buildProcess p route = addNode' (findMeta p) labelProcess p (AlterProcess route) >>* mkPair
|
buildProcess p route = addNode' (findMeta p) labelProcess p (AlterProcess route) >>* mkPair
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Builds a control-flow-graph. The mAlter monad is the monad in which
|
||||||
|
-- AST alterations would take place. Note that mAlter does not feature in
|
||||||
|
-- the parameters, only in the result. The mLabel monad is the monad in
|
||||||
|
-- which the labelling must be done; hence the flow-graph is returned inside
|
||||||
|
-- the label monad.
|
||||||
|
buildFlowGraph :: forall mLabel mAlter label structType. (Monad mLabel, Monad mAlter, Data structType) =>
|
||||||
|
GraphLabelFuncs mLabel label ->
|
||||||
|
A.Structured structType ->
|
||||||
|
mLabel (Either String (FlowGraph' mAlter label structType, [Node]))
|
||||||
|
buildFlowGraph funcs s
|
||||||
|
= do res <- flip runStateT (0, 0, ([],[]), []) $ flip runReaderT funcs $ runErrorT $ buildStructured (\_ _ _ -> throwError "Did not expect outer-most node to exist in AST") ONone s id
|
||||||
|
return $ case res of
|
||||||
|
(Left err,_) -> Left err
|
||||||
|
(Right (Left {}),(_,_,(nodes, edges),roots)) -> Right (mkGraph nodes edges, roots)
|
||||||
|
(Right (Right (root,_)),(_,_,(nodes, edges),roots)) -> Right (mkGraph nodes edges, root : roots)
|
||||||
|
|
||||||
|
buildFlowGraphP :: forall mLabel mAlter label. (Monad mLabel, Monad mAlter) =>
|
||||||
|
GraphLabelFuncs mLabel label ->
|
||||||
|
A.Structured A.Process ->
|
||||||
|
mLabel (Either String (FlowGraph' mAlter label A.Process, [Node]))
|
||||||
|
buildFlowGraphP funcs s
|
||||||
|
= do res <- flip runStateT (0, 0, ([],[]), []) $ flip runReaderT funcs $ runErrorT $ buildStructuredP ONone s id
|
||||||
|
return $ case res of
|
||||||
|
(Left err,_) -> Left err
|
||||||
|
(Right (Left {}),(_,_,(nodes, edges),roots)) -> Right (mkGraph nodes edges, roots)
|
||||||
|
(Right (Right (root,_)),(_,_,(nodes, edges),roots)) -> Right (mkGraph nodes edges, root : roots)
|
||||||
|
|
||||||
|
|
||||||
decomp22 :: (Monad m, Data a, Typeable a0, Typeable a1) => (a0 -> a1 -> a) -> (a1 -> m a1) -> (a -> m a)
|
decomp22 :: (Monad m, Data a, Typeable a0, Typeable a1) => (a0 -> a1 -> a) -> (a1 -> m a1) -> (a -> m a)
|
||||||
decomp22 con f1 = decomp2 con return f1
|
decomp22 con f1 = decomp2 con return f1
|
||||||
|
|
|
@ -112,7 +112,7 @@ testGraph testName nodes roots edges proc = testGraph' testName nodes roots edge
|
||||||
testGraph' :: String -> [(Int, Meta)] -> [Int] -> [(Int, Int, EdgeLabel)] -> A.Structured A.Process -> Test
|
testGraph' :: String -> [(Int, Meta)] -> [Int] -> [(Int, Int, EdgeLabel)] -> A.Structured A.Process -> Test
|
||||||
testGraph' testName nodes roots edges code
|
testGraph' testName nodes roots edges code
|
||||||
= TestCase $
|
= TestCase $
|
||||||
case evalState (buildFlowGraph testOps code) Map.empty of
|
case evalState (buildFlowGraphP testOps code) Map.empty of
|
||||||
Left err -> assertFailure (testName ++ " graph building failed: " ++ err)
|
Left err -> assertFailure (testName ++ " graph building failed: " ++ err)
|
||||||
Right gr -> checkGraphEquality (nodes, roots, edges) (gr :: (FlowGraph' Identity Int A.Process, [Node]))
|
Right gr -> checkGraphEquality (nodes, roots, edges) (gr :: (FlowGraph' Identity Int A.Process, [Node]))
|
||||||
where
|
where
|
||||||
|
@ -624,8 +624,8 @@ genProcess' = (1, genProcess)
|
||||||
|
|
||||||
-- | Generates a flow-graph from the given AST.
|
-- | Generates a flow-graph from the given AST.
|
||||||
-- TODO put this in proper error monad
|
-- TODO put this in proper error monad
|
||||||
genGraph :: Data a => A.Structured a -> FlowGraph' Identity () a
|
genGraph :: A.Structured A.Process -> FlowGraph' Identity () A.Process
|
||||||
genGraph s = either (\e -> error $ "QuickCheck graph did not build properly: " ++ e ++ ", from: " ++ pshow s) fst $ runIdentity $ buildFlowGraph funcs s
|
genGraph s = either (\e -> error $ "QuickCheck graph did not build properly: " ++ e ++ ", from: " ++ pshow s) fst $ runIdentity $ buildFlowGraphP funcs s
|
||||||
where
|
where
|
||||||
funcs :: GraphLabelFuncs Identity ()
|
funcs :: GraphLabelFuncs Identity ()
|
||||||
funcs = mkLabelFuncsConst (return ())
|
funcs = mkLabelFuncsConst (return ())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user