packages feed

hegg-0.5.0.0: src/Data/Equality/Graph/Dot.hs

{-# LANGUAGE OverloadedStrings         #-}
{-# LANGUAGE TypeApplications          #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE TypeFamilies              #-}

module Data.Equality.Graph.Dot
    ( module Data.Equality.Graph.Dot
    , writeDotFile
    )
    where

import Control.Monad

import Data.Text.Lazy (Text, pack)

import qualified Data.Set as S
import qualified Data.IntMap as IM

import Data.GraphViz.Commands.IO
import Data.GraphViz.Types.Generalised
import Data.GraphViz.Types.Monadic
import Data.GraphViz.Attributes (style, dotted, textLabel)
import Data.GraphViz.Attributes.Complete

import Data.Equality.Graph
import Data.Equality.Graph.Internal

txt :: Show a => a -> Text
txt = pack . show

writeDemo :: (Language language, Show (ENode language)) => EGraph analysis language -> IO ()
writeDemo = writeDotFile "demo.gv" . toDotGraph

toDotGraph :: (Language language, Show (ENode language)) => EGraph analysis language -> DotGraph Text
toDotGraph eg = digraph (Str "egraph") $ do

    graphAttrs [Compound True, ClusterRank Local]

    forM_ (IM.toList $ classes eg) $ \(class_id, EClass _ nodes _ _) ->

        subgraph (Str ("cluster_" <> txt class_id)) $ do
            graphAttrs [style dotted]
            forM_ (zip (S.toList nodes) [0..]) $ \(n, i) -> do
                let n' = canonicalize n eg
                node (txt class_id <> "." <> txt (find i eg)) [textLabel (txt n')]

    forM_ (IM.toList $ classes eg) $ \(class_id, EClass _ nodes _ _) -> do

        forM_ (zip (S.toList nodes) [0..]) $ \(n, i_in_class) -> do

            let n' = canonicalize n eg
            let i_in_class' = find i_in_class eg

            forM_ (zip (children n') [(0 :: Integer)..]) $ \(child, arg_i) -> do
                -- TODO: On anchors and labels...?
                let child_leader = find child eg
                if child_leader == class_id
                   then edge (txt class_id <> "." <> txt i_in_class') (txt class_id <> "." <> txt i_in_class') [textLabel (txt arg_i)] -- LHead ("cluster_" <> txt class_id),
                   else edge (txt class_id <> "." <> txt i_in_class') (txt child <> ".0") [LHead ("cluster_" <> txt child_leader), textLabel (txt arg_i)]