github.com/gopherd/gonum@v0.0.4/graph/formats/dot/sem.go (about) 1 // This file is dual licensed under CC0 and The Gonum License. 2 // 3 // Copyright ©2017 The Gonum Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 // 7 // Copyright ©2017 Robin Eklind. 8 // This file is made available under a Creative Commons CC0 1.0 9 // Universal Public Domain Dedication. 10 11 package dot 12 13 import ( 14 "fmt" 15 16 "github.com/gopherd/gonum/graph/formats/dot/ast" 17 ) 18 19 // check validates the semantics of the given DOT file. 20 func check(file *ast.File) error { 21 for _, graph := range file.Graphs { 22 // TODO: Check graph.ID for duplicates? 23 if err := checkGraph(graph); err != nil { 24 return err 25 } 26 } 27 return nil 28 } 29 30 // check validates the semantics of the given graph. 31 func checkGraph(graph *ast.Graph) error { 32 for _, stmt := range graph.Stmts { 33 if err := checkStmt(graph, stmt); err != nil { 34 return err 35 } 36 } 37 return nil 38 } 39 40 // check validates the semantics of the given statement. 41 func checkStmt(graph *ast.Graph, stmt ast.Stmt) error { 42 switch stmt := stmt.(type) { 43 case *ast.NodeStmt: 44 return checkNodeStmt(graph, stmt) 45 case *ast.EdgeStmt: 46 return checkEdgeStmt(graph, stmt) 47 case *ast.AttrStmt: 48 return checkAttrStmt(graph, stmt) 49 case *ast.Attr: 50 // TODO: Verify that the attribute is indeed of graph component kind. 51 return checkAttr(graph, ast.GraphKind, stmt) 52 case *ast.Subgraph: 53 return checkSubgraph(graph, stmt) 54 default: 55 panic(fmt.Sprintf("support for statement of type %T not yet implemented", stmt)) 56 } 57 } 58 59 // checkNodeStmt validates the semantics of the given node statement. 60 func checkNodeStmt(graph *ast.Graph, stmt *ast.NodeStmt) error { 61 if err := checkNode(graph, stmt.Node); err != nil { 62 return err 63 } 64 for _, attr := range stmt.Attrs { 65 // TODO: Verify that the attribute is indeed of node component kind. 66 if err := checkAttr(graph, ast.NodeKind, attr); err != nil { 67 return err 68 } 69 } 70 return nil 71 } 72 73 // checkEdgeStmt validates the semantics of the given edge statement. 74 func checkEdgeStmt(graph *ast.Graph, stmt *ast.EdgeStmt) error { 75 // TODO: if graph.Strict, check for multi-edges. 76 if err := checkVertex(graph, stmt.From); err != nil { 77 return err 78 } 79 for _, attr := range stmt.Attrs { 80 // TODO: Verify that the attribute is indeed of edge component kind. 81 if err := checkAttr(graph, ast.EdgeKind, attr); err != nil { 82 return err 83 } 84 } 85 return checkEdge(graph, stmt.From, stmt.To) 86 } 87 88 // checkEdge validates the semantics of the given edge. 89 func checkEdge(graph *ast.Graph, from ast.Vertex, to *ast.Edge) error { 90 if !graph.Directed && to.Directed { 91 return fmt.Errorf("undirected graph %q contains directed edge from %q to %q", graph.ID, from, to.Vertex) 92 } 93 if err := checkVertex(graph, to.Vertex); err != nil { 94 return err 95 } 96 if to.To != nil { 97 return checkEdge(graph, to.Vertex, to.To) 98 } 99 return nil 100 } 101 102 // checkAttrStmt validates the semantics of the given attribute statement. 103 func checkAttrStmt(graph *ast.Graph, stmt *ast.AttrStmt) error { 104 for _, attr := range stmt.Attrs { 105 if err := checkAttr(graph, stmt.Kind, attr); err != nil { 106 return err 107 } 108 } 109 return nil 110 } 111 112 // checkAttr validates the semantics of the given attribute for the given 113 // component kind. 114 func checkAttr(graph *ast.Graph, kind ast.Kind, attr *ast.Attr) error { 115 switch kind { 116 case ast.GraphKind: 117 // TODO: Validate key-value pairs for graphs. 118 return nil 119 case ast.NodeKind: 120 // TODO: Validate key-value pairs for nodes. 121 return nil 122 case ast.EdgeKind: 123 // TODO: Validate key-value pairs for edges. 124 return nil 125 default: 126 panic(fmt.Sprintf("support for component kind %v not yet supported", kind)) 127 } 128 } 129 130 // checkSubgraph validates the semantics of the given subgraph. 131 func checkSubgraph(graph *ast.Graph, subgraph *ast.Subgraph) error { 132 // TODO: Check subgraph.ID for duplicates? 133 for _, stmt := range subgraph.Stmts { 134 // TODO: Refine handling of subgraph statements? 135 // checkSubgraphStmt(graph, subgraph, stmt) 136 if err := checkStmt(graph, stmt); err != nil { 137 return err 138 } 139 } 140 return nil 141 } 142 143 // checkVertex validates the semantics of the given vertex. 144 func checkVertex(graph *ast.Graph, vertex ast.Vertex) error { 145 switch vertex := vertex.(type) { 146 case *ast.Node: 147 return checkNode(graph, vertex) 148 case *ast.Subgraph: 149 return checkSubgraph(graph, vertex) 150 default: 151 panic(fmt.Sprintf("support for vertex of type %T not yet supported", vertex)) 152 } 153 } 154 155 // checNode validates the semantics of the given node. 156 func checkNode(graph *ast.Graph, node *ast.Node) error { 157 // TODO: Check node.ID for duplicates? 158 // TODO: Validate node.Port. 159 return nil 160 }