diff --git a/checks/Check.hs b/checks/Check.hs index 658eed6..31a165c 100644 --- a/checks/Check.hs +++ b/checks/Check.hs @@ -143,13 +143,17 @@ showCodeExSet (NormalSet s) -- | Checks that no variable is used uninitialised. That is, it checks that every variable is written to before it is read. checkInitVar :: forall m. (Monad m, Die m, CSM m) => Meta -> FlowGraph m (Maybe Decl, Vars) -> Node -> m () checkInitVar m graph startNode - = do vwb <- case flowAlgorithm graphFuncs (dfs [startNode] graph) startNode of + = do startLabel <- checkJust (Just m, "Could not find starting node in the control-flow graph") + (lab graph startNode) >>* writeNode + vwb <- case flowAlgorithm graphFuncs connectedNodes (startNode, startLabel) of Left err -> dieP m $ "Error building control-flow graph: " ++ err Right x -> return x -- vwb is a map from Node to a set of Vars that have been written by that point -- Now we check that for every variable read in each node, it has already been written to by then mapM_ (checkInitVar' vwb) (map readNode (labNodes graph)) where + connectedNodes = dfs [startNode] graph + -- Gets all variables read-from in a particular node, and the node identifier readNode :: (Node, FNode m (Maybe Decl, Vars)) -> (Node, ExSet Var) readNode (n, Node (_,(_,Vars read _ _),_)) = (n,NormalSet read) @@ -170,7 +174,6 @@ checkInitVar m graph startNode nodeFunc = nodeFunction ,prevNodes = lpre graph ,nextNodes = lsuc graph - ,initVal = emptySet ,defVal = Everything } diff --git a/checks/UsageCheckAlgorithms.hs b/checks/UsageCheckAlgorithms.hs index 1ecf621..5defc77 100644 --- a/checks/UsageCheckAlgorithms.hs +++ b/checks/UsageCheckAlgorithms.hs @@ -98,7 +98,7 @@ checkPar f g = map f allParItems -- | Returns either an error, or map *from* the node with a read, *to* the node whose definitions might be available at that point findReachDef :: forall m. Monad m => FlowGraph m (Maybe Decl, Vars) -> Node -> Either String (Map.Map Node (Map.Map Var (Set.Set Node))) findReachDef graph startNode - = do r <- flowAlgorithm graphFuncs (nodes graph) startNode + = do r <- flowAlgorithm graphFuncs (nodes graph) (startNode, Map.empty) -- These lines remove the maps where the variable is not read in that particular node: let r' = Map.mapWithKey (\n -> Map.filterWithKey (readInNode' n)) r return $ Map.filter (not . Map.null) r' @@ -109,7 +109,6 @@ findReachDef graph startNode nodeFunc = processNode ,prevNodes = lpre graph ,nextNodes = lsuc graph - ,initVal = Map.empty ,defVal = Map.empty } diff --git a/common/FlowAlgorithms.hs b/common/FlowAlgorithms.hs index 30cec25..f43da52 100644 --- a/common/FlowAlgorithms.hs +++ b/common/FlowAlgorithms.hs @@ -28,7 +28,6 @@ data GraphFuncs n e a = GF { nodeFunc :: (n,e) -> a -> Maybe a -> a ,prevNodes :: n -> [(n,e)] ,nextNodes :: n -> [(n,e)] - ,initVal :: a -- defVal should be the unit of the aggregation. That is, if (nodeFunc a b) == defVal, then (nodeFunc a b defVal) == defVal too -- TODO not sure if the above is still true ,defVal :: a @@ -39,11 +38,11 @@ data GraphFuncs n e a = GF { -- | Given the graph functions, a list of nodes and an entry node, performs -- an iterative data-flow analysis. All the nodes in the list should be connected to -- the entry node, and there should be no nodes without predecessors in the list. -flowAlgorithm :: forall n e a. (Ord n, Show n, Eq a) => GraphFuncs n e a -> [n] -> n -> Either String (Map.Map n a) -flowAlgorithm funcs nodes startNode +flowAlgorithm :: forall n e a. (Ord n, Show n, Eq a) => GraphFuncs n e a -> [n] -> (n, a) -> Either String (Map.Map n a) +flowAlgorithm funcs nodes (startNode, startVal) = iterate (Set.fromList nonStartNodes) - (Map.fromList $ (startNode,initVal funcs):(zip nonStartNodes (repeat (defVal funcs)))) + (Map.fromList $ (startNode, startVal):(zip nonStartNodes (repeat (defVal funcs)))) where nonStartNodes = (filter ((/=) startNode) nodes)