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  }