2
0

write.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //Copyright 2013 GoGraphviz Authors
  2. //
  3. //Licensed under the Apache License, Version 2.0 (the "License");
  4. //you may not use this file except in compliance with the License.
  5. //You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. //Unless required by applicable law or agreed to in writing, software
  10. //distributed under the License is distributed on an "AS IS" BASIS,
  11. //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. //See the License for the specific language governing permissions and
  13. //limitations under the License.
  14. package gographviz
  15. import (
  16. "fmt"
  17. "github.com/awalterschulze/gographviz/ast"
  18. )
  19. type writer struct {
  20. *Graph
  21. writtenLocations map[string]bool
  22. }
  23. func newWriter(g *Graph) *writer {
  24. return &writer{g, make(map[string]bool)}
  25. }
  26. func appendAttrs(list ast.StmtList, attrs Attrs) ast.StmtList {
  27. for _, name := range attrs.sortedNames() {
  28. stmt := &ast.Attr{
  29. Field: ast.ID(name),
  30. Value: ast.ID(attrs[name]),
  31. }
  32. list = append(list, stmt)
  33. }
  34. return list
  35. }
  36. func (w *writer) newSubGraph(name string) (*ast.SubGraph, error) {
  37. sub := w.SubGraphs.SubGraphs[name]
  38. w.writtenLocations[sub.Name] = true
  39. s := &ast.SubGraph{}
  40. s.ID = ast.ID(sub.Name)
  41. s.StmtList = appendAttrs(s.StmtList, sub.Attrs)
  42. children := w.Relations.SortedChildren(name)
  43. for _, child := range children {
  44. if w.IsNode(child) {
  45. s.StmtList = append(s.StmtList, w.newNodeStmt(child))
  46. } else if w.IsSubGraph(child) {
  47. subgraph, err := w.newSubGraph(child)
  48. if err != nil {
  49. return nil, err
  50. }
  51. s.StmtList = append(s.StmtList, subgraph)
  52. } else {
  53. return nil, fmt.Errorf("%v is not a node or a subgraph", child)
  54. }
  55. }
  56. return s, nil
  57. }
  58. func (w *writer) newNodeID(name string, port string) *ast.NodeID {
  59. node := w.Nodes.Lookup[name]
  60. return ast.MakeNodeID(node.Name, port)
  61. }
  62. func (w *writer) newNodeStmt(name string) *ast.NodeStmt {
  63. node := w.Nodes.Lookup[name]
  64. id := ast.MakeNodeID(node.Name, "")
  65. w.writtenLocations[node.Name] = true
  66. return &ast.NodeStmt{
  67. NodeID: id,
  68. Attrs: ast.PutMap(node.Attrs.toMap()),
  69. }
  70. }
  71. func (w *writer) newLocation(name string, port string) (ast.Location, error) {
  72. if w.IsNode(name) {
  73. return w.newNodeID(name, port), nil
  74. } else if w.isClusterSubGraph(name) {
  75. if len(port) != 0 {
  76. return nil, fmt.Errorf("subgraph cannot have a port: %v", port)
  77. }
  78. return ast.MakeNodeID(name, port), nil
  79. } else if w.IsSubGraph(name) {
  80. if len(port) != 0 {
  81. return nil, fmt.Errorf("subgraph cannot have a port: %v", port)
  82. }
  83. return w.newSubGraph(name)
  84. }
  85. return nil, fmt.Errorf("%v is not a node or a subgraph", name)
  86. }
  87. func (w *writer) newEdgeStmt(edge *Edge) (*ast.EdgeStmt, error) {
  88. src, err := w.newLocation(edge.Src, edge.SrcPort)
  89. if err != nil {
  90. return nil, err
  91. }
  92. dst, err := w.newLocation(edge.Dst, edge.DstPort)
  93. if err != nil {
  94. return nil, err
  95. }
  96. stmt := &ast.EdgeStmt{
  97. Source: src,
  98. EdgeRHS: ast.EdgeRHS{
  99. &ast.EdgeRH{
  100. Op: ast.EdgeOp(edge.Dir),
  101. Destination: dst,
  102. },
  103. },
  104. Attrs: ast.PutMap(edge.Attrs.toMap()),
  105. }
  106. return stmt, nil
  107. }
  108. func (w *writer) Write() (*ast.Graph, error) {
  109. t := &ast.Graph{}
  110. t.Strict = w.Strict
  111. t.Type = ast.GraphType(w.Directed)
  112. t.ID = ast.ID(w.Name)
  113. t.StmtList = appendAttrs(t.StmtList, w.Attrs)
  114. for _, edge := range w.Edges.Edges {
  115. e, err := w.newEdgeStmt(edge)
  116. if err != nil {
  117. return nil, err
  118. }
  119. t.StmtList = append(t.StmtList, e)
  120. }
  121. subGraphs := w.SubGraphs.Sorted()
  122. for _, s := range subGraphs {
  123. if _, ok := w.writtenLocations[s.Name]; !ok {
  124. if _, ok := w.Relations.ParentToChildren[w.Name][s.Name]; ok {
  125. s, err := w.newSubGraph(s.Name)
  126. if err != nil {
  127. return nil, err
  128. }
  129. t.StmtList = append(t.StmtList, s)
  130. }
  131. }
  132. }
  133. nodes := w.Nodes.Sorted()
  134. for _, n := range nodes {
  135. if _, ok := w.writtenLocations[n.Name]; !ok {
  136. t.StmtList = append(t.StmtList, w.newNodeStmt(n.Name))
  137. }
  138. }
  139. return t, nil
  140. }
  141. // WriteAst creates an Abstract Syntrax Tree from the Graph.
  142. func (g *Graph) WriteAst() (*ast.Graph, error) {
  143. w := newWriter(g)
  144. return w.Write()
  145. }
  146. // String returns a DOT string representing the Graph.
  147. func (g *Graph) String() string {
  148. w, err := g.WriteAst()
  149. if err != nil {
  150. return fmt.Sprintf("error: %v", err)
  151. }
  152. return w.String()
  153. }