module Flite.CallGraph (CallGraph, callReachableGraph, reachable) where
import Flite.Syntax
import Flite.Traversals
import Data.List
type CallGraph = [(Id, [Id])]
callReachableGraph :: Prog -> CallGraph
callReachableGraph p = fixPoint step (zip fs cs)
where
fs = map funcName p
cs = map (nub . calls . funcRhs) p
reachable :: CallGraph -> Id -> [Id]
reachable g f = case lookup f g of { Nothing -> [] ; Just gs -> gs }
step :: CallGraph -> Maybe CallGraph
step g
| any snd joined = Just (map fst joined)
| otherwise = Nothing
where joined = map (join g) g
join :: CallGraph -> (Id, [Id]) -> ((Id, [Id]), Bool)
join g (f, fs) = ((f, reached), length fs < length reached)
where reached = nub (fs ++ concatMap (reachable g) fs)
fixPoint :: (a -> Maybe a) -> a -> a
fixPoint f a = case f a of { Nothing -> a ; Just b -> fixPoint f b }