module Data.Sifflet.TreeGraph
(LayoutGraph,
flayoutToGraph, treeLayoutToGraph,
orderedTreeToGraph,
treeGraphNodesTree, graphToTreeOriginal,
graphToTreeStructure,
flayoutToGraphRoots,
graphToOrderedTree, graphToOrderedTreeFrom,
orderedChildren, adjCompareEdge,
nextNodes,
grTranslateNode, grTranslateSubtree, grTranslateGraph,
functoidToFunction, graphToExprTree,
)
where
import Data.List (sort, sortBy)
import Data.Graph.Inductive as G
import Data.Sifflet.Functoid
import Data.Sifflet.Geometry
import Data.Sifflet.Tree as T
import Data.Sifflet.TreeLayout
import Data.Sifflet.WGraph
import Language.Sifflet.Expr
import Language.Sifflet.ExprTree
import Language.Sifflet.TypeCheck
import Language.Sifflet.Util
type LayoutGraph n e = Gr (LayoutNode n) e
flayoutToGraph :: FunctoidLayout -> WGraph
flayoutToGraph tlo =
case tlo of
FLayoutTree t -> treeLayoutToGraph t
FLayoutForest ts _bbox ->
foldl grAddGraph wgraphNew (map treeLayoutToGraph ts)
treeLayoutToGraph :: TreeLayout ExprNode -> WGraph
treeLayoutToGraph = orderedTreeToGraph . fmap WSimple
flayoutToGraphRoots :: FunctoidLayout -> [G.Node]
flayoutToGraphRoots (FLayoutTree _t) = [1]
flayoutToGraphRoots (FLayoutForest trees _bbox) =
let loop _ [] res = reverse res
loop next (t:ts) res =
loop (next + treeSize t) ts (next:res)
in loop 1 trees []
sprout :: G.Node -> Tree e -> [(G.Node, WEdge, Tree e)]
sprout parent (T.Node _ subtrees) =
let m = length subtrees 1
in [(parent, WEdge e, s) | (e, s) <- zip [0..m] subtrees]
orderedTreeToGraph :: Tree e -> Gr e WEdge
orderedTreeToGraph otree =
let g0 = empty :: Gr e WEdge
g1 = insNode (1, rootLabel otree) g0
grow :: Gr e WEdge -> [(G.Node, WEdge, Tree e)] -> G.Node -> Gr e WEdge
grow g [] _ = g
grow g ((p, e, t):pets) n =
let adj = (e, p)
g' = ([adj], n, (rootLabel t), []) & g
n' = succ n
in grow g' (pets ++
sprout n t
)
n'
in grow g1 (sprout 1 otree) 2
treeGraphNodesTree :: Tree e -> Tree Node
treeGraphNodesTree atree =
let gnTree :: Tree e -> Node -> Node -> (Tree Node, Node)
gnTree (T.Node _root subtrees) rootNode next =
let (nNodes, next') = nextNodes subtrees next
(subtrees', next'') = gnSubtrees subtrees nNodes next'
in (T.Node rootNode subtrees', next'')
gnSubtrees :: [Tree e] -> [Node] -> Node -> ([Tree Node], Node)
gnSubtrees [] [] next = ([], next)
gnSubtrees (t:ts) (n:ns) next =
let (t', next') = gnTree t n next
(ts', next'') = gnSubtrees ts ns next'
in ((t' : ts'), next'')
gnSubtrees _ _ _ = error "gnSubtrees: list lengths do not match"
in fst (gnTree atree 1 2)
nextNodes :: [e] -> Node -> ([Node], Node)
nextNodes items next =
let n = length items
next' = next + n
in ([next .. (next' 1)], next')
graphToOrderedTree :: Gr e WEdge -> Tree e
graphToOrderedTree g = graphToOrderedTreeFrom g 1
graphToOrderedTreeFrom :: Gr e WEdge -> G.Node -> Tree e
graphToOrderedTreeFrom g n =
case lab g n of
Just label ->
T.Node label (map (graphToOrderedTreeFrom g) (orderedChildren g n))
Nothing ->
errcats ["missing label for node", show n]
orderedChildren :: Gr e WEdge -> G.Node -> [G.Node]
orderedChildren g = map fst . sortBy adjCompareEdge . lsuc g
adjCompareEdge :: (Node, WEdge) -> (Node, WEdge) -> Ordering
adjCompareEdge (_n1, e1) (_n2, e2) = compare e1 e2
graphToTreeOriginal :: Gr e () -> G.Node -> Tree e
graphToTreeOriginal g n =
case lab g n of
Just label -> T.Node label (map (graphToTreeOriginal g)
(sort (suc g n)))
_ -> errcats ["missing label for node", show n]
graphToTreeStructure :: Gr n e -> G.Node -> Tree G.Node
graphToTreeStructure g n = T.Node n (map (graphToTreeStructure g)
(sort (suc g n)))
grTranslateNode ::
Node -> Double -> Double -> LayoutGraph n e -> LayoutGraph n e
grTranslateNode node dx dy graph =
grUpdateNodeLabel graph node (translate dx dy)
grTranslateSubtree ::
Node -> Double -> Double -> LayoutGraph n e -> LayoutGraph n e
grTranslateSubtree root dx dy graph =
let trSubtrees :: [Node] -> LayoutGraph n e -> LayoutGraph n e
trSubtrees [] g = g
trSubtrees (r:rs) g = trSubtrees (rs ++ suc g r)
(grTranslateNode r dx dy g)
in trSubtrees [root] graph
grTranslateGraph :: Double -> Double -> LayoutGraph n e -> LayoutGraph n e
grTranslateGraph dx dy graph = nmap (translate dx dy) graph
grUpdateNodeLabel :: (DynGraph g) => g a b -> Node -> (a -> a) -> g a b
grUpdateNodeLabel graph node updater =
case match node graph of
(Nothing, _) -> error "no such node"
(Just (preds, jnode, label, succs), graph') ->
(preds, jnode, updater label, succs) & graph'
functoidToFunction ::
Functoid -> WGraph -> G.Node -> Env -> SuccFail Function
functoidToFunction functoid graph frameNode env =
case functoid of
FunctoidFunc f -> Succ f
FunctoidParts {fpName = name, fpArgs = args} ->
case suc graph frameNode of
[root] ->
do
{
expr <- treeToExpr $ graphToExprTree graph root
; let impl = Compound args expr
; (atypes, rtype) <- decideTypes name expr args env
; Succ (Function (Just name) atypes rtype impl)
}
_ -> Fail "The graph structure is not a tree!"
graphToExprTree :: WGraph -> G.Node -> Tree ExprNode
graphToExprTree g root =
let extractExprNode wnode =
case wnode of
WSimple layoutNode -> gnodeValue (nodeGNode layoutNode)
WFrame _ -> error "graphToExprTreeFrom: unexpected WFrame node"
in fmap extractExprNode (graphToOrderedTreeFrom g root)