module Knuth1 where
import Pretty
import ExecutionPlan
import CommonTypes
import Control.Monad
import Control.Monad.ST
import Data.Maybe
import Data.List
import Data.STRef
import Debug.Trace
import Data.Array (Array)
import qualified Data.Array as Array
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set
traceST :: String -> ST s ()
traceST s = trace s (return ())
data AttrType = Inh | Syn | Loc deriving (Eq, Ord, Show)
data Vertex = VAttr AttrType Identifier Identifier
| VChild Identifier
| VRule Identifier deriving (Eq, Ord)
instance Show Vertex where
show (VAttr ty ch at) = show ty ++ " @" ++ show ch ++ "." ++ show at
show (VChild ch) = "Child " ++ show ch
show (VRule ru) = "Rule " ++ show ru
isVertexAttr :: Vertex -> Bool
isVertexAttr (VAttr _ _ _) = True
isVertexAttr _ = False
getAttrChildName :: Vertex -> Identifier
getAttrChildName (VAttr _ n _) = n
setAttrChildName :: Vertex -> Identifier -> Vertex
setAttrChildName (VAttr t _ a) n = VAttr t n a
getAttrType :: Vertex -> AttrType
getAttrType (VAttr t _ _) = t
getAttrName :: Vertex -> Identifier
getAttrName (VAttr _ _ a) = a
type Edge = (Vertex, Vertex)
type IVertex = Int
type IEdge = (IVertex, IVertex)
data DependencyGraph s = DependencyGraph { vertexIMap :: Map Vertex IVertex
, vertexOMap :: Array IVertex Vertex
, successors :: Array IVertex (STRef s (Set IVertex))
, predecessors :: Array IVertex (STRef s (Set IVertex)) }
graphConstruct :: [Vertex] -> ST s (DependencyGraph s)
graphConstruct vs = do let nv = length vs
let ivs = [0..nv-1]
let ivb = (0,nv-1)
let vimap = Map.fromList (zip vs ivs)
let vomap = Array.array ivb (zip ivs vs)
succs <- replicateM nv (newSTRef Set.empty)
preds <- replicateM nv (newSTRef Set.empty)
let su = Array.array ivb (zip ivs succs)
let pr = Array.array ivb (zip ivs preds)
let graph = DependencyGraph { vertexIMap = vimap
, vertexOMap = vomap
, successors = su
, predecessors = pr }
return graph
graphConstructTRC :: [Vertex] -> [Edge] -> ST s (DependencyGraph s)
graphConstructTRC vs es = do g <- graphConstruct vs
graphInsertEdgesTRC g es
return g
graphSuccessors :: DependencyGraph s -> Vertex -> ST s (Set Vertex)
graphSuccessors g v = do sucs <- readSTRef $ (successors g) Array.! (graphGetIVertex g v)
return $ Set.map (graphGetVertex g) sucs
graphPredecessors :: DependencyGraph s -> Vertex -> ST s (Set Vertex)
graphPredecessors g v = do sucs <- readSTRef $ (predecessors g) Array.! (graphGetIVertex g v)
return $ Set.map (graphGetVertex g) sucs
graphContainsEdge :: DependencyGraph s -> Edge -> ST s Bool
graphContainsEdge g (v1,v2) = do let iv1 = graphGetIVertex g v1
let iv2 = graphGetIVertex g v2
sucs <- readSTRef $ (successors g) Array.! iv1
return $ iv2 `Set.member` sucs
graphInsert :: DependencyGraph s -> Edge -> ST s ()
graphInsert g (v1,v2) = do let iv1 = graphGetIVertex g v1
let iv2 = graphGetIVertex g v2
modifySTRef ((successors g) Array.! iv1) $ Set.insert iv2
modifySTRef ((predecessors g) Array.! iv2) $ Set.insert iv1
graphInsertTRC :: DependencyGraph s -> Edge -> ST s [(IVertex, Set IVertex)]
graphInsertTRC g (v1,v2) = do let iv1 = graphGetIVertex g v1
let iv2 = graphGetIVertex g v2
pred1 <- readSTRef $ (predecessors g) Array.! iv1
succ2 <- readSTRef $ (successors g) Array.! iv2
let rsucc1 = (successors g) Array.! iv1
succ1 <- readSTRef rsucc1
let add1 = succ2 `Set.difference` succ1
modifySTRef rsucc1 (Set.union add1 . Set.insert iv2)
let rpred2 = (predecessors g) Array.! iv2
modifySTRef rpred2 (Set.union pred1 . Set.insert iv1)
sucl <- forM (Set.toList pred1) $ \pred -> do
let rsucc = (successors g) Array.! pred
csucc <- readSTRef rsucc
let cadd = (Set.insert iv2 succ2) `Set.difference` csucc
modifySTRef rsucc (Set.union cadd)
return (pred, cadd)
forM_ (Set.toList succ2) $ \succ -> do
let rpred = (predecessors g) Array.! succ
cpred <- readSTRef rpred
let cadd = (Set.insert iv1 pred1) `Set.difference` cpred
modifySTRef rpred (Set.union cadd)
return $ (iv1,add1) : sucl
graphVertices :: DependencyGraph s -> ST s [Vertex]
graphVertices = return . Array.elems . vertexOMap
graphEdges :: DependencyGraph s -> ST s [Edge]
graphEdges g = do let vs = Array.indices $ vertexOMap g
perv <- forM vs $ \v -> do
let rv = graphGetVertex g v
sucs <- readSTRef $ (successors g) Array.! v
let sucl = Set.toList sucs
return $ map ((,) rv . graphGetVertex g) sucl
return $ concat perv
graphInsertEdges :: DependencyGraph s -> [Edge] -> ST s ()
graphInsertEdges g ed = mapM_ (graphInsert g) ed
graphInsertEdgesTRC :: DependencyGraph s -> [Edge] -> ST s [Edge]
graphInsertEdgesTRC g ed = do
rets <- mapM (graphInsertTRC g) ed
let f :: (IVertex, (Set IVertex)) -> [(IVertex, IVertex)]
f (v,s) = map ((,) v) (Set.toList s)
let comb :: [(IVertex, IVertex)]
comb = concatMap (concatMap f) rets
return $ map (graphGetEdge g) $ comb
graphIsCyclic :: DependencyGraph s -> ST s Bool
graphIsCyclic g = do
s <- graphCyclicVertices g
return $ not $ Set.null s
graphCyclicVertices :: DependencyGraph s -> ST s (Set IVertex)
graphCyclicVertices g = do
vs <- return $ Array.indices $ vertexOMap g
sets <- forM vs $ \v -> do
sucs <- readSTRef $ (successors g) Array.! v
let res | v `Set.member` sucs = Set.singleton v
| otherwise = Set.empty
return res
return (Set.unions sets)
graphCyclicVerticesExt :: DependencyGraph s -> ST s [Vertex]
graphCyclicVerticesExt g = (map (graphGetVertex g) . Set.elems) `fmap` graphCyclicVertices g
graphGetIVertex :: DependencyGraph s -> Vertex -> IVertex
graphGetIVertex g v = vertexIMap g Map.! v
graphGetVertex :: DependencyGraph s -> IVertex -> Vertex
graphGetVertex g v = vertexOMap g Array.! v
graphGetEdge :: DependencyGraph s -> IEdge -> Edge
graphGetEdge g (v1,v2) = (graphGetVertex g v1, graphGetVertex g v2)
graphIsTRC :: DependencyGraph s -> ST s Bool
graphIsTRC g = do let vs = Array.indices $ vertexOMap g
bs <- forM vs $ \v -> do
succs <- readSTRef $ (successors g) Array.! v
bs2 <- forM (Set.toList succs) $ \v2 -> do
succs2 <- readSTRef $ (successors g) Array.! v2
return $ succs2 `Set.isSubsetOf` succs
return $ and bs2
return $ and bs
graphCheckConsistency :: DependencyGraph s -> ST s Bool
graphCheckConsistency g = do let vs = Array.indices $ vertexOMap g
ret <- forM vs $ \v -> do
succs <- readSTRef $ (successors g) Array.! v
r1 <- forM (Set.toList succs) $ \succ -> do
preds2 <- readSTRef $ (predecessors g) Array.! succ
return (v `Set.member` preds2)
preds <- readSTRef $ (predecessors g) Array.! v
r2 <- forM (Set.toList preds) $ \pred -> do
succs2 <- readSTRef $ (successors g) Array.! pred
return (v `Set.member` succs2)
return $ and $ r1 ++ r2
return $ and $ ret
graphTopSort :: DependencyGraph s -> ST s [Edge]
graphTopSort g = do let vs = Array.indices $ vertexOMap g
order <- foldM (graphTopSort' g) [] vs
mb <- forM (zip order (tail order)) $ \(v1,v2) -> do
let edg = graphGetEdge g (v2,v1)
ce <- graphContainsEdge g edg
if ce
then return Nothing
else do graphInsert g edg
return $ Just edg
return $ catMaybes mb
graphTopSort' :: DependencyGraph s -> [IVertex] -> IVertex -> ST s [IVertex]
graphTopSort' g prev cur | cur `elem` prev = return prev
| otherwise = do pred <- readSTRef $ (predecessors g) Array.! cur
order <- foldM (graphTopSort' g) prev $ Set.toList pred
return $ cur : order
data NontDependencyGraph = NontDependencyGraph { ndgVertices :: [Vertex]
, ndgEdges :: [Edge] }
data ProdDependencyGraph = ProdDependencyGraph { pdgVertices :: [Vertex]
, pdgEdges :: [Edge]
, pdgRules :: ERules
, pdgChilds :: EChildren
, pdgProduction :: Identifier
, pdgChildMap :: [(Identifier, Identifier)]
, pdgConstraints :: [Type]
, pdgParams :: [Identifier] }
data NontDependencyInformation = NontDependencyInformation { ndiNonterminal :: Identifier
, ndiParams :: [Identifier]
, ndiInh :: [Identifier]
, ndiSyn :: [Identifier]
, ndiDepGraph :: NontDependencyGraph
, ndiProds :: [ProdDependencyGraph]
, ndiRecursive :: Bool
, ndiHoInfo :: HigherOrderInfo
, ndiClassCtxs :: ClassContext
}
data NontDependencyGraphM s = NontDependencyGraphM { ndgmDepGraph :: DependencyGraph s
, ndgmOrig :: NontDependencyGraph }
data ProdDependencyGraphM s = ProdDependencyGraphM { pdgmDepGraph :: DependencyGraph s
, pdgmOrig :: ProdDependencyGraph }
data NontDependencyInformationM s = NontDependencyInformationM { ndimOrig :: NontDependencyInformation
, ndimDepGraph :: NontDependencyGraphM s
, ndimProds :: [ProdDependencyGraphM s] }
mkNontDependencyGraphM :: NontDependencyGraph -> ST s (NontDependencyGraphM s)
mkNontDependencyGraphM ndg = do g <- graphConstructTRC (ndgVertices ndg) (ndgEdges ndg)
return $ NontDependencyGraphM { ndgmDepGraph = g
, ndgmOrig = ndg }
mkProdDependencyGraphM :: Bool -> ProdDependencyGraph -> ST s (ProdDependencyGraphM s)
mkProdDependencyGraphM trc pdg = do g <- if trc
then graphConstructTRC (pdgVertices pdg) (pdgEdges pdg)
else do g <- graphConstruct (pdgVertices pdg)
mapM_ (graphInsert g) (pdgEdges pdg)
return g
return $ ProdDependencyGraphM { pdgmDepGraph = g
, pdgmOrig = pdg }
mkNontDependencyInformationM :: NontDependencyInformation -> ST s (NontDependencyInformationM s)
mkNontDependencyInformationM ndi = do dg <- mkNontDependencyGraphM (ndiDepGraph ndi)
prods <- mapM (mkProdDependencyGraphM True) (ndiProds ndi)
return $ NontDependencyInformationM { ndimOrig = ndi
, ndimDepGraph = dg
, ndimProds = prods }
undoTransitiveClosure :: [NontDependencyInformationM s] -> ST s [NontDependencyInformationM s]
undoTransitiveClosure ndis = do edgesl <- mapM (\ndi -> graphEdges (ndgmDepGraph $ ndimDepGraph ndi)) ndis
let edges = concat edgesl
forM ndis $ \ndi -> do
prods <- mapM (mkProdDependencyGraphM False) (ndiProds $ ndimOrig ndi)
forM_ (zip prods (ndimProds ndi)) $ \(nprod,oprod) -> do
let possa = do (v1,v2) <- edges
guard $ isVertexAttr v1
guard $ isVertexAttr v2
let tp = getAttrChildName v1
(ch,chtp) <- pdgChildMap $ pdgmOrig nprod
guard $ tp == chtp
let nv1 = setAttrChildName v1 ch
let nv2 = setAttrChildName v2 ch
return (nv1, nv2)
toadd <- filterM (graphContainsEdge (pdgmDepGraph oprod)) possa
graphInsertEdges (pdgmDepGraph nprod) toadd
return $ NontDependencyInformationM { ndimOrig = ndimOrig ndi
, ndimDepGraph = ndimDepGraph ndi
, ndimProds = prods }
knuth1 :: [NontDependencyInformationM s] -> ST s ()
knuth1 ndis = do
pndis <- forM ndis $ \ndi -> do
ipend <- mapM (graphEdges . pdgmDepGraph) . ndimProds $ ndi
return (ipend, ndi)
knuth1' pndis
knuth1' :: [([[Edge]], NontDependencyInformationM s)] -> ST s ()
knuth1' ndis = do
ndis' <- mapM addProdNont ndis
let pntedge = concat ndis'
let ntedge = pntedge
if null ntedge
then return ()
else do
ndis'' <- mapM (\(_,x) -> addNontProd True (ntedge, x)) ndis
nndis' <- zipWithM (\(_,ndi) me -> return (me, ndi)) ndis ndis''
if any (not . null) ndis''
then knuth1' nndis'
else return ()
addProdNont :: ([[Edge]], NontDependencyInformationM s) -> ST s [Edge]
addProdNont (pending, ndi) = do
let nontDepGraph = ndimDepGraph ndi
let nontGraph = ndgmDepGraph nontDepGraph
let possa = nub $ do (v1,v2) <- concat pending
guard $ isVertexAttr v1
guard $ getAttrChildName v1 == _LHS
guard $ getAttrType v1 == Syn
guard $ isVertexAttr v2
guard $ getAttrChildName v2 == _LHS
guard $ getAttrType v2 == Inh
let nv1 = setAttrChildName v1 (ndiNonterminal $ ndimOrig ndi)
let nv2 = setAttrChildName v2 (ndiNonterminal $ ndimOrig ndi)
return (nv1, nv2)
toadd <- filterM (\e -> return not `ap` graphContainsEdge nontGraph e) possa
when (not $ null toadd) $ do
graphInsertEdgesTRC nontGraph toadd
return ()
return toadd
addNontProd :: Bool -> ([Edge], NontDependencyInformationM s) -> ST s [[Edge]]
addNontProd trc (pending, ndi) = do
mapM (addNontProd' trc pending) (ndimProds ndi)
addNontProd' :: Bool -> [Edge] -> ProdDependencyGraphM s -> ST s [Edge]
addNontProd' trc pend pdg = do
prodGraph <- return $ pdgmDepGraph pdg
let possa = do (v1,v2) <- pend
guard $ isVertexAttr v1
guard $ isVertexAttr v2
let tp = getAttrChildName v1
(ch,chtp) <- pdgChildMap $ pdgmOrig pdg
guard $ tp == chtp
let nv1 = setAttrChildName v1 ch
let nv2 = setAttrChildName v2 ch
return (nv1, nv2)
toadd <- filterM (\e -> return not `ap` graphContainsEdge prodGraph e) possa
if null toadd
then return []
else do
ret <- if trc
then graphInsertEdgesTRC prodGraph toadd
else do mapM_ (graphInsert prodGraph) toadd
return []
return ret
addBackEdges :: [([[Edge]], NontDependencyInformationM s)] -> ST s [Edge]
addBackEdges ndis = do
lBackEdges <- forM ndis $ \(aedg,ndi) -> do
bs <- forM (zip aedg (ndimProds ndi)) $ \(edg,prod) -> do
return $ do (v1,v2) <- edg
guard $ isVertexAttr v1
guard $ getAttrChildName v1 /= _LHS
guard $ getAttrType v1 == Inh
guard $ isVertexAttr v2
guard $ getAttrChildName v2 /= _LHS
guard $ getAttrType v2 == Syn
guard $ getAttrChildName v1 == getAttrChildName v2
(ch,chtp) <- pdgChildMap $ pdgmOrig prod
let tp = getAttrChildName v1
guard $ tp == ch
let nv1 = setAttrChildName v1 chtp
let nv2 = setAttrChildName v2 chtp
return (nv1, nv2)
return $ foldl' union [] bs
let backedges = foldl' union [] lBackEdges
ret <- forM ndis $ \(_,ndi) -> do
let nont = ndiNonterminal . ndimOrig $ ndi
let thisbe = filter ((==) nont . getAttrChildName . fst) backedges
graphInsertEdgesTRC (ndgmDepGraph . ndimDepGraph $ ndi) thisbe
return $ backedges ++ concat ret
addTopSortEdges :: [Edge] -> ProdDependencyGraphM s -> ST s ()
addTopSortEdges pend pdg = do
prodGraph <- return $ pdgmDepGraph pdg
let possa = do (v1,v2) <- pend
guard $ isVertexAttr v1
guard $ isVertexAttr v2
let tp = getAttrChildName v1
(ch,chtp) <- pdgChildMap $ pdgmOrig pdg
guard $ tp == chtp
let nv1 = setAttrChildName v1 ch
let nv2 = setAttrChildName v2 ch
return (nv1, nv2)
forM_ possa $ \(v1,v2) -> do e1 <- graphContainsEdge prodGraph (v1,v2)
e2 <- graphContainsEdge prodGraph (v2,v1)
when (not $ e1 || e2) $ do
graphInsertTRC prodGraph (v1,v2)
return ()