mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-09 04:59:31 -06:00
117 lines
3.1 KiB
Haskell
117 lines
3.1 KiB
Haskell
----------------------------------------------------------------------
|
|
-- |
|
|
-- Module : Graphviz
|
|
-- Maintainer : BB
|
|
-- Stability : (stable)
|
|
-- Portability : (portable)
|
|
--
|
|
-- > CVS $Date: 2005/09/15 18:10:44 $
|
|
-- > CVS $Author: bringert $
|
|
-- > CVS $Revision: 1.2 $
|
|
--
|
|
-- Graphviz DOT format representation and printing.
|
|
-----------------------------------------------------------------------------
|
|
|
|
module GF.Data.Graphviz (
|
|
Graph(..), GraphType(..),
|
|
Node(..), Edge(..),
|
|
Attr,
|
|
addSubGraphs,
|
|
setName,
|
|
setAttr,
|
|
prGraphviz
|
|
) where
|
|
|
|
import Data.Char
|
|
|
|
import GF.Data.Utilities
|
|
|
|
-- | Graph type, graph ID, graph attirbutes, graph nodes, graph edges, subgraphs
|
|
data Graph = Graph {
|
|
gType :: GraphType,
|
|
gId :: Maybe String,
|
|
gAttrs :: [Attr],
|
|
gNodes :: [Node],
|
|
gEdges :: [Edge],
|
|
gSubgraphs :: [Graph]
|
|
}
|
|
deriving (Show)
|
|
|
|
data GraphType = Directed | Undirected
|
|
deriving (Show)
|
|
|
|
data Node = Node String [Attr]
|
|
deriving Show
|
|
|
|
data Edge = Edge String String [Attr]
|
|
deriving Show
|
|
|
|
type Attr = (String,String)
|
|
|
|
--
|
|
-- * Graph construction
|
|
--
|
|
|
|
addSubGraphs :: [Graph] -> Graph -> Graph
|
|
addSubGraphs gs g = g { gSubgraphs = gs ++ gSubgraphs g }
|
|
|
|
setName :: String -> Graph -> Graph
|
|
setName n g = g { gId = Just n }
|
|
|
|
setAttr :: String -> String -> Graph -> Graph
|
|
setAttr n v g = g { gAttrs = tableSet n v (gAttrs g) }
|
|
|
|
--
|
|
-- * Pretty-printing
|
|
--
|
|
|
|
prGraphviz :: Graph -> String
|
|
prGraphviz g@(Graph t i _ _ _ _) =
|
|
graphtype t ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}\n"
|
|
|
|
prSubGraph :: Graph -> String
|
|
prSubGraph g@(Graph _ i _ _ _ _) =
|
|
"subgraph" ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}"
|
|
|
|
prGraph :: Graph -> String
|
|
prGraph (Graph t id at ns es ss) =
|
|
unlines $ map (++";") (map prAttr at
|
|
++ map prNode ns
|
|
++ map (prEdge t) es
|
|
++ map prSubGraph ss)
|
|
|
|
graphtype :: GraphType -> String
|
|
graphtype Directed = "digraph"
|
|
graphtype Undirected = "graph"
|
|
|
|
prNode :: Node -> String
|
|
prNode (Node n at) = esc n ++ " " ++ prAttrList at
|
|
|
|
prEdge :: GraphType -> Edge -> String
|
|
prEdge t (Edge x y at) = esc x ++ " " ++ edgeop t ++ " " ++ esc y ++ " " ++ prAttrList at
|
|
|
|
edgeop :: GraphType -> String
|
|
edgeop Directed = "->"
|
|
edgeop Undirected = "--"
|
|
|
|
prAttrList :: [Attr] -> String
|
|
prAttrList [] = ""
|
|
prAttrList at = "[" ++ join "," (map prAttr at) ++ "]"
|
|
|
|
prAttr :: Attr -> String
|
|
prAttr (n,v) = esc n ++ " = " ++ esc v
|
|
|
|
esc :: String -> String
|
|
esc s | needEsc s = "\"" ++ concat [ if shouldEsc c then ['\\',c] else [c] | c <- s ] ++ "\""
|
|
| otherwise = s
|
|
where shouldEsc = (`elem` ['"', '\\'])
|
|
|
|
needEsc :: String -> Bool
|
|
needEsc [] = True
|
|
needEsc xs | all isDigit xs = False
|
|
needEsc (x:xs) = not (isIDFirst x && all isIDChar xs)
|
|
|
|
isIDFirst, isIDChar :: Char -> Bool
|
|
isIDFirst c = c `elem` (['_']++['a'..'z']++['A'..'Z'])
|
|
isIDChar c = isIDFirst c || isDigit c
|