Changed the types involved in the control-flow graph so that I can customise the Show implementation

This commit is contained in:
Neil Brown 2007-10-28 11:35:51 +00:00
parent a0c54220e2
commit cf17814b98
2 changed files with 23 additions and 8 deletions

View File

@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>. with this program. If not, see <http://www.gnu.org/licenses/>.
-} -}
module FlowGraph (EdgeLabel(..), FlowGraph, buildFlowGraph) where module FlowGraph (EdgeLabel(..), FNode(..), FlowGraph, buildFlowGraph, makeFlowGraphInstr) where
import Control.Monad.Error import Control.Monad.Error
import Control.Monad.State import Control.Monad.State
@ -31,15 +31,21 @@ data EdgeLabel = EChoice | ESeq | EPar deriving (Show, Eq, Ord)
data OuterType = None | Seq | Par data OuterType = None | Seq | Par
type FNode a = (Meta, a) newtype FNode a = Node (Meta, a)
--type FEdge = (Node, EdgeLabel, Node) --type FEdge = (Node, EdgeLabel, Node)
instance Show a => Show (FNode a) where
show (Node (m,x)) = (filter ((/=) '\"')) $ show m ++ ":" ++ show x
type FlowGraph a = Gr (FNode a) EdgeLabel type FlowGraph a = Gr (FNode a) EdgeLabel
type NodesEdges a = ([LNode (FNode a)],[LEdge EdgeLabel]) type NodesEdges a = ([LNode (FNode a)],[LEdge EdgeLabel])
type GraphMaker m a b = ErrorT String (StateT (Node, NodesEdges a) m) b type GraphMaker m a b = ErrorT String (StateT (Node, NodesEdges a) m) b
-- | Builds the instructions to send to GraphViz
makeFlowGraphInstr :: Show a => FlowGraph a -> String
makeFlowGraphInstr = graphviz'
-- The primary reason for having the blank generator take a Meta as an argument is actually for testing. But other uses can simply ignore it if they want. -- The primary reason for having the blank generator take a Meta as an argument is actually for testing. But other uses can simply ignore it if they want.
buildFlowGraph :: Monad m => (Meta -> m a) -> (forall t. Data t => t -> m a) -> A.Structured -> m (Either String (FlowGraph a)) buildFlowGraph :: Monad m => (Meta -> m a) -> (forall t. Data t => t -> m a) -> A.Structured -> m (Either String (FlowGraph a))
@ -51,9 +57,9 @@ buildFlowGraph blank f s
where where
-- All the functions return the new graph, and the identifier of the node just added -- All the functions return the new graph, and the identifier of the node just added
addNode :: Monad m => FNode a -> GraphMaker m a Node addNode :: Monad m => (Meta, a) -> GraphMaker m a Node
addNode x = do (n,(nodes, edges)) <- get addNode x = do (n,(nodes, edges)) <- get
put (n+1, ((n, x):nodes, edges)) put (n+1, ((n, Node x):nodes, edges))
return n return n
addEdge :: Monad m => EdgeLabel -> Node -> Node -> GraphMaker m a () addEdge :: Monad m => EdgeLabel -> Node -> Node -> GraphMaker m a ()
@ -71,7 +77,9 @@ buildFlowGraph blank f s
buildStructured outer (A.Several m ss) buildStructured outer (A.Several m ss)
= do nodes <- mapM (buildStructured outer) ss = do nodes <- mapM (buildStructured outer) ss
case outer of case outer of
None -> throwError "Cannot handle Several without an outer context" None -> -- If there is no context, they should be left as disconnected graphs.
do n <- addDummyNode m
return (n, n)
Seq -> do sequence_ $ mapPairs (\(_,s) (e,_) -> addEdge ESeq s e) nodes Seq -> do sequence_ $ mapPairs (\(_,s) (e,_) -> addEdge ESeq s e) nodes
case nodes of case nodes of
[] -> do n <- addDummyNode m [] -> do n <- addDummyNode m

View File

@ -30,12 +30,13 @@ import Test.HUnit hiding (Node, State)
import qualified AST as A import qualified AST as A
import FlowGraph import FlowGraph
import Metadata import Metadata
import TestUtil
import Utils import Utils
makeMeta :: Int -> Meta makeMeta :: Int -> Meta
makeMeta n = Meta (Just "FlowGraphTest") n 0 makeMeta n = Meta (Just "FlowGraphTest") n 0
-- To make typing the tests as short as possible: -- To make typing the tests as short as possible (typing a function call means bracketing is needed, which is a pain):
m0 = makeMeta 0 m0 = makeMeta 0
m1 = makeMeta 1 m1 = makeMeta 1
m2 = makeMeta 2 m2 = makeMeta 2
@ -84,9 +85,15 @@ testGraph testName nodes edges proc
-- Checks two graphs are equal by creating a node mapping from the expected graph to the real map (checkNodeEquality), -- Checks two graphs are equal by creating a node mapping from the expected graph to the real map (checkNodeEquality),
-- then mapping the edges across (transformEdge) and checking everything is right (in checkGraphEquality) -- then mapping the edges across (transformEdge) and checking everything is right (in checkGraphEquality)
checkGraphEquality :: (Graph g, Show b, Ord b) => ([(Int, Meta)], [(Int, Int, b)]) -> g (Meta, Int) b -> Assertion deNode :: FNode a -> (Meta, a)
deNode (Node x) = x
mapPair :: (x -> a) -> (y -> b) -> (x,y) -> (a,b)
mapPair f g (x,y) = (f x, g y)
checkGraphEquality :: (Graph g, Show b, Ord b) => ([(Int, Meta)], [(Int, Int, b)]) -> g (FNode Int) b -> Assertion
checkGraphEquality (nodes, edges) g checkGraphEquality (nodes, edges) g
= do let (remainingNodes, nodeLookup, ass) = foldl checkNodeEquality (Map.fromList (map revPair nodes),Map.empty, return ()) (labNodes g) = do let (remainingNodes, nodeLookup, ass) = foldl checkNodeEquality (Map.fromList (map revPair nodes),Map.empty, return ()) (map (mapPair id deNode) $ labNodes g)
ass ass
assertBool (testName ++ " Test graph had nodes not found in the real graph: " ++ show remainingNodes ++ ", real graph: " ++ showGraph g) (Map.null remainingNodes) assertBool (testName ++ " Test graph had nodes not found in the real graph: " ++ show remainingNodes ++ ", real graph: " ++ showGraph g) (Map.null remainingNodes)
edges' <- mapM (transformEdge nodeLookup) edges edges' <- mapM (transformEdge nodeLookup) edges