github.com/openconfig/goyang@v1.4.5/pkg/yang/node.go (about)

     1  // Copyright 2015 Google Inc.
     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  
    15  package yang
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"reflect"
    22  	"strings"
    23  
    24  	"github.com/openconfig/goyang/pkg/indent"
    25  )
    26  
    27  // A Node contains a yang statement and all attributes and sub-statements.
    28  // Only pointers to structures should implement Node.
    29  type Node interface {
    30  	// Kind returns the kind of yang statement (the keyword).
    31  	Kind() string
    32  	// NName returns the node's name (the argument)
    33  	NName() string
    34  	// Statement returns the original Statement of this Node.
    35  	Statement() *Statement
    36  	// ParentNode returns the parent of this Node, or nil if the
    37  	// Node has no parent.
    38  	ParentNode() Node
    39  	// Exts returns the list of extension statements found.
    40  	Exts() []*Statement
    41  }
    42  
    43  // A Typedefer is a Node that defines typedefs.
    44  type Typedefer interface {
    45  	Node
    46  	Typedefs() []*Typedef
    47  }
    48  
    49  // An ErrorNode is a node that only contains an error.
    50  type ErrorNode struct {
    51  	Parent Node `yang:"Parent,nomerge"`
    52  
    53  	Error error
    54  }
    55  
    56  func (ErrorNode) Kind() string             { return "error" }
    57  func (s *ErrorNode) ParentNode() Node      { return s.Parent }
    58  func (s *ErrorNode) NName() string         { return "error" }
    59  func (s *ErrorNode) Statement() *Statement { return &Statement{} }
    60  func (s *ErrorNode) Exts() []*Statement    { return nil }
    61  
    62  // isRPCNode is a terrible hack to return back that a path points into
    63  // an RPC and we should ignore it.
    64  var isRPCNode = &ErrorNode{Error: errors.New("rpc is unsupported")}
    65  
    66  // Source returns the location of the source where n was defined.
    67  func Source(n Node) string {
    68  	if n != nil && n.Statement() != nil {
    69  		return n.Statement().Location()
    70  	}
    71  	return "unknown"
    72  }
    73  
    74  // getPrefix returns the prefix and base name of s.  If s has no prefix
    75  // then the returned prefix is "".
    76  func getPrefix(s string) (string, string) {
    77  	f := strings.SplitN(s, ":", 2)
    78  	if len(f) == 1 {
    79  		return "", s
    80  	}
    81  	return f[0], f[1]
    82  }
    83  
    84  // Prefix notes for types:
    85  //
    86  // If there is prefix, look in nodes ancestors.
    87  //
    88  // If prefix matches the module's prefix statement, look in nodes ancestors.
    89  //
    90  // If prefix matches the submodule's belongs-t statement, look in nodes
    91  // ancestors.
    92  //
    93  // Finally, look in the module imported with prefix.
    94  
    95  // FindModuleByPrefix finds the module or submodule with the provided prefix
    96  // relative to where n was defined.  If the prefix cannot be resolved then nil
    97  // is returned.
    98  func FindModuleByPrefix(n Node, prefix string) *Module {
    99  	if n == nil {
   100  		return nil
   101  	}
   102  	mod := RootNode(n)
   103  
   104  	if prefix == "" || prefix == mod.GetPrefix() {
   105  		return mod
   106  	}
   107  
   108  	for _, i := range mod.Import {
   109  		if prefix == i.Prefix.Name {
   110  			return mod.Modules.FindModule(i)
   111  		}
   112  	}
   113  	return nil
   114  }
   115  
   116  // MatchingExtensions returns the subset of the given node's extensions
   117  // that match the given module and identifier.
   118  func MatchingExtensions(n Node, module, identifier string) ([]*Statement, error) {
   119  	return matchingExtensions(n, n.Exts(), module, identifier)
   120  }
   121  
   122  // MatchingEntryExtensions returns the subset of the given entry's extensions
   123  // that match the given module and identifier.
   124  func MatchingEntryExtensions(e *Entry, module, identifier string) ([]*Statement, error) {
   125  	return matchingExtensions(e.Node, e.Exts, module, identifier)
   126  }
   127  
   128  // matchingEntryExtensions returns the subset of the given node's extensions
   129  // that match the given module and identifier.
   130  func matchingExtensions(n Node, exts []*Statement, module, identifier string) ([]*Statement, error) {
   131  	var matchingExtensions []*Statement
   132  	for _, ext := range exts {
   133  		names := strings.SplitN(ext.Keyword, ":", 2)
   134  		mod := FindModuleByPrefix(n, names[0])
   135  		if mod == nil {
   136  			return nil, fmt.Errorf("matchingExtensions: module prefix %q not found", names[0])
   137  		}
   138  		if len(names) == 2 && names[1] == identifier && mod.Name == module {
   139  			matchingExtensions = append(matchingExtensions, ext)
   140  		}
   141  	}
   142  	return matchingExtensions, nil
   143  }
   144  
   145  // RootNode returns the submodule or module that n was defined in.
   146  func RootNode(n Node) *Module {
   147  	for ; n.ParentNode() != nil; n = n.ParentNode() {
   148  	}
   149  	if mod, ok := n.(*Module); ok {
   150  		return mod
   151  	}
   152  	return nil
   153  }
   154  
   155  // module returns the Module to which n belongs. If n resides in a submodule,
   156  // the belonging module will be returned.
   157  // If n is nil or a module could not be find, nil is returned.
   158  func module(n Node) *Module {
   159  	m := RootNode(n)
   160  	if m.Kind() == "submodule" {
   161  		m = m.Modules.Modules[m.BelongsTo.Name]
   162  	}
   163  	return m
   164  }
   165  
   166  // NodePath returns the full path of the node from the module name.
   167  func NodePath(n Node) string {
   168  	var path string
   169  	for n != nil {
   170  		path = "/" + n.NName() + path
   171  		n = n.ParentNode()
   172  	}
   173  	return path
   174  }
   175  
   176  // FindNode finds the node referenced by path relative to n.  If path does not
   177  // reference a node then nil is returned (i.e. path not found).  The path looks
   178  // similar to an XPath but currently has no wildcarding.  For example:
   179  // "/if:interfaces/if:interface" and "../config".
   180  func FindNode(n Node, path string) (Node, error) {
   181  	if path == "" {
   182  		return n, nil
   183  	}
   184  	// / is not a valid path, it needs a module name
   185  	if path == "/" {
   186  		return nil, fmt.Errorf("invalid path %q", path)
   187  	}
   188  	// Paths do not end in /'s
   189  	if path[len(path)-1] == '/' {
   190  		return nil, fmt.Errorf("invalid path %q", path)
   191  	}
   192  
   193  	parts := strings.Split(path, "/")
   194  
   195  	// An absolute path has a leading component of "".
   196  	// We need to discover which module they are part of
   197  	// based on our imports.
   198  	if parts[0] == "" {
   199  		parts = parts[1:]
   200  
   201  		// TODO(borman): merge this with FindModuleByPrefix?
   202  		// The base is always a module
   203  		mod := RootNode(n)
   204  		n = mod
   205  		prefix, _ := getPrefix(parts[0])
   206  		if mod.Kind() == "submodule" {
   207  			m := mod.Modules.Modules[mod.BelongsTo.Name]
   208  			if m == nil {
   209  				return nil, fmt.Errorf("%s: unknown module %s", m.Name, mod.BelongsTo.Name)
   210  			}
   211  			if prefix == "" || prefix == mod.BelongsTo.Prefix.Name {
   212  				goto processing
   213  			}
   214  			mod = m
   215  		}
   216  
   217  		if prefix == "" || prefix == mod.Prefix.Name {
   218  			goto processing
   219  		}
   220  
   221  		for _, i := range mod.Import {
   222  			if prefix == i.Prefix.Name {
   223  				n = i.Module
   224  				goto processing
   225  			}
   226  		}
   227  		// We didn't find a matching prefix.
   228  		return nil, fmt.Errorf("unknown prefix: %q", prefix)
   229  	processing:
   230  		// At this point, n should be pointing to the Module node
   231  		// of module we are rooted in
   232  	}
   233  
   234  	for _, part := range parts {
   235  		// If we encounter an RPC node in our search then we
   236  		// return the magic isRPCNode Node which just contains
   237  		// an error that it is an RPC node.  isRPCNode is a singleton
   238  		// and can be checked against.
   239  		if n.Kind() == "rpc" {
   240  			return isRPCNode, nil
   241  		}
   242  		if part == ".." {
   243  		Loop:
   244  			for {
   245  				n = n.ParentNode()
   246  				if n == nil {
   247  					return nil, fmt.Errorf(".. with no parent")
   248  				}
   249  				// choice, leaf, and case nodes
   250  				// are "invisible" when doing ".."
   251  				// up the tree.
   252  				switch n.Kind() {
   253  				case "choice", "leaf", "case":
   254  				default:
   255  					break Loop
   256  				}
   257  			}
   258  			continue
   259  		}
   260  		// For now just strip off any prefix
   261  		// TODO(borman): fix this
   262  		_, spart := getPrefix(part)
   263  		n = ChildNode(n, spart)
   264  		if n == nil {
   265  			return nil, fmt.Errorf("%s: no such element", part)
   266  		}
   267  	}
   268  	return n, nil
   269  }
   270  
   271  // ChildNode finds n's child node named name.  It returns nil if the node
   272  // could not be found.  ChildNode looks at every direct Node pointer in
   273  // n as well as every node in all slices of Node pointers.  Names must
   274  // be non-ambiguous, otherwise ChildNode has a non-deterministic result.
   275  func ChildNode(n Node, name string) Node {
   276  	v := reflect.ValueOf(n).Elem()
   277  	t := v.Type()
   278  	nf := t.NumField()
   279  
   280  Loop:
   281  	for i := 0; i < nf; i++ {
   282  		ft := t.Field(i)
   283  		yang := ft.Tag.Get("yang")
   284  		if yang == "" {
   285  			continue
   286  		}
   287  		parts := strings.Split(yang, ",")
   288  		for _, p := range parts[1:] {
   289  			if p == "nomerge" {
   290  				continue Loop
   291  			}
   292  		}
   293  
   294  		f := v.Field(i)
   295  		if !f.IsValid() || f.IsNil() {
   296  			continue
   297  		}
   298  
   299  		check := func(n Node) Node {
   300  			if n.NName() == name {
   301  				return n
   302  			}
   303  			return nil
   304  		}
   305  		if parts[0] == "uses" {
   306  			check = func(n Node) Node {
   307  				uname := n.NName()
   308  				// unrooted uses are rooted at root
   309  				if !strings.HasPrefix(uname, "/") {
   310  					uname = "/" + uname
   311  				}
   312  				if n, _ = FindNode(n, uname); n != nil {
   313  					return ChildNode(n, name)
   314  				}
   315  				return nil
   316  			}
   317  		}
   318  
   319  		switch ft.Type.Kind() {
   320  		case reflect.Ptr:
   321  			if n = check(f.Interface().(Node)); n != nil {
   322  				return n
   323  			}
   324  		case reflect.Slice:
   325  			sl := f.Len()
   326  			for i := 0; i < sl; i++ {
   327  				n = f.Index(i).Interface().(Node)
   328  				if n = check(n); n != nil {
   329  					return n
   330  				}
   331  			}
   332  		}
   333  	}
   334  	return nil
   335  }
   336  
   337  // PrintNode prints node n to w, recursively.
   338  // TODO(borman): display more information
   339  func PrintNode(w io.Writer, n Node) {
   340  	v := reflect.ValueOf(n).Elem()
   341  	t := v.Type()
   342  	nf := t.NumField()
   343  	fmt.Fprintf(w, "%s [%s]\n", n.NName(), n.Kind())
   344  Loop:
   345  	for i := 0; i < nf; i++ {
   346  		ft := t.Field(i)
   347  		yang := ft.Tag.Get("yang")
   348  		if yang == "" {
   349  			continue
   350  		}
   351  		parts := strings.Split(yang, ",")
   352  		for _, p := range parts[1:] {
   353  			if p == "nomerge" {
   354  				continue Loop
   355  			}
   356  		}
   357  
   358  		// Skip uppercase elements.
   359  		if parts[0][0] >= 'A' && parts[0][0] <= 'Z' {
   360  			continue
   361  		}
   362  
   363  		f := v.Field(i)
   364  		if !f.IsValid() || f.IsNil() {
   365  			continue
   366  		}
   367  
   368  		switch ft.Type.Kind() {
   369  		case reflect.Ptr:
   370  			n = f.Interface().(Node)
   371  			if v, ok := n.(*Value); ok {
   372  				fmt.Fprintf(w, "%s = %s\n", ft.Name, v.Name)
   373  			} else {
   374  				PrintNode(indent.NewWriter(w, "    "), n)
   375  			}
   376  		case reflect.Slice:
   377  			sl := f.Len()
   378  			for i := 0; i < sl; i++ {
   379  				n = f.Index(i).Interface().(Node)
   380  				if v, ok := n.(*Value); ok {
   381  					fmt.Fprintf(w, "%s[%d] = %s\n", ft.Name, i, v.Name)
   382  				} else {
   383  					PrintNode(indent.NewWriter(w, "    "), n)
   384  				}
   385  			}
   386  		}
   387  	}
   388  }