func getCompassPoint(s string) (ast.CompassPoint, bool) {
	switch s {
	case "_":
		return ast.CompassPointDefault, true
	case "n":
		return ast.CompassPointNorth, true
	case "ne":
		return ast.CompassPointNorthEast, true
	case "e":
		return ast.CompassPointEast, true
	case "se":
		return ast.CompassPointSouthEast, true
	case "s":
		return ast.CompassPointSouth, true
	case "sw":
		return ast.CompassPointSouthWest, true
	case "w":
		return ast.CompassPointWest, true
	case "nw":
		return ast.CompassPointNorthWest, true
	case "c":
		return ast.CompassPointCenter, true
	}
	return ast.CompassPointDefault, false
}
getCompassPoint returns the corresponding compass point to the given string,
and a boolean value indicating if such a compass point exists.
package astx
import (
	"fmt"
	"strings"
	"gonum.org/v1/gonum/graph/formats/dot/ast"
	"gonum.org/v1/gonum/graph/formats/dot/internal/token"
)
func NewFile(graph interface{}) (*ast.File, error) {
	g, ok := graph.(*ast.Graph)
	if !ok {
		return nil, fmt.Errorf("invalid graph type; expected *ast.Graph, got %T", graph)
	}
	return &ast.File{Graphs: []*ast.Graph{g}}, nil
}
func AppendGraph(file, graph interface{}) (*ast.File, error) {
	f, ok := file.(*ast.File)
	if !ok {
		return nil, fmt.Errorf("invalid file type; expected *ast.File, got %T", file)
	}
	g, ok := graph.(*ast.Graph)
	if !ok {
		return nil, fmt.Errorf("invalid graph type; expected *ast.Graph, got %T", graph)
	}
	f.Graphs = append(f.Graphs, g)
	return f, nil
}
func NewGraph(strict, directed, optID, optStmts interface{}) (*ast.Graph, error) {
	s, ok := strict.(bool)
	if !ok {
		return nil, fmt.Errorf("invalid strictness type; expected bool, got %T", strict)
	}
	d, ok := directed.(bool)
	if !ok {
		return nil, fmt.Errorf("invalid direction type; expected bool, got %T", directed)
	}
	id, ok := optID.(string)
	if optID != nil && !ok {
		return nil, fmt.Errorf("invalid ID type; expected string or nil, got %T", optID)
	}
	stmts, ok := optStmts.([]ast.Stmt)
	if optStmts != nil && !ok {
		return nil, fmt.Errorf("invalid statements type; expected []ast.Stmt or nil, got %T", optStmts)
	}
	return &ast.Graph{Strict: s, Directed: d, ID: id, Stmts: stmts}, nil
}
func NewStmtList(stmt interface{}) ([]ast.Stmt, error) {
	s, ok := stmt.(ast.Stmt)
	if !ok {
		return nil, fmt.Errorf("invalid statement type; expected ast.Stmt, got %T", stmt)
	}
	return []ast.Stmt{s}, nil
}
func AppendStmt(list, stmt interface{}) ([]ast.Stmt, error) {
	l, ok := list.([]ast.Stmt)
	if !ok {
		return nil, fmt.Errorf("invalid statement list type; expected []ast.Stmt, got %T", list)
	}
	s, ok := stmt.(ast.Stmt)
	if !ok {
		return nil, fmt.Errorf("invalid statement type; expected ast.Stmt, got %T", stmt)
	}
	return append(l, s), nil
}
func NewNodeStmt(node, optAttrs interface{}) (*ast.NodeStmt, error) {
	n, ok := node.(*ast.Node)
	if !ok {
		return nil, fmt.Errorf("invalid node type; expected *ast.Node, got %T", node)
	}
	attrs, ok := optAttrs.([]*ast.Attr)
	if optAttrs != nil && !ok {
		return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
	}
	return &ast.NodeStmt{Node: n, Attrs: attrs}, nil
}
func NewEdgeStmt(from, to, optAttrs interface{}) (*ast.EdgeStmt, error) {
	f, ok := from.(ast.Vertex)
	if !ok {
		return nil, fmt.Errorf("invalid source vertex type; expected ast.Vertex, got %T", from)
	}
	t, ok := to.(*ast.Edge)
	if !ok {
		return nil, fmt.Errorf("invalid outgoing edge type; expected *ast.Edge, got %T", to)
	}
	attrs, ok := optAttrs.([]*ast.Attr)
	if optAttrs != nil && !ok {
		return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
	}
	return &ast.EdgeStmt{From: f, To: t, Attrs: attrs}, nil
}
func NewEdge(directed, vertex, optTo interface{}) (*ast.Edge, error) {
	d, ok := directed.(bool)
	if !ok {
		return nil, fmt.Errorf("invalid direction type; expected bool, got %T", directed)
	}
	v, ok := vertex.(ast.Vertex)
	if !ok {
		return nil, fmt.Errorf("invalid destination vertex type; expected ast.Vertex, got %T", vertex)
	}
	to, ok := optTo.(*ast.Edge)
	if optTo != nil && !ok {
		return nil, fmt.Errorf("invalid outgoing edge type; expected *ast.Edge or nil, got %T", optTo)
	}
	return &ast.Edge{Directed: d, Vertex: v, To: to}, nil
}
func NewAttrStmt(kind, optAttrs interface{}) (*ast.AttrStmt, error) {
	k, ok := kind.(ast.Kind)
	if !ok {
		return nil, fmt.Errorf("invalid graph component kind type; expected ast.Kind, got %T", kind)
	}
	attrs, ok := optAttrs.([]*ast.Attr)
	if optAttrs != nil && !ok {
		return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
	}
	return &ast.AttrStmt{Kind: k, Attrs: attrs}, nil
}
func NewAttrList(attr interface{}) ([]*ast.Attr, error) {
	a, ok := attr.(*ast.Attr)
	if !ok {
		return nil, fmt.Errorf("invalid attribute type; expected *ast.Attr, got %T", attr)
	}
	return []*ast.Attr{a}, nil
}
func AppendAttr(list, attr interface{}) ([]*ast.Attr, error) {
	l, ok := list.([]*ast.Attr)
	if !ok {
		return nil, fmt.Errorf("invalid attribute list type; expected []*ast.Attr, got %T", list)
	}
	a, ok := attr.(*ast.Attr)
	if !ok {
		return nil, fmt.Errorf("invalid attribute type; expected *ast.Attr, got %T", attr)
	}
	return append(l, a), nil
}
func AppendAttrList(optList, optAttrs interface{}) ([]*ast.Attr, error) {
	list, ok := optList.([]*ast.Attr)
	if optList != nil && !ok {
		return nil, fmt.Errorf("invalid attribute list type; expected []*ast.Attr or nil, got %T", optList)
	}
	attrs, ok := optAttrs.([]*ast.Attr)
	if optAttrs != nil && !ok {
		return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
	}
	return append(list, attrs...), nil
}
func NewAttr(key, val interface{}) (*ast.Attr, error) {
	k, ok := key.(string)
	if !ok {
		return nil, fmt.Errorf("invalid key type; expected string, got %T", key)
	}
	v, ok := val.(string)
	if !ok {
		return nil, fmt.Errorf("invalid value type; expected string, got %T", val)
	}
	return &ast.Attr{Key: k, Val: v}, nil
}
func NewSubgraph(optID, optStmts interface{}) (*ast.Subgraph, error) {
	id, ok := optID.(string)
	if optID != nil && !ok {
		return nil, fmt.Errorf("invalid ID type; expected string or nil, got %T", optID)
	}
	stmts, ok := optStmts.([]ast.Stmt)
	if optStmts != nil && !ok {
		return nil, fmt.Errorf("invalid statements type; expected []ast.Stmt or nil, got %T", optStmts)
	}
	return &ast.Subgraph{ID: id, Stmts: stmts}, nil
}
func NewNode(id, optPort interface{}) (*ast.Node, error) {
	i, ok := id.(string)
	if !ok {
		return nil, fmt.Errorf("invalid ID type; expected string, got %T", id)
	}
	port, ok := optPort.(*ast.Port)
	if optPort != nil && !ok {
		return nil, fmt.Errorf("invalid port type; expected *ast.Port or nil, got %T", optPort)
	}
	return &ast.Node{ID: i, Port: port}, nil
}
func NewPort(id, optCompassPoint interface{}) (*ast.Port, error) {
	i, ok := id.(string)
	if !ok {
		return nil, fmt.Errorf("invalid ID type; expected string, got %T", id)
	}
	if optCompassPoint == nil {
		if compassPoint, ok := getCompassPoint(i); ok {
			return &ast.Port{CompassPoint: compassPoint}, nil
		}
	}
	c, ok := optCompassPoint.(string)
	if optCompassPoint != nil && !ok {
		return nil, fmt.Errorf("invalid compass point type; expected string or nil, got %T", optCompassPoint)
	}
	compassPoint, _ := getCompassPoint(c)
	return &ast.Port{ID: i, CompassPoint: compassPoint}, nil
}