module KennedyWarren where
import Prelude hiding (init, succ)
import CommonTypes
import Pretty
import Knuth1
import ExecutionPlan
import Debug.Trace
import Control.Monad.ST
import Control.Monad.State
import Control.Monad.Error
import Data.STRef
import Data.Maybe
import Data.List (intersperse, groupBy, partition, sortBy)
import Data.Ord
import qualified ErrorMessages as Err
import PrintErrorMessages ()
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Map (Map)
import qualified Data.Map as Map
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
kennedyWarrenLazy :: Options -> Set NontermIdent -> [NontDependencyInformation] -> TypeSyns -> Derivings -> ExecutionPlan
kennedyWarrenLazy _ wr ndis typesyns derivings = plan where
plan = ExecutionPlan nonts typesyns wr derivings
nonts = zipWith mkNont ndis nontIds
nontIds = enumFromThen 1 4
initvMap = Map.fromList $ zipWith (\ndi initv -> (ndiNonterminal ndi, initv)) ndis nontIds
mkNont ndi initv = nont where
nont = ENonterminal
(ndiNonterminal ndi)
(ndiParams ndi)
(ndiClassCtxs ndi)
initst
(Just initv)
nextMap
prevMap
prods
(ndiRecursive ndi)
(ndiHoInfo ndi)
initst = initv + 1
finals = initv + 2
nextMap = Map.fromList [(initst, OneVis initv), (finals, NoneVis)]
prevMap = Map.fromList [(initst, NoneVis), (finals, OneVis initv)]
prods = map mkProd (ndiProds ndi)
mkProd pdi = prod where
prod = EProduction
(pdgProduction pdi)
(pdgParams pdi)
(pdgConstraints pdi)
(pdgRules pdi)
(pdgChilds pdi)
visits
visits = [vis]
vis = Visit initv initst finals inh syn steps kind
inh = Set.fromList $ ndiInh ndi
syn = Set.fromList $ ndiSyn ndi
kind = VisitPure False
steps = childSteps ++ invokeSteps ++ ruleSteps
childSteps = [ ChildIntro nm | EChild nm _ _ _ _ _ <- pdgChilds pdi ]
invokeSteps = [ ChildVisit nm nt v
| EChild nm tp _ _ _ _ <- pdgChilds pdi
, let nt = extractNonterminal tp
v = Map.findWithDefault (error "child not in initv-map") nt initvMap
]
ruleSteps = [ Sem nm | (ERule nm _ _ _ _ _ _ _) <- pdgRules pdi ]
kennedyWarrenOrder :: Options -> Set NontermIdent -> [NontDependencyInformation] -> TypeSyns -> Derivings -> Either Err.Error (ExecutionPlan, PP_Doc, PP_Doc)
kennedyWarrenOrder opts wr ndis typesyns derivings = runST $ runErrorT $ do
indi <- lift $ mapM mkNontDependencyInformationM ndis
lift $ knuth1 indi
forM_ indi $ \ndi -> do
let nont = ndiNonterminal . ndimOrig $ ndi
let g = ndgmDepGraph . ndimDepGraph $ ndi
ntCycVerts <- lift $ graphCyclicVerticesExt g
when (not $ null ntCycVerts) $ do
throwError $ Err.Cyclic nont Nothing (map show ntCycVerts)
trc <- lift $ graphIsTRC g
when (not trc) $ do
let msg = "Nonterminal graph " ++ show nont ++ " is not transitively closed!"
fail msg
cons <- lift $ graphCheckConsistency g
when (not cons) $ do
let msg = "Nonterminal graph " ++ show nont ++ " is not consistent!"
fail msg
forM_ (ndimProds ndi) $ \prod -> do
let pr = pdgProduction $ pdgmOrig prod
let g' = pdgmDepGraph $ prod
pdCycVerts <- lift $ graphCyclicVerticesExt g'
when (not $ null pdCycVerts) $ do
throwError $ Err.Cyclic nont (Just pr) (map show pdCycVerts)
trc' <- lift $ graphIsTRC g'
when (not trc') $ do
lift $ traceST $ "Production graph " ++ show pr ++ " of nonterminal "
++ show nont ++ " is not transitively closed!"
fail "Production graph is not transitively closed."
consistent <- lift $ graphCheckConsistency g'
when (not consistent) $ do
let msg = "Production graph " ++ show pr ++ " of nonterminal "
++ show nont ++ " is not consistent!"
fail msg
lift $ do
indi' <- undoTransitiveClosure indi
gvs <- mapM toGVNontDependencyInfo indi'
(ret, visitg) <- runVG $ do
initvs <- kennedyWarrenVisitM wr indi'
nodes <- gets vgNodeNum
edges <- gets vgEdgeNum
when (not $ beQuiet opts) $ do
traceVG $ "Number of nodes = " ++ show nodes
traceVG $ "Number of edges = " ++ show edges
ex <- kennedyWarrenExecutionPlan opts indi' initvs wr typesyns derivings
visitg <- toGVVisitGraph
return (ex,visitg)
return (ret, vlist gvs, visitg)
toGVVertex :: Bool -> Vertex -> ST s PP_Doc
toGVVertex l (VAttr t a b) = return $ (text $ "attr_" ++ show t ++ "_" ++ show a ++ "_" ++ show b) >#< if l
then text ("[shape=box,label=\"" ++ show t ++ " @" ++ show a ++ "." ++ show b ++ "\"]") else empty
toGVVertex l (VChild c) = return $ (text $ "child_" ++ show c) >#< if l
then text ("[shape=ellipse,label=\"Child " ++ show c ++ "\"]") else empty
toGVVertex l (VRule r) = return $ (text $ "rule_" ++ show r) >#< if l
then text ("[shape=diamond,label=\"" ++ show r ++ "\"]") else empty
toGVEdge :: Edge -> ST s PP_Doc
toGVEdge (v1, v2) = do r1 <- toGVVertex False v1
r2 <- toGVVertex False v2
return $ r1 >|< text "->" >#< r2
toGVNontDependencyInfo :: NontDependencyInformationM s -> ST s PP_Doc
toGVNontDependencyInfo ndi = do dg <- return $ ndgmDepGraph . ndimDepGraph $ ndi
verts <- graphVertices dg
edges <- graphEdges dg
vtexts <- mapM (toGVVertex True) verts
etexts <- mapM toGVEdge edges
ptexts <- mapM toGVProdDependencyGraph (ndimProds ndi)
return $ (text ("digraph ndg_" ++ show (ndiNonterminal $ ndimOrig ndi) ++ " {")
>-<
vlist vtexts
>-<
vlist etexts
>-<
text "}"
>-<
text ""
>-<
vlist ptexts)
toGVProdDependencyGraph :: ProdDependencyGraphM s -> ST s PP_Doc
toGVProdDependencyGraph pdg = do dg <- return $ pdgmDepGraph pdg
verts <- graphVertices dg
edges <- graphEdges dg
vtexts <- mapM (toGVVertex True) verts
etexts <- mapM toGVEdge edges
return $ (text ("digraph pdg_" ++ show (pdgProduction $ pdgmOrig pdg) ++ " {")
>-<
(vlist vtexts)
>-<
(vlist etexts)
>-<
text ("info [shape=box,label=\"" ++ show (pdgChildMap $ pdgmOrig pdg) ++ "\"];")
>-<
text "}"
>-<
text "")
toGVVisitGraph :: VG s PP_Doc
toGVVisitGraph = do
ndis <- gets vgNDI
noded <- forM (IntMap.toList ndis) $ \(n,rndi) -> do
ndi <- vgInST $ readSTRef rndi
return $ "node_" >|< n >#< "[label=\"" >|< ndiNonterminal (ndimOrig ndi) >|< "_" >|< n >|< "\"];"
edges <- gets vgEdges
edged <- forM (IntMap.toList edges) $ \(edg,(VGNode from,VGNode to)) -> do
inh <- getInherited (VGEdge edg)
syn <- getSynthesized (VGEdge edg)
return $ "node_" >|< from >#< "-> node_" >|< to >#< "[label=\"visit v" >|< edg
>|< "\\ninh:" >#< (concat $ intersperse ", " $ map show $ Set.toList inh) >|< "\\nsyn: " >|< (concat $ intersperse ", " $ map show $ Set.toList syn) >|< "\"];"
return $ "digraph visitgraph { " >-< vlist noded >-< vlist edged >-< "}"
newtype VGNode = VGNode Int deriving (Show,Eq,Ord)
newtype VGEdge = VGEdge Int deriving (Show,Eq,Ord)
newtype VGProd = VGProd (VGEdge,Int) deriving (Show,Eq,Ord)
data VGState s = VGState { vgNodeNum :: Int
, vgEdgeNum :: Int
, vgOutgoing :: IntMap (STRef s (Set VGEdge))
, vgIncoming :: IntMap (Maybe VGEdge)
, vgNDI :: IntMap (STRef s (NontDependencyInformationM s))
, vgInhSynNode :: Map (Identifier, Set Identifier, Set Identifier) VGNode
, vgNodeInhSyn :: IntMap (Set Identifier, Set Identifier)
, vgInitial :: Map Identifier VGNode
, vgEdges :: IntMap (VGNode, VGNode)
, vgEdgesR :: Map (VGNode,VGNode) VGEdge
, vgInherited :: IntMap (Set Identifier)
, vgSynthesized :: IntMap (Set Identifier)
, vgPending :: IntSet
, vgChildVisits :: IntMap (STRef s (Map (Identifier,Int) [VGNode]))
, vgFinalVertices :: IntMap (STRef s (Set (Vertex,Int)))
, vgProdVisits :: Map (Identifier,Identifier,VGEdge) (STRef s [VisitStep])
}
type VG s a = ErrorT String (StateT (VGState s) (ST s)) a
runVG :: VG s a -> ST s a
runVG vg = do (Right a,_) <- runStateT (runErrorT vg) vgEmptyState
return a
insertInitialNode :: NontDependencyInformationM s -> VG s VGNode
insertInitialNode ndi = do
rndi <- vgInST $ newSTRef ndi
(VGNode node) <- vgCreateNode rndi Set.empty Set.empty
initial <- gets vgInitial
incoming <- gets vgIncoming
modify $ \st -> st { vgInitial = Map.insert (ndiNonterminal $ ndimOrig ndi) (VGNode node) initial
, vgIncoming = IntMap.insert node Nothing incoming }
return (VGNode node)
createPending :: VGNode -> Set Identifier -> Set Identifier -> VG s VGEdge
createPending vgn@(VGNode n) inh syn = do
ninhsyn <- gets vgNodeInhSyn
let (pinh,psyn) = imLookup n ninhsyn
let ninh = Set.union pinh inh
let nsyn = Set.union psyn syn
mndi <- gets vgNDI
let rndi = imLookup n mndi
ndi <- vgInST $ readSTRef rndi
inhsynn <- gets vgInhSynNode
case Map.lookup (ndiNonterminal $ ndimOrig ndi, ninh, nsyn) inhsynn of
Just tn -> do
when (tn == vgn) $ do traceVG $ "Source and target nodes are the same!"
traceVG $ "Maybe there is a wrapper with no inherited or synthesized attributes."
traceVG $ "Inh: " ++ show inh
traceVG $ "Syn: " ++ show syn
traceVG $ "PInh: " ++ show pinh
traceVG $ "PSyn: " ++ show psyn
edgesr <- gets vgEdgesR
case Map.lookup (vgn,tn) edgesr of
Just e -> return e
Nothing -> vgCreatePendingEdge vgn tn inh syn
Nothing -> do
tn <- vgCreateNode rndi ninh nsyn
vgCreatePendingEdge vgn tn inh syn
selectPending :: VG s VGEdge
selectPending = do
pending <- gets vgPending
incoming <- gets vgIncoming
edges <- gets vgEdges
let readyPend = filter (\p -> let (VGNode fr,_) = imLookup p edges
in isJust $ IntMap.lookup fr incoming) $ IntSet.toList pending
guard $ not $ null readyPend
return $ VGEdge $ head $ readyPend
getInherited :: VGEdge -> VG s (Set Identifier)
getInherited (VGEdge edg) = do
inhs <- gets vgInherited
return $ imLookup edg inhs
getSynthesized :: VGEdge -> VG s (Set Identifier)
getSynthesized (VGEdge edg) = do
syns <- gets vgSynthesized
return $ imLookup edg syns
markFinal :: VGEdge -> VG s ()
markFinal vgedg@(VGEdge edg) = do
incoming <- gets vgIncoming
edges <- gets vgEdges
pending <- gets vgPending
let (_,VGNode to) = imLookup edg edges
modify $ \st -> st { vgIncoming = IntMap.insert to (Just vgedg) incoming
, vgPending = IntSet.delete edg pending }
getProductions :: VGEdge -> VG s [VGProd]
getProductions vedg@(VGEdge edg) = do
edges <- gets vgEdges
let (VGNode fr,_) = imLookup edg edges
ndis <- gets vgNDI
let rndi = imLookup fr ndis
ndi <- vgInST $ readSTRef rndi
return $ map (\x -> VGProd (vedg,x)) [0..(length $ ndimProds ndi)1]
onMarkedDepGraph :: (ProdDependencyGraphM s -> ST s a) -> VGProd -> VG s a
onMarkedDepGraph f (VGProd (VGEdge edg, n)) = do
edges <- gets vgEdges
let (VGNode fr,_) = imLookup edg edges
ndis <- gets vgNDI
let rndi = imLookup fr ndis
ndi <- vgInST $ readSTRef rndi
vgInST $ f $ (ndimProds ndi) !! n
isDepGraphVertexFinal :: VGProd -> Vertex -> VG s Bool
isDepGraphVertexFinal (VGProd (VGEdge edg, p)) v = do
edges <- gets vgEdges
let (from,_) = imLookup edg edges
vgDepGraphVertexFinal from p v
setDepGraphVerticesFinal :: VGProd -> [Vertex] -> VG s ()
setDepGraphVerticesFinal (VGProd (VGEdge edg, p)) vs = do
edges <- gets vgEdges
let (_,VGNode to) = imLookup edg edges
finalv <- gets vgFinalVertices
let rfinalv = imLookup to finalv
vgInST $ modifySTRef rfinalv $ Set.union (Set.fromList $ map (\v -> (v,p)) vs)
addChildVisit :: VGProd -> Identifier -> VGEdge -> VG s VisitStep
addChildVisit (VGProd (VGEdge edg, p)) ide (VGEdge vs) = do
edges <- gets vgEdges
let (VGNode from,vgto) = imLookup vs edges
childvs <- gets vgChildVisits
let rchildv = imLookup edg childvs
vgInST $ modifySTRef rchildv $ Map.insertWith' (++) (ide,p) [vgto]
ndis <- gets vgNDI
let rndi = imLookup from ndis
ndi <- vgInST $ readSTRef rndi
let nt = ndiNonterminal $ ndimOrig ndi
return $ ChildVisit ide nt vs
addVisitStep :: VGProd -> VisitStep -> VG s ()
addVisitStep (VGProd (VGEdge edg, p)) st = do
edges <- gets vgEdges
let (VGNode fr,_) = imLookup edg edges
ndis <- gets vgNDI
let rndi = imLookup fr ndis
ndi <- vgInST $ readSTRef rndi
prodvs <- gets vgProdVisits
let nont = ndiNonterminal $ ndimOrig ndi
let prod = pdgProduction $ pdgmOrig $ ndimProds ndi !! p
let Just rprodv = Map.lookup (nont, prod, VGEdge edg) prodvs
vgInST $ modifySTRef rprodv (++ [st])
getChildState :: VGProd -> Identifier -> VG s VGNode
getChildState (VGProd (VGEdge edg,p)) ide = do
childvs <- gets vgChildVisits
let rchildv = imLookup edg childvs
childv <- vgInST $ readSTRef rchildv
case Map.lookup (ide,p) childv of
Just (n:_) -> return n
_ -> do
edges <- gets vgEdges
let (VGNode from,_) = imLookup edg edges
incoming <- gets vgIncoming
case IntMap.lookup from incoming of
Just (Just iedg) -> getChildState (VGProd (iedg,p)) ide
Just Nothing -> do
ndis <- gets vgNDI
let rndi = imLookup from ndis
ndi <- vgInST $ readSTRef rndi
let Just nt = lookup ide $ pdgChildMap $ pdgmOrig $ (ndimProds ndi) !! p
vgFindInitial nt
Nothing -> error "getChildState"
repeatM :: VG s () -> VG s ()
repeatM m = catchError (m >> repeatM m) (const $ return ())
vgInST :: ST s a -> VG s a
vgInST = lift . lift
vgEmptyState :: VGState s
vgEmptyState = VGState { vgNodeNum = 0
, vgEdgeNum = 0
, vgOutgoing = IntMap.empty
, vgIncoming = IntMap.empty
, vgNDI = IntMap.empty
, vgInhSynNode = Map.empty
, vgNodeInhSyn = IntMap.empty
, vgInitial = Map.empty
, vgEdges = IntMap.empty
, vgEdgesR = Map.empty
, vgInherited = IntMap.empty
, vgSynthesized = IntMap.empty
, vgPending = IntSet.empty
, vgChildVisits = IntMap.empty
, vgFinalVertices = IntMap.empty
, vgProdVisits = Map.empty
}
vgCreateNode :: STRef s (NontDependencyInformationM s) -> Set Identifier -> Set Identifier -> VG s VGNode
vgCreateNode rndi inh syn = do
num <- gets vgNodeNum
outgoing <- gets vgOutgoing
inhsyn <- gets vgInhSynNode
ninhsyn <- gets vgNodeInhSyn
ndi <- gets vgNDI
finalv <- gets vgFinalVertices
rout <- vgInST $ newSTRef Set.empty
rfinalv <- vgInST $ newSTRef Set.empty
nndi <- vgInST $ readSTRef rndi
modify $ \st -> st { vgNodeNum = num + 1
, vgOutgoing = IntMap.insert num rout outgoing
, vgInhSynNode = Map.insert (ndiNonterminal $ ndimOrig nndi,inh,syn) (VGNode num) inhsyn
, vgNodeInhSyn = IntMap.insert num (inh,syn) ninhsyn
, vgNDI = IntMap.insert num rndi ndi
, vgFinalVertices = IntMap.insert num rfinalv finalv }
return $ VGNode num
vgCreatePendingEdge :: VGNode -> VGNode -> Set Identifier -> Set Identifier -> VG s VGEdge
vgCreatePendingEdge vgn1@(VGNode n1) vgn2 inh syn = do
num <- gets vgEdgeNum
edges <- gets vgEdges
edgesr <- gets vgEdgesR
inhs <- gets vgInherited
syns <- gets vgSynthesized
outgoing <- gets vgOutgoing
pend <- gets vgPending
childv <- gets vgChildVisits
rchildv <- vgInST $ newSTRef Map.empty
let outr = imLookup n1 outgoing
let ret = VGEdge num
vgInST $ modifySTRef outr (Set.insert ret)
modify $ \st -> st { vgEdgeNum = num + 1
, vgEdges = IntMap.insert num (vgn1,vgn2) edges
, vgEdgesR = Map.insert (vgn1,vgn2) ret edgesr
, vgPending = IntSet.insert num pend
, vgInherited = IntMap.insert num inh inhs
, vgSynthesized = IntMap.insert num syn syns
, vgChildVisits = IntMap.insert num rchildv childv }
ndis <- gets vgNDI
let rndi = imLookup n1 ndis
ndi <- vgInST $ readSTRef rndi
prodv <- gets vgProdVisits
refs <- forM (ndimProds ndi) $ \prod -> do
rprod <- vgInST $ newSTRef []
return ((ndiNonterminal $ ndimOrig ndi, pdgProduction $ pdgmOrig prod, ret),rprod)
modify $ \st -> st { vgProdVisits = Map.union (Map.fromList refs) prodv }
return $ ret
vgDepGraphVertexFinal :: VGNode -> Int -> Vertex -> VG s Bool
vgDepGraphVertexFinal (VGNode n) p v = do
finalv <- gets vgFinalVertices
let rfinalv = imLookup n finalv
curset <- vgInST $ readSTRef rfinalv
if Set.member (v,p) curset
then return True
else do
incoming <- gets vgIncoming
case IntMap.lookup n incoming of
Just (Just (VGEdge edg)) -> do
edges <- gets vgEdges
let (fr,_) = imLookup edg edges
vgDepGraphVertexFinal fr p v
Just Nothing -> return False
Nothing -> error "This can never happen"
vgFindInitial :: Identifier -> VG s VGNode
vgFindInitial nt = do
initial <- gets vgInitial
let Just r = Map.lookup nt initial
return r
imLookup :: Int -> IntMap a -> a
imLookup k m = let Just r = IntMap.lookup k m in r
traceVG :: String -> VG s ()
traceVG s = trace s (return ())
kennedyWarrenVisitM :: Set NontermIdent -> [NontDependencyInformationM s] -> VG s [Maybe Int]
kennedyWarrenVisitM wr ndis = do
initvs <- forM ndis $ \ndi -> do
nd <- insertInitialNode ndi
let inh = Set.fromList $ ndiInh $ ndimOrig ndi
let syn = Set.fromList $ ndiSyn $ ndimOrig ndi
if (Set.member (ndiNonterminal $ ndimOrig $ ndi) wr) && (not (Set.null inh) || not (Set.null syn))
then do
VGEdge initv <- createPending nd inh syn
return $ Just initv
else return Nothing
repeatM $ do
pend <- selectPending
prods <- getProductions pend
inhs <- getInherited pend
syns <- getSynthesized pend
forM_ prods $ \prod -> do
setDepGraphVerticesFinal prod (map createLhsInh . Set.toList $ inhs)
(vis,_) <- foldM (foldChildVisits prod) ([],0) (map createLhsSyn . Set.toList $ syns)
setDepGraphVerticesFinal prod (map fst vis)
vis2 <- correctInhChilds prod vis
extravis <- extraChildSyn prod vis2
setDepGraphVerticesFinal prod (map fst extravis)
let gvis = groupSortBy (comparing snd) $ vis2 ++ extravis
forM_ gvis $ \vis3 -> do
let (chattrs, rules) = partition isChildAttr $ map fst vis3
forM_ (reverse $ rules) $ \rule ->
case rule of
VRule r -> addVisitStep prod $ Sem r
VChild c -> addVisitStep prod $ ChildIntro c
_ -> return ()
let chs = groupSortBy (comparing getAttrChildName) $ chattrs
chvs <- forM chs $ \childvs -> do
let cinhs = map getAttrName $ filter isChildInh childvs
let csyns = map getAttrName $ filter isChildSyn childvs
let cname = getAttrChildName $ head childvs
curstate <- getChildState prod cname
target <- createPending curstate (Set.fromList cinhs) (Set.fromList csyns)
addChildVisit prod cname target
when (not $ null chvs) $
if (length chvs == 1)
then addVisitStep prod $ head chvs
else addVisitStep prod $ Sim chvs
markFinal pend
return initvs
groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]
groupSortBy f = groupBy (\x y -> f x y == EQ) . sortBy f
type ChildVisits = [(Vertex,Int)]
foldChildVisits :: VGProd -> (ChildVisits, Int) -> Vertex -> VG s (ChildVisits, Int)
foldChildVisits prod (vis,i) v = do
(nvis,ni) <- findChildVisits prod v vis
return (nvis, ni `max` i)
findChildVisits :: VGProd -> Vertex -> ChildVisits -> VG s (ChildVisits, Int)
findChildVisits prod v vis = do
case lookup v vis of
Just i -> return (vis,i)
Nothing -> do
final <- isDepGraphVertexFinal prod v
if final
then return (vis,0)
else do
succs <- onMarkedDepGraph (liftM Set.toList . flip graphSuccessors v . pdgmDepGraph) prod
(nvis,ni) <- foldM (foldChildVisits prod) (vis,0) succs
if isChildSyn v
then return ((v,ni + 1) : nvis, ni + 1)
else return ((v,ni) : nvis, ni)
correctInhChilds :: VGProd -> ChildVisits -> VG s ChildVisits
correctInhChilds prod vis =
forM vis $ \(v,i) -> do
if isChildInh v
then do
preds <- onMarkedDepGraph (liftM Set.toList . flip graphPredecessors v . pdgmDepGraph) prod
let ni = foldl min 99999999 $ mapMaybe (`lookup` vis) preds
return (v,ni)
else if not $ isChildSyn v
then do
succs <- onMarkedDepGraph (liftM Set.toList . flip graphSuccessors v . pdgmDepGraph) prod
let ni = foldl max (1) $ mapMaybe (`lookup` vis) succs
return (v,ni+1)
else return (v,i)
extraChildSyn :: VGProd -> ChildVisits -> VG s ChildVisits
extraChildSyn prod vis = do
allpreds <- forM vis $ \(v,_) -> do
if isChildInh v
then do
preds <- onMarkedDepGraph (liftM Set.toList . flip graphPredecessors v . pdgmDepGraph) prod
return $ Set.fromList $ filter isChildSyn preds
else return Set.empty
lextravis <- forM (Set.toList $ Set.unions allpreds) $ \v -> do
ready <- isReadyVertex prod vis v
return $ maybe Nothing (\i -> Just (v,i)) ready
return $ catMaybes lextravis
isReadyVertex :: VGProd -> ChildVisits -> Vertex -> VG s (Maybe Int)
isReadyVertex prod vis v = do
final <- isDepGraphVertexFinal prod v
if v `elem` (map fst vis) || final
then return Nothing
else do
succ <- onMarkedDepGraph (flip graphSuccessors v . pdgmDepGraph) prod
rd <- mapM (\x -> do case lookup x vis of
Just i -> return $ Just i
Nothing -> do fin <- isDepGraphVertexFinal prod x
return $ if fin then Just 1 else Nothing) (Set.toList succ)
if all isJust rd
then return $ Just $ foldl1 max $ catMaybes rd
else return $ Nothing
isChildSyn :: Vertex -> Bool
isChildSyn v = isChildAttr v && getAttrType v == Syn
isChildInh :: Vertex -> Bool
isChildInh v = isChildAttr v && getAttrType v == Inh
isChildAttr :: Vertex -> Bool
isChildAttr v = isVertexAttr v && getAttrChildName v /= _LHS && getAttrType v /= Loc
createLhsInh :: Identifier -> Vertex
createLhsInh = VAttr Inh _LHS
createLhsSyn :: Identifier -> Vertex
createLhsSyn = VAttr Syn _LHS
kennedyWarrenExecutionPlan :: Options -> [NontDependencyInformationM s] -> [Maybe Int] ->
Set NontermIdent -> TypeSyns -> Derivings -> VG s ExecutionPlan
kennedyWarrenExecutionPlan opts ndis initvs wr typesyns derivings = do
nonts <- forM (zip ndis initvs) $ \(ndi, initv) -> do
prods <- forM (ndimProds ndi) $ \prod -> do
let inont = ndiNonterminal $ ndimOrig ndi
let iprod = pdgProduction $ pdgmOrig prod
prodvs <- gets vgProdVisits
let thisvisits = filter (\((int,ipr,_),_) -> int == inont && ipr == iprod) $ Map.toList prodvs
visits <- forM thisvisits $ \((_,_,vgedg@(VGEdge edg)),rprodvs) -> do
edges <- gets vgEdges
let (VGNode fr, VGNode to) = imLookup edg edges
steps <- vgInST $ readSTRef rprodvs
inh <- getInherited vgedg
syn <- getSynthesized vgedg
let kind | monadic opts = VisitMonadic
| otherwise = VisitPure True
return $ Visit edg fr to inh syn steps kind
return $ EProduction (pdgProduction $ pdgmOrig prod)
(pdgParams $ pdgmOrig prod)
(pdgConstraints $ pdgmOrig prod)
(pdgRules $ pdgmOrig prod)
(pdgChilds $ pdgmOrig prod)
visits
VGNode init <- vgFindInitial $ ndiNonterminal $ ndimOrig ndi
nextMap <- mkNextMap init
prevMap <- mkPrevMap init
return $ ENonterminal (ndiNonterminal $ ndimOrig ndi)
(ndiParams $ ndimOrig ndi)
(ndiClassCtxs $ ndimOrig ndi)
init
initv
nextMap
prevMap
prods
(ndiRecursive $ ndimOrig ndi)
(ndiHoInfo $ ndimOrig ndi)
return $ ExecutionPlan nonts typesyns wr derivings
exploreGraph :: (VGNode -> Set VGEdge -> Set VGEdge -> a -> VG s a) -> VGNode -> a -> VG s a
exploreGraph f (VGNode init) a0 = do
exploredRef <- vgInST $ newSTRef IntSet.empty
pendingRef <- vgInST $ newSTRef [init]
resRef <- vgInST $ newSTRef a0
outgoingMap <- gets vgOutgoing
edgesInfo <- gets vgEdges
let explore = do
pending <- vgInST $ readSTRef pendingRef
case pending of
[] -> return ()
(p:ps) -> do
vgInST $ writeSTRef pendingRef ps
explored <- vgInST $ readSTRef exploredRef
if IntSet.member p explored
then return ()
else do
vgInST $ writeSTRef exploredRef (IntSet.insert p explored)
case IntMap.lookup p outgoingMap of
Nothing -> return ()
Just outRef -> case IntMap.lookup p outgoingMap of
Nothing -> return ()
Just inRef -> do
outSet <- vgInST $ readSTRef outRef
inSet <- vgInST $ readSTRef inRef
sol0 <- vgInST $ readSTRef resRef
sol1 <- f (VGNode p) inSet outSet sol0
vgInST $ writeSTRef resRef sol1
forM_ (Set.elems outSet) $ \(VGEdge edge) ->
case IntMap.lookup edge edgesInfo of
Nothing -> return ()
Just (_,VGNode to) -> vgInST $ modifySTRef pendingRef (to :)
explore
explore
vgInST $ readSTRef resRef
mkNextMap :: Int -> VG s (Map Int StateCtx)
mkNextMap start = exploreGraph f (VGNode start) Map.empty where
f (VGNode nd) _ edges = updateCountMap nd edges
mkPrevMap :: Int -> VG s (Map Int StateCtx)
mkPrevMap start = exploreGraph f (VGNode start) Map.empty where
f (VGNode nd) edges _ = updateCountMap nd edges
updateCountMap :: Int -> Set VGEdge -> Map Int StateCtx -> VG s (Map Int StateCtx)
updateCountMap nd edges mp = return $ Map.insert nd v mp where
s = Set.size edges
v | s == 0 = NoneVis
| s == 1 = let [VGEdge v'] = Set.elems edges
in OneVis v'
| otherwise = ManyVis