| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- //Copyright 2013 GoGraphviz Authors
- //
- //Licensed under the Apache License, Version 2.0 (the "License");
- //you may not use this file except in compliance with the License.
- //You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- //Unless required by applicable law or agreed to in writing, software
- //distributed under the License is distributed on an "AS IS" BASIS,
- //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- //See the License for the specific language governing permissions and
- //limitations under the License.
- package gographviz
- import (
- "fmt"
- "github.com/awalterschulze/gographviz/ast"
- )
- type writer struct {
- *Graph
- writtenLocations map[string]bool
- }
- func newWriter(g *Graph) *writer {
- return &writer{g, make(map[string]bool)}
- }
- func appendAttrs(list ast.StmtList, attrs Attrs) ast.StmtList {
- for _, name := range attrs.sortedNames() {
- stmt := &ast.Attr{
- Field: ast.ID(name),
- Value: ast.ID(attrs[name]),
- }
- list = append(list, stmt)
- }
- return list
- }
- func (w *writer) newSubGraph(name string) (*ast.SubGraph, error) {
- sub := w.SubGraphs.SubGraphs[name]
- w.writtenLocations[sub.Name] = true
- s := &ast.SubGraph{}
- s.ID = ast.ID(sub.Name)
- s.StmtList = appendAttrs(s.StmtList, sub.Attrs)
- children := w.Relations.SortedChildren(name)
- for _, child := range children {
- if w.IsNode(child) {
- s.StmtList = append(s.StmtList, w.newNodeStmt(child))
- } else if w.IsSubGraph(child) {
- subgraph, err := w.newSubGraph(child)
- if err != nil {
- return nil, err
- }
- s.StmtList = append(s.StmtList, subgraph)
- } else {
- return nil, fmt.Errorf("%v is not a node or a subgraph", child)
- }
- }
- return s, nil
- }
- func (w *writer) newNodeID(name string, port string) *ast.NodeID {
- node := w.Nodes.Lookup[name]
- return ast.MakeNodeID(node.Name, port)
- }
- func (w *writer) newNodeStmt(name string) *ast.NodeStmt {
- node := w.Nodes.Lookup[name]
- id := ast.MakeNodeID(node.Name, "")
- w.writtenLocations[node.Name] = true
- return &ast.NodeStmt{
- NodeID: id,
- Attrs: ast.PutMap(node.Attrs.toMap()),
- }
- }
- func (w *writer) newLocation(name string, port string) (ast.Location, error) {
- if w.IsNode(name) {
- return w.newNodeID(name, port), nil
- } else if w.isClusterSubGraph(name) {
- if len(port) != 0 {
- return nil, fmt.Errorf("subgraph cannot have a port: %v", port)
- }
- return ast.MakeNodeID(name, port), nil
- } else if w.IsSubGraph(name) {
- if len(port) != 0 {
- return nil, fmt.Errorf("subgraph cannot have a port: %v", port)
- }
- return w.newSubGraph(name)
- }
- return nil, fmt.Errorf("%v is not a node or a subgraph", name)
- }
- func (w *writer) newEdgeStmt(edge *Edge) (*ast.EdgeStmt, error) {
- src, err := w.newLocation(edge.Src, edge.SrcPort)
- if err != nil {
- return nil, err
- }
- dst, err := w.newLocation(edge.Dst, edge.DstPort)
- if err != nil {
- return nil, err
- }
- stmt := &ast.EdgeStmt{
- Source: src,
- EdgeRHS: ast.EdgeRHS{
- &ast.EdgeRH{
- Op: ast.EdgeOp(edge.Dir),
- Destination: dst,
- },
- },
- Attrs: ast.PutMap(edge.Attrs.toMap()),
- }
- return stmt, nil
- }
- func (w *writer) Write() (*ast.Graph, error) {
- t := &ast.Graph{}
- t.Strict = w.Strict
- t.Type = ast.GraphType(w.Directed)
- t.ID = ast.ID(w.Name)
- t.StmtList = appendAttrs(t.StmtList, w.Attrs)
- for _, edge := range w.Edges.Edges {
- e, err := w.newEdgeStmt(edge)
- if err != nil {
- return nil, err
- }
- t.StmtList = append(t.StmtList, e)
- }
- subGraphs := w.SubGraphs.Sorted()
- for _, s := range subGraphs {
- if _, ok := w.writtenLocations[s.Name]; !ok {
- if _, ok := w.Relations.ParentToChildren[w.Name][s.Name]; ok {
- s, err := w.newSubGraph(s.Name)
- if err != nil {
- return nil, err
- }
- t.StmtList = append(t.StmtList, s)
- }
- }
- }
- nodes := w.Nodes.Sorted()
- for _, n := range nodes {
- if _, ok := w.writtenLocations[n.Name]; !ok {
- t.StmtList = append(t.StmtList, w.newNodeStmt(n.Name))
- }
- }
- return t, nil
- }
- // WriteAst creates an Abstract Syntrax Tree from the Graph.
- func (g *Graph) WriteAst() (*ast.Graph, error) {
- w := newWriter(g)
- return w.Write()
- }
- // String returns a DOT string representing the Graph.
- func (g *Graph) String() string {
- w, err := g.WriteAst()
- if err != nil {
- return fmt.Sprintf("error: %v", err)
- }
- return w.String()
- }
|