github.com/openconfig/goyang@v1.4.5/pkg/yang/entry.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  // The file contains the code to convert an AST (Node) tree into an Entry tree
    18  // via the ToEntry function.  The entry tree, once fully resolved, is the
    19  // product of this package.  The tree should have all types and references
    20  // resolved.
    21  //
    22  // TODO(borman): handle types, leafrefs, and extensions
    23  
    24  import (
    25  	"errors"
    26  	"fmt"
    27  	"io"
    28  	"math"
    29  	"reflect"
    30  	"sort"
    31  	"strconv"
    32  	"strings"
    33  
    34  	"github.com/openconfig/goyang/pkg/indent"
    35  )
    36  
    37  // A TriState may be true, false, or unset
    38  type TriState int
    39  
    40  // The possible states of a TriState.
    41  const (
    42  	TSUnset = TriState(iota)
    43  	TSTrue
    44  	TSFalse
    45  )
    46  
    47  // Value returns the value of t as a boolean.  Unset is returned as false.
    48  func (t TriState) Value() bool {
    49  	return t == TSTrue
    50  }
    51  
    52  // String displays t as a string.
    53  func (t TriState) String() string {
    54  	switch t {
    55  	case TSUnset:
    56  		return "unset"
    57  	case TSTrue:
    58  		return "true"
    59  	case TSFalse:
    60  		return "false"
    61  	default:
    62  		return fmt.Sprintf("ts-%d", t)
    63  	}
    64  }
    65  
    66  // deviationPresence stores whether certain attributes for a DeviateEntry-type
    67  // Entry have been given deviation values. This is useful when the attribute
    68  // doesn't have a presence indicator (e.g. non-pointers).
    69  type deviationPresence struct {
    70  	hasMinElements bool
    71  	hasMaxElements bool
    72  }
    73  
    74  // Entry represents a single schema tree node, which can be a directory
    75  // (containing a subtree) or a leaf node (which contains YANG types that have
    76  // no children, e.g., leaf, leaf-list). They can be distinguished by whether
    77  // their "Dir" field is nil. This object is created from a corresponding AST
    78  // node after applying modifications (i.e. uses, augments, deviations). If
    79  // Errors is not nil then it means semantic errors existed while converting the
    80  // AST, in which case the only other valid field other than Errors is Node.
    81  type Entry struct {
    82  	Parent      *Entry `json:"-"`
    83  	Node        Node   `json:"-"` // the base node this Entry was derived from.
    84  	Name        string // our name, same as the key in our parent Dirs
    85  	Description string `json:",omitempty"` // description from node, if any
    86  	// Default value for the node, if any. Note that only leaf-lists may
    87  	// have more than one value. For all other types, use the
    88  	// SingleDefaultValue() method to access the default value.
    89  	Default   []string  `json:",omitempty"`
    90  	Units     string    `json:",omitempty"` // units associated with the type, if any
    91  	Errors    []error   `json:"-"`          // list of errors encountered on this node
    92  	Kind      EntryKind // kind of Entry
    93  	Config    TriState  // config state of this entry, if known
    94  	Prefix    *Value    `json:",omitempty"` // prefix to use from this point down
    95  	Mandatory TriState  `json:",omitempty"` // whether this entry is mandatory in the tree
    96  
    97  	// Fields associated with directory nodes
    98  	Dir map[string]*Entry `json:",omitempty"`
    99  	Key string            `json:",omitempty"` // Optional key name for lists (i.e., maps)
   100  
   101  	// Fields associated with leaf nodes
   102  	Type *YangType `json:",omitempty"`
   103  
   104  	// Extensions found
   105  	Exts []*Statement `json:",omitempty"`
   106  
   107  	// Fields associated with list nodes (both lists and leaf-lists)
   108  	ListAttr *ListAttr `json:",omitempty"`
   109  
   110  	RPC *RPCEntry `json:",omitempty"` // set if we are an RPC
   111  
   112  	// Identities that are defined in this context, this is set if the Entry
   113  	// is a module only.
   114  	Identities []*Identity `json:",omitempty"`
   115  
   116  	Augments   []*Entry                   `json:",omitempty"` // Augments defined in this entry.
   117  	Augmented  []*Entry                   `json:",omitempty"` // Augments merged into this entry.
   118  	Deviations []*DeviatedEntry           `json:"-"`          // Deviations associated with this entry.
   119  	Deviate    map[deviationType][]*Entry `json:"-"`
   120  	// deviationPresence tracks whether certain attributes for a DeviateEntry-type
   121  	// Entry have been given deviation values.
   122  	deviatePresence deviationPresence
   123  	Uses            []*UsesStmt `json:",omitempty"` // Uses merged into this entry.
   124  
   125  	// Extra maps all the unsupported fields to their values
   126  	Extra map[string][]interface{} `json:"extra-unstable,omitempty"`
   127  
   128  	// Annotation stores annotated values, and is not populated by this
   129  	// library but rather can be used by calling code where additional
   130  	// information should be stored alongside the Entry.
   131  	Annotation map[string]interface{} `json:",omitempty"`
   132  
   133  	// namespace stores the namespace of the Entry if it overrides the
   134  	// root namespace within the schema tree. This is the case where an
   135  	// entry is augmented into the tree, and it retains the namespace of
   136  	// the augmenting entity per RFC6020 Section 7.15.2. The namespace
   137  	// of the Entry should be accessed using the Namespace function.
   138  	namespace *Value
   139  }
   140  
   141  // An RPCEntry contains information related to an RPC Node.
   142  type RPCEntry struct {
   143  	Input  *Entry
   144  	Output *Entry
   145  }
   146  
   147  // A ListAttr is associated with an Entry that represents a List node
   148  type ListAttr struct {
   149  	MinElements uint64 // leaf-list or list MUST have at least min-elements
   150  	MaxElements uint64 // leaf-list or list has at most max-elements
   151  	// OrderedBy is deprecated. Use OrderedByUser instead.
   152  	OrderedBy *Value
   153  	// OrderedByUser indicates whether the entries are "ordered-by user".
   154  	// Otherwise the order is determined by the system.
   155  	OrderedByUser bool
   156  }
   157  
   158  // parseOrderedBy parses the ordered-by value and classifies the list/leaf-list
   159  // by whether the `ordered-by user` modifier is active.
   160  //
   161  // For more information see
   162  // https://datatracker.ietf.org/doc/html/rfc7950#section-7.7.7
   163  func (l *ListAttr) parseOrderedBy(s *Value) error {
   164  	if s == nil {
   165  		return nil
   166  	}
   167  	l.OrderedBy = s
   168  	switch s.Name {
   169  	case "user":
   170  		l.OrderedByUser = true
   171  	case "system":
   172  	default:
   173  		return fmt.Errorf("%s: ordered-by has invalid argument: %q", Source(s), s.Name)
   174  	}
   175  	return nil
   176  }
   177  
   178  // NewDefaultListAttr returns a new ListAttr object with min/max elements being
   179  // set to 0/math.MaxUint64 respectively.
   180  func NewDefaultListAttr() *ListAttr {
   181  	return &ListAttr{
   182  		MinElements: 0,
   183  		MaxElements: math.MaxUint64,
   184  	}
   185  }
   186  
   187  // A UsesStmt associates a *Uses with its referenced grouping *Entry
   188  type UsesStmt struct {
   189  	Uses     *Uses
   190  	Grouping *Entry
   191  }
   192  
   193  // Modules returns the Modules structure that e is part of.  This is needed
   194  // when looking for rooted nodes not part of this Entry tree.
   195  func (e *Entry) Modules() *Modules {
   196  	for e.Parent != nil {
   197  		e = e.Parent
   198  	}
   199  	return e.Node.(*Module).Modules
   200  }
   201  
   202  // IsDir returns true if e is a directory.
   203  func (e *Entry) IsDir() bool {
   204  	return e.Dir != nil
   205  }
   206  
   207  // IsLeaf returns true if e is a leaf i.e. is not a container, list, leaf-list,
   208  // choice or case statement.
   209  func (e *Entry) IsLeaf() bool {
   210  	return !e.IsDir() && e.Kind == LeafEntry && e.ListAttr == nil
   211  }
   212  
   213  // IsLeafList returns true if e is a leaf-list.
   214  func (e *Entry) IsLeafList() bool {
   215  	return !e.IsDir() && e.Kind == LeafEntry && e.ListAttr != nil
   216  }
   217  
   218  // IsList returns true if e is a list.
   219  func (e *Entry) IsList() bool {
   220  	return e.IsDir() && e.ListAttr != nil
   221  }
   222  
   223  // IsContainer returns true if e is a container.
   224  func (e *Entry) IsContainer() bool {
   225  	return e.Kind == DirectoryEntry && e.ListAttr == nil
   226  }
   227  
   228  // IsChoice returns true if the entry is a choice node within the schema.
   229  func (e *Entry) IsChoice() bool {
   230  	return e.Kind == ChoiceEntry
   231  }
   232  
   233  // IsCase returns true if the entry is a case node within the schema.
   234  func (e *Entry) IsCase() bool {
   235  	return e.Kind == CaseEntry
   236  }
   237  
   238  // Print prints e to w in human readable form.
   239  func (e *Entry) Print(w io.Writer) {
   240  	if e.Description != "" {
   241  		fmt.Fprintln(w)
   242  		fmt.Fprintln(indent.NewWriter(w, "// "), e.Description)
   243  	}
   244  	if e.ReadOnly() {
   245  		fmt.Fprintf(w, "RO: ")
   246  	} else {
   247  		fmt.Fprintf(w, "rw: ")
   248  	}
   249  	if e.Type != nil {
   250  		fmt.Fprintf(w, "%s ", e.Type.Name)
   251  	}
   252  	switch {
   253  	case e.Dir == nil && e.ListAttr != nil:
   254  		fmt.Fprintf(w, "[]%s\n", e.Name)
   255  		return
   256  	case e.Dir == nil:
   257  		fmt.Fprintf(w, "%s\n", e.Name)
   258  		return
   259  	case e.ListAttr != nil:
   260  		fmt.Fprintf(w, "[%s]%s {\n", e.Key, e.Name) //}
   261  	default:
   262  		fmt.Fprintf(w, "%s {\n", e.Name) //}
   263  	}
   264  	var names []string
   265  	for k := range e.Dir {
   266  		names = append(names, k)
   267  	}
   268  	sort.Strings(names)
   269  	for _, k := range names {
   270  		e.Dir[k].Print(indent.NewWriter(w, "  "))
   271  	}
   272  	// { to match the brace below to keep brace matching working
   273  	fmt.Fprintln(w, "}")
   274  }
   275  
   276  // An EntryKind is the kind of node an Entry is.  All leaf nodes are of kind
   277  // LeafEntry.  A LeafList is also considered a leaf node.  All other kinds are
   278  // directory nodes.
   279  type EntryKind int
   280  
   281  // Enumeration of the types of entries.
   282  const (
   283  	LeafEntry = EntryKind(iota)
   284  	DirectoryEntry
   285  	AnyDataEntry
   286  	AnyXMLEntry
   287  	CaseEntry
   288  	ChoiceEntry
   289  	InputEntry
   290  	NotificationEntry
   291  	OutputEntry
   292  	DeviateEntry
   293  )
   294  
   295  // EntryKindToName maps EntryKind to their names
   296  var EntryKindToName = map[EntryKind]string{
   297  	LeafEntry:         "Leaf",
   298  	DirectoryEntry:    "Directory",
   299  	AnyDataEntry:      "AnyData",
   300  	AnyXMLEntry:       "AnyXML",
   301  	CaseEntry:         "Case",
   302  	ChoiceEntry:       "Choice",
   303  	InputEntry:        "Input",
   304  	NotificationEntry: "Notification",
   305  	OutputEntry:       "Output",
   306  	DeviateEntry:      "Deviate",
   307  }
   308  
   309  func (k EntryKind) String() string {
   310  	if s := EntryKindToName[k]; s != "" {
   311  		return s
   312  	}
   313  	return fmt.Sprintf("unknown-entry-%d", k)
   314  }
   315  
   316  // newDirectory returns an empty directory Entry.
   317  func newDirectory(n Node) *Entry {
   318  	return &Entry{
   319  		Kind:  DirectoryEntry,
   320  		Dir:   make(map[string]*Entry),
   321  		Node:  n,
   322  		Name:  n.NName(),
   323  		Extra: map[string][]interface{}{},
   324  	}
   325  }
   326  
   327  // newLeaf returns an empty leaf Entry.
   328  func newLeaf(n Node) *Entry {
   329  	return &Entry{
   330  		Kind:  LeafEntry,
   331  		Node:  n,
   332  		Name:  n.NName(),
   333  		Extra: map[string][]interface{}{},
   334  	}
   335  }
   336  
   337  // newError returns an error Entry using format and v to create the error
   338  // contained in the node.  The location of the error is prepended.
   339  func newError(n Node, format string, v ...interface{}) *Entry {
   340  	e := &Entry{Node: n}
   341  	e.errorf("%s: "+format, append([]interface{}{Source(n)}, v...)...)
   342  	return e
   343  }
   344  
   345  // errorf appends the error constructed from string and v to the list of errors
   346  // on e.
   347  func (e *Entry) errorf(format string, v ...interface{}) {
   348  	e.Errors = append(e.Errors, fmt.Errorf(format, v...))
   349  }
   350  
   351  // addError appends err to the list of errors on e if err is not nil.
   352  func (e *Entry) addError(err error) {
   353  	if err != nil {
   354  		e.Errors = append(e.Errors, err)
   355  	}
   356  }
   357  
   358  // importErrors imports all the errors from c and its children into e.
   359  func (e *Entry) importErrors(c *Entry) {
   360  	if c == nil {
   361  		return
   362  	}
   363  	for _, err := range c.Errors {
   364  		e.addError(err)
   365  	}
   366  	// TODO(borman): need to determine if the extensions have errors
   367  	// for _, ce := range e.Exts {
   368  	// 	e.importErrors(ce)
   369  	// }
   370  	for _, ce := range c.Dir {
   371  		e.importErrors(ce)
   372  	}
   373  }
   374  
   375  // checkErrors calls f on every error found in the tree e and its children.
   376  func (e *Entry) checkErrors(f func(error)) {
   377  	if e == nil {
   378  		return
   379  	}
   380  	for _, e := range e.Dir {
   381  		e.checkErrors(f)
   382  	}
   383  	for _, err := range e.Errors {
   384  		f(err)
   385  	}
   386  	// TODO(borman): need to determine if the extensions have errors
   387  	// for _, e := range e.Exts {
   388  	// 	e.checkErrors(f)
   389  	// }
   390  }
   391  
   392  // GetErrors returns a sorted list of errors found in e.
   393  func (e *Entry) GetErrors() []error {
   394  	// the seen map is used to eliminate duplicate errors.
   395  	// Some entries will be processed more than once
   396  	// (groupings in particular) and as such may cause
   397  	// duplication of errors.
   398  	seen := map[error]bool{}
   399  	var errs []error
   400  	e.checkErrors(func(err error) {
   401  		if !seen[err] {
   402  			errs = append(errs, err)
   403  			seen[err] = true
   404  		}
   405  	})
   406  	return errorSort(errs)
   407  }
   408  
   409  // add adds the directory entry key assigned to the provided value.
   410  func (e *Entry) add(key string, value *Entry) *Entry {
   411  	value.Parent = e
   412  	if e.Dir[key] != nil {
   413  		e.errorf("%s: duplicate key from %s: %s", Source(e.Node), Source(value.Node), key)
   414  		return e
   415  	}
   416  	e.Dir[key] = value
   417  	return e
   418  }
   419  
   420  // delete removes the directory entry key from the entry.
   421  func (e *Entry) delete(key string) {
   422  	if _, ok := e.Dir[key]; !ok {
   423  		e.errorf("%s: unknown child key %s", Source(e.Node), key)
   424  	}
   425  	delete(e.Dir, key)
   426  }
   427  
   428  // GetWhenXPath returns the when XPath statement of e if able.
   429  func (e *Entry) GetWhenXPath() (string, bool) {
   430  	switch n := e.Node.(type) {
   431  	case *Container:
   432  		if n.When != nil && n.When.Statement() != nil {
   433  			return n.When.Statement().Arg()
   434  		}
   435  	case *Leaf:
   436  		if n.When != nil && n.When.Statement() != nil {
   437  			return n.When.Statement().Arg()
   438  		}
   439  	case *LeafList:
   440  		if n.When != nil && n.When.Statement() != nil {
   441  			return n.When.Statement().Arg()
   442  		}
   443  	case *List:
   444  		if n.When != nil && n.When.Statement() != nil {
   445  			return n.When.Statement().Arg()
   446  		}
   447  	case *Choice:
   448  		if n.When != nil && n.When.Statement() != nil {
   449  			return n.When.Statement().Arg()
   450  		}
   451  	case *Case:
   452  		if n.When != nil && n.When.Statement() != nil {
   453  			return n.When.Statement().Arg()
   454  		}
   455  	case *AnyXML:
   456  		if n.When != nil && n.When.Statement() != nil {
   457  			return n.When.Statement().Arg()
   458  		}
   459  	case *AnyData:
   460  		if n.When != nil && n.When.Statement() != nil {
   461  			return n.When.Statement().Arg()
   462  		}
   463  	case *Augment:
   464  		if n.When != nil && n.When.Statement() != nil {
   465  			return n.When.Statement().Arg()
   466  		}
   467  	}
   468  	return "", false
   469  }
   470  
   471  // deviationType specifies an enumerated value covering the different substatements
   472  // to the deviate statement.
   473  type deviationType int64
   474  
   475  const (
   476  	// DeviationUnset specifies that the argument was unset, which is invalid.
   477  	DeviationUnset deviationType = iota
   478  	// DeviationNotSupported corresponds to the not-supported deviate argument.
   479  	DeviationNotSupported
   480  	// DeviationAdd corresponds to the add deviate argument to the deviate stmt.
   481  	DeviationAdd
   482  	// DeviationReplace corresponds to the replace argument to the deviate stmt.
   483  	DeviationReplace
   484  	// DeviationDelete corresponds to the delete argument to the deviate stmt.
   485  	DeviationDelete
   486  )
   487  
   488  var (
   489  	// fromDeviation maps from an enumerated deviation type to the YANG keyword.
   490  	fromDeviation = map[deviationType]string{
   491  		DeviationNotSupported: "not-supported",
   492  		DeviationAdd:          "add",
   493  		DeviationReplace:      "replace",
   494  		DeviationDelete:       "delete",
   495  		DeviationUnset:        "unknown",
   496  	}
   497  
   498  	// toDeviation maps from the YANG keyword to an enumerated deviation type.
   499  	toDeviation = map[string]deviationType{
   500  		"not-supported": DeviationNotSupported,
   501  		"add":           DeviationAdd,
   502  		"replace":       DeviationReplace,
   503  		"delete":        DeviationDelete,
   504  	}
   505  )
   506  
   507  func (d deviationType) String() string {
   508  	return fromDeviation[d]
   509  }
   510  
   511  // DeviatedEntry stores a wrapped Entry that corresponds to a deviation.
   512  type DeviatedEntry struct {
   513  	Type         deviationType // Type specifies the deviation type.
   514  	DeviatedPath string        // DeviatedPath corresponds to the path that is being deviated.
   515  	// Entry is the embedded Entry storing the deviations that are made. Fields
   516  	// are set to the value in the schema after the deviation has been applied.
   517  	*Entry
   518  }
   519  
   520  // semCheckMaxElements checks whether the max-element argument is valid, and returns the specified value.
   521  func semCheckMaxElements(v *Value) (uint64, error) {
   522  	if v == nil || v.Name == "unbounded" {
   523  		return math.MaxUint64, nil
   524  	}
   525  	val, err := strconv.ParseUint(v.Name, 10, 64)
   526  	if err != nil {
   527  		return val, fmt.Errorf(`%s: invalid max-elements value %q (expect "unbounded" or a positive integer): %v`, Source(v), v.Name, err)
   528  	}
   529  	if val == 0 {
   530  		return val, fmt.Errorf(`%s: invalid max-elements value 0 (expect "unbounded" or a positive integer)`, Source(v))
   531  	}
   532  	return val, nil
   533  }
   534  
   535  // semCheckMinElements checks whether the min-element argument is valid, and returns the specified value.
   536  func semCheckMinElements(v *Value) (uint64, error) {
   537  	if v == nil {
   538  		return 0, nil
   539  	}
   540  	val, err := strconv.ParseUint(v.Name, 10, 64)
   541  	if err != nil {
   542  		return val, fmt.Errorf(`%s: invalid min-elements value %q (expect a non-negative integer): %v`, Source(v), v.Name, err)
   543  	}
   544  	return val, nil
   545  }
   546  
   547  // ToEntry expands node n into a directory Entry.  Expansion is based on the
   548  // YANG tags in the structure behind n.  ToEntry must only be used
   549  // with nodes that are directories, such as top level modules and sub-modules.
   550  // ToEntry never returns nil.  Any errors encountered are found in the Errors
   551  // fields of the returned Entry and its children.  Use GetErrors to determine
   552  // if there were any errors.
   553  func ToEntry(n Node) (e *Entry) {
   554  	if n == nil {
   555  		err := errors.New("ToEntry called on nil AST node")
   556  		return &Entry{
   557  			Node:   &ErrorNode{Error: err},
   558  			Errors: []error{err},
   559  		}
   560  	}
   561  	ms := RootNode(n).Modules
   562  	if e := ms.getEntryCache(n); e != nil {
   563  		return e
   564  	}
   565  	defer func() {
   566  		ms.setEntryCache(n, e)
   567  	}()
   568  
   569  	// Copy in the extensions from our Node, if any.
   570  	defer func(n Node) {
   571  		if e != nil {
   572  			e.Exts = append(e.Exts, n.Exts()...)
   573  		}
   574  	}(n)
   575  
   576  	// tristateValue returns TSTrue if i contains the value of true, TSFalse
   577  	// if it contains the value of false, and TSUnset if i does not have
   578  	// a set value (for instance, i is nil).  An error is returned if i
   579  	// contains a value other than true or false.
   580  	tristateValue := func(i interface{}) (TriState, error) {
   581  		if v, ok := i.(*Value); ok && v != nil {
   582  			switch v.Name {
   583  			case "true":
   584  				return TSTrue, nil
   585  			case "false":
   586  				return TSFalse, nil
   587  			default:
   588  				return TSUnset, fmt.Errorf("%s: invalid config value: %s", Source(n), v.Name)
   589  			}
   590  		}
   591  		return TSUnset, nil
   592  	}
   593  
   594  	var err error
   595  	// Handle non-directory nodes (leaf, leafref, and oddly enough, uses).
   596  	switch s := n.(type) {
   597  	case *Leaf:
   598  		e := newLeaf(n)
   599  		if errs := s.Type.resolve(ms.typeDict); errs != nil {
   600  			e.Errors = errs
   601  		}
   602  		if s.Description != nil {
   603  			e.Description = s.Description.Name
   604  		}
   605  		if s.Default != nil {
   606  			e.Default = []string{s.Default.Name}
   607  		}
   608  		e.Type = s.Type.YangType
   609  		e.Config, err = tristateValue(s.Config)
   610  		e.addError(err)
   611  		e.Prefix = getRootPrefix(e)
   612  		addExtraKeywordsToLeafEntry(n, e)
   613  		e.Mandatory, err = tristateValue(s.Mandatory)
   614  		e.addError(err)
   615  		return e
   616  	case *LeafList:
   617  		// Create the equivalent leaf element that we are a list of.
   618  		// We can then just annotate it as a list rather than a leaf.
   619  		leaf := &Leaf{
   620  			Name:        s.Name,
   621  			Source:      s.Source,
   622  			Parent:      s.Parent,
   623  			Extensions:  s.Extensions,
   624  			Config:      s.Config,
   625  			Description: s.Description,
   626  			IfFeature:   s.IfFeature,
   627  			Must:        s.Must,
   628  			Reference:   s.Reference,
   629  			Status:      s.Status,
   630  			Type:        s.Type,
   631  			Units:       s.Units,
   632  			When:        s.When,
   633  		}
   634  
   635  		e = ToEntry(leaf)
   636  		e.ListAttr = NewDefaultListAttr()
   637  		if err := e.ListAttr.parseOrderedBy(s.OrderedBy); err != nil {
   638  			e.addError(err)
   639  		}
   640  		var err error
   641  		if e.ListAttr.MaxElements, err = semCheckMaxElements(s.MaxElements); err != nil {
   642  			e.addError(err)
   643  		}
   644  		if e.ListAttr.MinElements, err = semCheckMinElements(s.MinElements); err != nil {
   645  			e.addError(err)
   646  		}
   647  		if len(s.Default) != 0 {
   648  			for _, def := range s.Default {
   649  				e.Default = append(e.Default, def.Name)
   650  			}
   651  		}
   652  		e.Prefix = getRootPrefix(e)
   653  		return e
   654  	case *Uses:
   655  		g := FindGrouping(s, s.Name, map[string]bool{})
   656  		if g == nil {
   657  			return newError(n, "unknown group: %s", s.Name)
   658  		}
   659  		// We need to return a duplicate so we resolve properly
   660  		// when the group is used in multiple locations and the
   661  		// grouping has a leafref that references outside the group.
   662  		e = ToEntry(g).dup()
   663  		addExtraKeywordsToLeafEntry(n, e)
   664  		return e
   665  	}
   666  
   667  	e = newDirectory(n)
   668  
   669  	// Special handling for individual Node types.  Lists are like any other
   670  	// node except a List has a ListAttr.
   671  	//
   672  	// Nodes of identified special kinds have their Kind set here.
   673  	switch s := n.(type) {
   674  	case *List:
   675  		e.ListAttr = NewDefaultListAttr()
   676  		if err := e.ListAttr.parseOrderedBy(s.OrderedBy); err != nil {
   677  			e.addError(err)
   678  		}
   679  		var err error
   680  		if e.ListAttr.MaxElements, err = semCheckMaxElements(s.MaxElements); err != nil {
   681  			e.addError(err)
   682  		}
   683  		if e.ListAttr.MinElements, err = semCheckMinElements(s.MinElements); err != nil {
   684  			e.addError(err)
   685  		}
   686  	case *Choice:
   687  		e.Kind = ChoiceEntry
   688  		if s.Default != nil {
   689  			e.Default = []string{s.Default.Name}
   690  		}
   691  	case *Case:
   692  		e.Kind = CaseEntry
   693  	case *AnyData:
   694  		e.Kind = AnyDataEntry
   695  	case *AnyXML:
   696  		e.Kind = AnyXMLEntry
   697  	case *Input:
   698  		e.Kind = InputEntry
   699  	case *Output:
   700  		e.Kind = OutputEntry
   701  	case *Notification:
   702  		e.Kind = NotificationEntry
   703  	case *Deviate:
   704  		e.Kind = DeviateEntry
   705  	}
   706  
   707  	// Use Elem to get the Value of structure that n is pointing to.
   708  	v := reflect.ValueOf(n).Elem()
   709  	t := v.Type()
   710  	found := false
   711  
   712  	for i := t.NumField() - 1; i > 0; i-- {
   713  		f := t.Field(i)
   714  		yang := f.Tag.Get("yang")
   715  		if yang == "" {
   716  			continue
   717  		}
   718  		fv := v.Field(i)
   719  		name := strings.Split(yang, ",")[0]
   720  		switch name {
   721  		case "":
   722  			e.addError(fmt.Errorf("%s: nil statement", Source(n)))
   723  		case "config":
   724  			e.Config, err = tristateValue(fv.Interface())
   725  			e.addError(err)
   726  		case "description":
   727  			if v := fv.Interface().(*Value); v != nil {
   728  				e.Description = v.Name
   729  			}
   730  		case "prefix":
   731  			if v := fv.Interface().(*Value); v != nil {
   732  				e.Prefix = v
   733  			}
   734  		case "action":
   735  			for _, r := range fv.Interface().([]*Action) {
   736  				e.add(r.Name, ToEntry(r))
   737  			}
   738  		case "augment":
   739  			for _, a := range fv.Interface().([]*Augment) {
   740  				ne := ToEntry(a)
   741  				ne.Parent = e
   742  				e.Augments = append(e.Augments, ne)
   743  			}
   744  		case "anydata":
   745  			for _, a := range fv.Interface().([]*AnyData) {
   746  				e.add(a.Name, ToEntry(a))
   747  			}
   748  		case "anyxml":
   749  			for _, a := range fv.Interface().([]*AnyXML) {
   750  				e.add(a.Name, ToEntry(a))
   751  			}
   752  		case "case":
   753  			for _, a := range fv.Interface().([]*Case) {
   754  				e.add(a.Name, ToEntry(a))
   755  			}
   756  		case "choice":
   757  			for _, a := range fv.Interface().([]*Choice) {
   758  				e.add(a.Name, ToEntry(a))
   759  			}
   760  		case "container":
   761  			for _, a := range fv.Interface().([]*Container) {
   762  				e.add(a.Name, ToEntry(a))
   763  			}
   764  		case "grouping":
   765  			for _, a := range fv.Interface().([]*Grouping) {
   766  				// We just want to parse the grouping to
   767  				// collect errors.
   768  				e.importErrors(ToEntry(a))
   769  			}
   770  		case "import":
   771  			// Import only makes types and such available.
   772  			// There is nothing else for us to do.
   773  		case "include":
   774  			for _, a := range fv.Interface().([]*Include) {
   775  				// Handle circular dependencies between submodules. This can occur in
   776  				// two ways:
   777  				//  - Where submodule A imports submodule B, and vice versa then the
   778  				//    whilst processing A we will also try and process A (learnt via
   779  				//    B). The default case of the switch handles this case.
   780  				//  - Where submodule A imports submodule B that imports C, which also
   781  				//    imports A, then we need to check whether we already have merged
   782  				//    the specified module during this parse attempt. We check this
   783  				//    against a map of merged submodules.
   784  				// The key of the map used is a synthesised value which is formed by
   785  				// concatenating the name of this node and the included submodule,
   786  				// separated by a ":".
   787  				srcToIncluded := a.Module.Name + ":" + n.NName()
   788  				includedToSrc := n.NName() + ":" + a.Module.Name
   789  
   790  				switch {
   791  				case ms.mergedSubmodule[srcToIncluded]:
   792  					// We have already merged this module, so don't try and do it
   793  					// again.
   794  					continue
   795  				case !ms.mergedSubmodule[includedToSrc] && a.Module.NName() != n.NName():
   796  					// We have not merged A->B, and B != B hence go ahead and merge.
   797  					includedToParent := a.Module.Name + ":" + a.Module.BelongsTo.Name
   798  					if ms.mergedSubmodule[includedToParent] {
   799  						// Don't try and re-import submodules that have already been imported
   800  						// into the top-level module. Note that this ensures that we get to the
   801  						// top the tree (whichever the actual module for the chain of
   802  						// submodules is). The tracking of the immediate parent is achieved
   803  						// through 'key', which ensures that we do not end up in loops
   804  						// walking through a sub-cycle of the include graph.
   805  						continue
   806  					}
   807  					ms.mergedSubmodule[srcToIncluded] = true
   808  					ms.mergedSubmodule[includedToParent] = true
   809  					e.merge(a.Module.Prefix, nil, ToEntry(a.Module))
   810  				case ms.ParseOptions.IgnoreSubmoduleCircularDependencies:
   811  					continue
   812  				default:
   813  					e.addError(fmt.Errorf("%s: has a circular dependency, importing %s", n.NName(), a.Module.NName()))
   814  				}
   815  			}
   816  		case "leaf":
   817  			for _, a := range fv.Interface().([]*Leaf) {
   818  				e.add(a.Name, ToEntry(a))
   819  			}
   820  		case "leaf-list":
   821  			for _, a := range fv.Interface().([]*LeafList) {
   822  				e.add(a.Name, ToEntry(a))
   823  			}
   824  		case "list":
   825  			for _, a := range fv.Interface().([]*List) {
   826  				e.add(a.Name, ToEntry(a))
   827  			}
   828  		case "key":
   829  			if v := fv.Interface().(*Value); v != nil {
   830  				e.Key = v.Name
   831  			}
   832  		case "notification":
   833  			for _, a := range fv.Interface().([]*Notification) {
   834  				e.add(a.Name, ToEntry(a))
   835  			}
   836  		case "rpc":
   837  			// TODO(borman): what do we do with these?
   838  			// seems fine to ignore them for now, we are
   839  			// just interested in the tree structure.
   840  			for _, r := range fv.Interface().([]*RPC) {
   841  				switch rpc := ToEntry(r); {
   842  				case rpc.RPC == nil:
   843  					// When "rpc" has no "input" or "output" children
   844  					rpc.RPC = &RPCEntry{}
   845  					fallthrough
   846  				default:
   847  					e.add(r.Name, rpc)
   848  				}
   849  			}
   850  
   851  		case "input":
   852  			if i := fv.Interface().(*Input); i != nil {
   853  				if e.RPC == nil {
   854  					e.RPC = &RPCEntry{}
   855  				}
   856  				in := ToEntry(i)
   857  				in.Parent = e
   858  				e.RPC.Input = in
   859  				e.RPC.Input.Name = "input"
   860  				e.RPC.Input.Kind = InputEntry
   861  			}
   862  		case "output":
   863  			if o := fv.Interface().(*Output); o != nil {
   864  				if e.RPC == nil {
   865  					e.RPC = &RPCEntry{}
   866  				}
   867  				out := ToEntry(o)
   868  				out.Parent = e
   869  				e.RPC.Output = out
   870  				e.RPC.Output.Name = "output"
   871  				e.RPC.Output.Kind = OutputEntry
   872  			}
   873  		case "identity":
   874  			if i := fv.Interface().([]*Identity); i != nil {
   875  				e.Identities = i
   876  			}
   877  		case "uses":
   878  			for _, a := range fv.Interface().([]*Uses) {
   879  				grouping := ToEntry(a)
   880  				e.merge(nil, nil, grouping)
   881  				if ms.ParseOptions.StoreUses {
   882  					e.Uses = append(e.Uses, &UsesStmt{a, grouping.shallowDup()})
   883  				}
   884  			}
   885  		case "type":
   886  			// The type keyword is specific to deviate to change a type. Other type handling
   887  			// (e.g., leaf type resolution) is done outside of this case.
   888  			n, ok := n.(*Deviate)
   889  			if !ok {
   890  				e.addError(fmt.Errorf("unexpected type found, only valid under Deviate, is %T", n))
   891  				continue
   892  			}
   893  
   894  			if n.Type != nil {
   895  				if errs := n.Type.resolve(ms.typeDict); errs != nil {
   896  					e.addError(fmt.Errorf("deviation has unresolvable type, %v", errs))
   897  					continue
   898  				}
   899  				e.Type = n.Type.YangType
   900  			}
   901  			continue
   902  		// Keywords that do not need to be handled as an Entry as they are added
   903  		// to other dictionaries.
   904  		case "default":
   905  			switch e.Kind {
   906  			case LeafEntry, ChoiceEntry:
   907  				// default is handled separately for leaf, leaf-list and choice
   908  			case DeviateEntry:
   909  				// handle deviate statements.
   910  				// TODO(wenovus): support refine statement's default substatement.
   911  				d, ok := fv.Interface().(*Value)
   912  				if !ok {
   913  					e.addError(fmt.Errorf("%s: unexpected default type in %s:%s", Source(n), n.Kind(), n.NName()))
   914  				}
   915  				// TODO(wenovus): deviate statement and refine statement should
   916  				// allow multiple default substatements for leaf-list types (YANG1.1).
   917  				if d != nil {
   918  					e.Default = []string{d.asString()}
   919  				}
   920  			}
   921  		case "typedef":
   922  			continue
   923  		case "deviation":
   924  			if a := fv.Interface().([]*Deviation); a != nil {
   925  				for _, d := range a {
   926  					deviatedEntry := ToEntry(d)
   927  					e.importErrors(deviatedEntry)
   928  					e.Deviations = append(e.Deviations, &DeviatedEntry{
   929  						Entry:        deviatedEntry,
   930  						DeviatedPath: d.Statement().Argument,
   931  					})
   932  
   933  					for _, sd := range d.Deviate {
   934  						if sd.Type != nil {
   935  							sd.Type.resolve(ms.typeDict)
   936  						}
   937  					}
   938  				}
   939  			}
   940  		case "deviate":
   941  			if a := fv.Interface().([]*Deviate); a != nil {
   942  				for _, d := range a {
   943  					de := ToEntry(d)
   944  
   945  					dt, ok := toDeviation[d.Statement().Argument]
   946  					if !ok {
   947  						e.addError(fmt.Errorf("%s: unknown deviation type in %s:%s", Source(n), n.Kind(), n.NName()))
   948  						continue
   949  					}
   950  
   951  					if e.Deviate == nil {
   952  						e.Deviate = map[deviationType][]*Entry{}
   953  					}
   954  
   955  					e.Deviate[dt] = append(e.Deviate[dt], de)
   956  				}
   957  			}
   958  		case "mandatory":
   959  			v, ok := fv.Interface().(*Value)
   960  			if !ok {
   961  				e.addError(fmt.Errorf("%s: did not get expected value type", Source(n)))
   962  			}
   963  			e.Mandatory, err = tristateValue(v)
   964  			e.addError(err)
   965  		case "max-elements", "min-elements":
   966  			if e.Kind != DeviateEntry {
   967  				continue
   968  			}
   969  			// we can get max-elements or min-elements in a deviate statement, so create the
   970  			// corresponding logic.
   971  			v, ok := fv.Interface().(*Value)
   972  			if !ok {
   973  				e.addError(fmt.Errorf("%s: max or min elements had wrong type, %s:%s", Source(n), n.Kind(), n.NName()))
   974  				continue
   975  			}
   976  
   977  			if e.ListAttr == nil {
   978  				e.ListAttr = NewDefaultListAttr()
   979  			}
   980  
   981  			// Only record the deviation if the statement exists.
   982  			if v != nil {
   983  				var err error
   984  				if name == "max-elements" {
   985  					e.deviatePresence.hasMaxElements = true
   986  					if e.ListAttr.MaxElements, err = semCheckMaxElements(v); err != nil {
   987  						e.addError(err)
   988  					}
   989  				} else {
   990  					e.deviatePresence.hasMinElements = true
   991  					if e.ListAttr.MinElements, err = semCheckMinElements(v); err != nil {
   992  						e.addError(err)
   993  					}
   994  				}
   995  			}
   996  		case "units":
   997  			v, ok := fv.Interface().(*Value)
   998  			if !ok {
   999  				e.addError(fmt.Errorf("%s: units had wrong type, %s:%s", Source(n), n.Kind(), n.NName()))
  1000  			}
  1001  			if v != nil {
  1002  				e.Units = v.asString()
  1003  			}
  1004  		// TODO(borman): unimplemented keywords
  1005  		case "belongs-to",
  1006  			"contact",
  1007  			"extension",
  1008  			"feature",
  1009  			"if-feature",
  1010  			"must",
  1011  			"namespace",
  1012  			"ordered-by",
  1013  			"organization",
  1014  			"presence",
  1015  			"reference",
  1016  			"revision",
  1017  			"status",
  1018  			"unique",
  1019  			"when",
  1020  			"yang-version":
  1021  			if !fv.IsNil() {
  1022  				addToExtrasSlice(fv, name, e)
  1023  			}
  1024  			continue
  1025  
  1026  		case "Ext", "Name", "Parent", "Statement":
  1027  			// These are meta-keywords used internally
  1028  			continue
  1029  		default:
  1030  			e.addError(fmt.Errorf("%s: unexpected statement: %s", Source(n), name))
  1031  			continue
  1032  
  1033  		}
  1034  		// We found at least one field.
  1035  		found = true
  1036  	}
  1037  	if !found {
  1038  		return newError(n, "%T: cannot be converted to a *Entry", n)
  1039  	}
  1040  	// If prefix isn't set, provide it based on our root node (module)
  1041  	if e.Prefix == nil {
  1042  		e.Prefix = getRootPrefix(e)
  1043  	}
  1044  
  1045  	return e
  1046  }
  1047  
  1048  // addExtraKeywordsToLeafEntry stores the values for unimplemented keywords in leaf entries.
  1049  func addExtraKeywordsToLeafEntry(n Node, e *Entry) {
  1050  	v := reflect.ValueOf(n).Elem()
  1051  	t := v.Type()
  1052  
  1053  	for i := t.NumField() - 1; i > 0; i-- {
  1054  		f := t.Field(i)
  1055  		yang := f.Tag.Get("yang")
  1056  		if yang == "" {
  1057  			continue
  1058  		}
  1059  		fv := v.Field(i)
  1060  		name := strings.Split(yang, ",")[0]
  1061  		switch name {
  1062  		case "if-feature",
  1063  			"must",
  1064  			"reference",
  1065  			"status",
  1066  			"when":
  1067  			if !fv.IsNil() {
  1068  				addToExtrasSlice(fv, name, e)
  1069  			}
  1070  		}
  1071  	}
  1072  }
  1073  
  1074  func addToExtrasSlice(fv reflect.Value, name string, e *Entry) {
  1075  	if fv.Kind() == reflect.Slice {
  1076  		for j := 0; j < fv.Len(); j++ {
  1077  			e.Extra[name] = append(e.Extra[name], fv.Index(j).Interface())
  1078  		}
  1079  	} else {
  1080  		e.Extra[name] = append(e.Extra[name], fv.Interface())
  1081  	}
  1082  }
  1083  
  1084  // getRootPrefix returns the prefix of e's root node (module)
  1085  func getRootPrefix(e *Entry) *Value {
  1086  	if m := RootNode(e.Node); m != nil {
  1087  		return m.getPrefix()
  1088  	}
  1089  	return nil
  1090  }
  1091  
  1092  // Augment processes augments in e, return the number of augments processed
  1093  // and the augments skipped.  If addErrors is true then missing augments will
  1094  // generate errors.
  1095  func (e *Entry) Augment(addErrors bool) (processed, skipped int) {
  1096  	// Now process the augments we found
  1097  	// NOTE(borman): is it possible this will fail if the augment refers
  1098  	// to some removed sibling that has not been processed?  Perhaps this
  1099  	// should be done after the entire tree is built.  Is it correct to
  1100  	// assume augment paths are data tree paths and not schema tree paths?
  1101  	// Augments can depend upon augments.  We need to figure out how to
  1102  	// order the augments (or just keep trying until we can make no further
  1103  	// progress)
  1104  	var unapplied []*Entry
  1105  	for _, a := range e.Augments {
  1106  		target := a.Find(a.Name)
  1107  		if target == nil {
  1108  			if addErrors {
  1109  				e.errorf("%s: augment %s not found", Source(a.Node), a.Name)
  1110  			}
  1111  			skipped++
  1112  			unapplied = append(unapplied, a)
  1113  			continue
  1114  		}
  1115  		// Augments do not have a prefix we merge in, just a node.
  1116  		// We retain the namespace from the original context of the
  1117  		// augment since the nodes have this namespace even though they
  1118  		// are merged into another entry.
  1119  		processed++
  1120  		target.merge(nil, a.Namespace(), a)
  1121  		target.Augmented = append(target.Augmented, a.shallowDup())
  1122  	}
  1123  	e.Augments = unapplied
  1124  	return processed, skipped
  1125  }
  1126  
  1127  // ApplyDeviate walks the deviations within the supplied entry, and applies them to the
  1128  // schema.
  1129  func (e *Entry) ApplyDeviate(deviateOpts ...DeviateOpt) []error {
  1130  	var errs []error
  1131  	appendErr := func(err error) { errs = append(errs, err) }
  1132  	for _, d := range e.Deviations {
  1133  		deviatedNode := e.Find(d.DeviatedPath)
  1134  		if deviatedNode == nil {
  1135  			appendErr(fmt.Errorf("cannot find target node to deviate, %s", d.DeviatedPath))
  1136  			continue
  1137  		}
  1138  
  1139  		for dt, dv := range d.Deviate {
  1140  			for _, devSpec := range dv {
  1141  				switch dt {
  1142  				case DeviationAdd, DeviationReplace:
  1143  					if devSpec.Config != TSUnset {
  1144  						deviatedNode.Config = devSpec.Config
  1145  					}
  1146  
  1147  					if len(devSpec.Default) > 0 {
  1148  						switch dt {
  1149  						case DeviationAdd:
  1150  							switch {
  1151  							case deviatedNode.IsLeafList():
  1152  								deviatedNode.Default = append(deviatedNode.Default, devSpec.Default...)
  1153  							case len(devSpec.Default) > 1:
  1154  								appendErr(fmt.Errorf("%s: tried to add more than one default to a non-leaflist entry at deviation", Source(e.Node)))
  1155  							case len(deviatedNode.Default) != 0:
  1156  								appendErr(fmt.Errorf("%s: tried to add a default value to an entry that already has a default value", Source(e.Node)))
  1157  							case len(devSpec.Default) == 1 && len(deviatedNode.Default) == 0:
  1158  								deviatedNode.Default = append([]string{}, devSpec.Default[0])
  1159  							}
  1160  						case DeviationReplace:
  1161  							deviatedNode.Default = append([]string{}, devSpec.Default...)
  1162  						}
  1163  					}
  1164  
  1165  					if devSpec.Mandatory != TSUnset {
  1166  						deviatedNode.Mandatory = devSpec.Mandatory
  1167  					}
  1168  
  1169  					if devSpec.deviatePresence.hasMinElements {
  1170  						if !deviatedNode.IsList() && !deviatedNode.IsLeafList() {
  1171  							appendErr(fmt.Errorf("tried to deviate min-elements on a non-list type %s", deviatedNode.Kind))
  1172  							continue
  1173  						}
  1174  						deviatedNode.ListAttr.MinElements = devSpec.ListAttr.MinElements
  1175  					}
  1176  
  1177  					if devSpec.deviatePresence.hasMaxElements {
  1178  						if !deviatedNode.IsList() && !deviatedNode.IsLeafList() {
  1179  							appendErr(fmt.Errorf("tried to deviate max-elements on a non-list type %s", deviatedNode.Kind))
  1180  							continue
  1181  						}
  1182  						deviatedNode.ListAttr.MaxElements = devSpec.ListAttr.MaxElements
  1183  					}
  1184  
  1185  					if devSpec.Units != "" {
  1186  						deviatedNode.Units = devSpec.Units
  1187  					}
  1188  
  1189  					if devSpec.Type != nil {
  1190  						deviatedNode.Type = devSpec.Type
  1191  					}
  1192  
  1193  				case DeviationNotSupported:
  1194  					dp := deviatedNode.Parent
  1195  					if dp == nil {
  1196  						appendErr(fmt.Errorf("%s: node %s does not have a valid parent, but deviate not-supported references one", Source(e.Node), e.Name))
  1197  						continue
  1198  					}
  1199  					if !hasIgnoreDeviateNotSupported(deviateOpts) {
  1200  						dp.delete(deviatedNode.Name)
  1201  					}
  1202  				case DeviationDelete:
  1203  					if devSpec.Config != TSUnset {
  1204  						deviatedNode.Config = TSUnset
  1205  					}
  1206  
  1207  					if len(devSpec.Default) > 0 {
  1208  						switch {
  1209  						case deviatedNode.IsLeafList():
  1210  							// It is unclear from RFC7950 on how deviate delete works
  1211  							// when there are duplicate leaf-list values in config-false leafs.
  1212  							// TODO(wenbli): Add support for deleting default values when the leaf-list is a config leaf (duplicates are not allowed).
  1213  							appendErr(fmt.Errorf("%s: deviate delete on default statements unsupported for leaf-lists, please use replace instead", Source(e.Node)))
  1214  						case len(deviatedNode.Default) == 0:
  1215  							appendErr(fmt.Errorf("%s: tried to deviate delete a default statement that doesn't exist", Source(e.Node)))
  1216  						case devSpec.Default[0] != deviatedNode.Default[0]:
  1217  							appendErr(fmt.Errorf("%s: tried to deviate delete a default statement with a non-matching keyword", Source(e.Node)))
  1218  						default:
  1219  							deviatedNode.Default = nil
  1220  						}
  1221  					}
  1222  
  1223  					if devSpec.Mandatory != TSUnset {
  1224  						deviatedNode.Mandatory = TSUnset
  1225  					}
  1226  
  1227  					if devSpec.deviatePresence.hasMinElements {
  1228  						if !deviatedNode.IsList() && !deviatedNode.IsLeafList() {
  1229  							appendErr(fmt.Errorf("tried to deviate min-elements on a non-list type %s", deviatedNode.Kind))
  1230  							continue
  1231  						}
  1232  						if deviatedNode.ListAttr.MinElements != devSpec.ListAttr.MinElements {
  1233  							// Argument value must match:
  1234  							// https://tools.ietf.org/html/rfc7950#section-7.20.3.2
  1235  							appendErr(fmt.Errorf("min-element value %d differs from deviation's min-element value %d for entry %v", devSpec.ListAttr.MinElements, deviatedNode.ListAttr.MinElements, d.DeviatedPath))
  1236  						}
  1237  						deviatedNode.ListAttr.MinElements = 0
  1238  					}
  1239  
  1240  					if devSpec.deviatePresence.hasMaxElements {
  1241  						if !deviatedNode.IsList() && !deviatedNode.IsLeafList() {
  1242  							appendErr(fmt.Errorf("tried to deviate max-elements on a non-list type %s", deviatedNode.Kind))
  1243  							continue
  1244  						}
  1245  						if deviatedNode.ListAttr.MaxElements != devSpec.ListAttr.MaxElements {
  1246  							appendErr(fmt.Errorf("max-element value %d differs from deviation's max-element value %d for entry %v", devSpec.ListAttr.MaxElements, deviatedNode.ListAttr.MaxElements, d.DeviatedPath))
  1247  						}
  1248  						deviatedNode.ListAttr.MaxElements = math.MaxUint64
  1249  					}
  1250  
  1251  				default:
  1252  					appendErr(fmt.Errorf("invalid deviation type %s", dt))
  1253  				}
  1254  			}
  1255  		}
  1256  	}
  1257  
  1258  	return errs
  1259  }
  1260  
  1261  // FixChoice inserts missing Case entries for non-case entries within a choice
  1262  // entry.
  1263  func (e *Entry) FixChoice() {
  1264  	if e.Kind == ChoiceEntry && len(e.Errors) == 0 {
  1265  		for k, ce := range e.Dir {
  1266  			if ce.Kind != CaseEntry {
  1267  				ne := &Entry{
  1268  					Parent: e,
  1269  					Node: &Case{
  1270  						Parent:     ce.Node.ParentNode(),
  1271  						Name:       ce.Node.NName(),
  1272  						Source:     ce.Node.Statement(),
  1273  						Extensions: ce.Node.Exts(),
  1274  					},
  1275  					Name:   ce.Name,
  1276  					Kind:   CaseEntry,
  1277  					Config: ce.Config,
  1278  					Prefix: ce.Prefix,
  1279  					Dir:    map[string]*Entry{ce.Name: ce},
  1280  					Extra:  map[string][]interface{}{},
  1281  				}
  1282  				ce.Parent = ne
  1283  				e.Dir[k] = ne
  1284  			}
  1285  		}
  1286  	}
  1287  	for _, ce := range e.Dir {
  1288  		ce.FixChoice()
  1289  	}
  1290  }
  1291  
  1292  // ReadOnly returns true if e is a read-only variable (config == false).
  1293  // If Config is unset in e, then false is returned if e has no parent,
  1294  // otherwise the value parent's ReadOnly is returned.
  1295  func (e *Entry) ReadOnly() bool {
  1296  	switch {
  1297  	case e == nil:
  1298  		// We made it all the way to the root of the tree
  1299  		return false
  1300  	case e.Kind == OutputEntry:
  1301  		return true
  1302  	case e.Config == TSUnset:
  1303  		return e.Parent.ReadOnly()
  1304  	default:
  1305  		return !e.Config.Value()
  1306  	}
  1307  }
  1308  
  1309  // Find finds the Entry named by name relative to e.
  1310  func (e *Entry) Find(name string) *Entry {
  1311  	if e == nil || name == "" {
  1312  		return nil
  1313  	}
  1314  	parts := strings.Split(name, "/")
  1315  
  1316  	// If parts[0] is "" then this path started with a /
  1317  	// and we need to find our parent.
  1318  	if parts[0] == "" {
  1319  		parts = parts[1:]
  1320  		contextNode := e.Node
  1321  		for e.Parent != nil {
  1322  			e = e.Parent
  1323  		}
  1324  		if prefix, _ := getPrefix(parts[0]); prefix != "" {
  1325  			mod := FindModuleByPrefix(contextNode, prefix)
  1326  			if mod == nil {
  1327  				e.addError(fmt.Errorf("cannot find module giving prefix %q within context entry %q", prefix, e.Path()))
  1328  				return nil
  1329  			}
  1330  			m := module(mod)
  1331  			if m == nil {
  1332  				e.addError(fmt.Errorf("cannot find which module %q belongs to within context entry %q",
  1333  					mod.NName(), e.Path()))
  1334  				return nil
  1335  			}
  1336  			if m != e.Node.(*Module) {
  1337  				e = ToEntry(m)
  1338  			}
  1339  		}
  1340  	}
  1341  
  1342  	for _, part := range parts {
  1343  		switch {
  1344  		case e == nil:
  1345  			return nil
  1346  		case part == ".":
  1347  		case part == "..":
  1348  			e = e.Parent
  1349  		case e.RPC != nil:
  1350  			_, part = getPrefix(part)
  1351  			switch part {
  1352  			case "input":
  1353  				if e.RPC.Input == nil {
  1354  					e.RPC.Input = &Entry{
  1355  						Name: "input",
  1356  						Kind: InputEntry,
  1357  						Dir:  make(map[string]*Entry),
  1358  					}
  1359  				}
  1360  				e = e.RPC.Input
  1361  			case "output":
  1362  				if e.RPC.Output == nil {
  1363  					e.RPC.Output = &Entry{
  1364  						Name: "output",
  1365  						Kind: OutputEntry,
  1366  						Dir:  make(map[string]*Entry),
  1367  					}
  1368  				}
  1369  				e = e.RPC.Output
  1370  			}
  1371  		default:
  1372  			_, part = getPrefix(part)
  1373  			switch part {
  1374  			case ".":
  1375  			case "", "..":
  1376  				return nil
  1377  			default:
  1378  				e = e.Dir[part]
  1379  			}
  1380  		}
  1381  	}
  1382  	return e
  1383  }
  1384  
  1385  // Path returns the path to e. A nil Entry returns "".
  1386  func (e *Entry) Path() string {
  1387  	if e == nil {
  1388  		return ""
  1389  	}
  1390  	return e.Parent.Path() + "/" + e.Name
  1391  }
  1392  
  1393  // Namespace returns the YANG/XML namespace Value for e as mounted in the Entry
  1394  // tree (e.g., as placed by grouping statements).
  1395  //
  1396  // Per RFC6020 section 7.12, the namespace on elements in the tree due to a
  1397  // "uses" statement is that of the where the uses statement occurs, i.e., the
  1398  // user, rather than creator (grouping) of those elements, so we follow the
  1399  // usage (Entry) tree up to the parent before obtaining the (then adjacent) root
  1400  // node for its namespace Value.
  1401  func (e *Entry) Namespace() *Value {
  1402  	// Make e the root parent entry
  1403  	for ; e.Parent != nil; e = e.Parent {
  1404  		if e.namespace != nil {
  1405  			return e.namespace
  1406  		}
  1407  	}
  1408  
  1409  	// Return the namespace of a valid root parent entry
  1410  	if e != nil && e.Node != nil {
  1411  		if root := RootNode(e.Node); root != nil {
  1412  			if root.Kind() == "submodule" {
  1413  				root = root.Modules.Modules[root.BelongsTo.Name]
  1414  				if root == nil {
  1415  					return new(Value)
  1416  				}
  1417  			}
  1418  			return root.Namespace
  1419  		}
  1420  	}
  1421  
  1422  	// Otherwise return an empty namespace Value (rather than nil)
  1423  	return new(Value)
  1424  }
  1425  
  1426  // InstantiatingModule returns the YANG module which instantiated the Entry
  1427  // within the schema tree - using the same rules described in the documentation
  1428  // of the Namespace function. The namespace is resolved in the module name. This
  1429  // approach to namespacing is used when serialising YANG-modelled data to JSON as
  1430  // per RFC7951.
  1431  func (e *Entry) InstantiatingModule() (string, error) {
  1432  	n := e.Namespace()
  1433  	if n == nil {
  1434  		return "", fmt.Errorf("entry %s had nil namespace", e.Name)
  1435  	}
  1436  
  1437  	module, err := e.Modules().FindModuleByNamespace(n.Name)
  1438  	if err != nil {
  1439  		return "", fmt.Errorf("could not find module %q when retrieving namespace for %s: %v", n.Name, e.Name, err)
  1440  	}
  1441  	return module.Name, nil
  1442  }
  1443  
  1444  // shallowDup makes a shallow duplicate of e (only direct children are
  1445  // duplicated; grandchildren and deeper descendants are deleted).
  1446  func (e *Entry) shallowDup() *Entry {
  1447  	// Warning: if we add any elements to Entry that should not be
  1448  	// copied we will have to explicitly uncopy them.
  1449  	ne := *e
  1450  
  1451  	// Now only copy direct children, clear their Dir, and fix up
  1452  	// Parent pointers.
  1453  	if e.Dir != nil {
  1454  		ne.Dir = make(map[string]*Entry, len(e.Dir))
  1455  		for k, v := range e.Dir {
  1456  			de := *v
  1457  			de.Dir = nil
  1458  			de.Parent = &ne
  1459  			ne.Dir[k] = &de
  1460  		}
  1461  	}
  1462  	return &ne
  1463  }
  1464  
  1465  // dup makes a deep duplicate of e.
  1466  func (e *Entry) dup() *Entry {
  1467  	// Warning: if we add any elements to Entry that should not be
  1468  	// copied we will have to explicitly uncopy them.
  1469  	// It is possible we may want to do a deep copy on some other fields,
  1470  	// such as Exts, Choice and Case, but it is not clear that we need
  1471  	// to do that.
  1472  	ne := *e
  1473  
  1474  	// Now recurse down to all of our children, fixing up Parent
  1475  	// pointers as we go.
  1476  	if e.Dir != nil {
  1477  		ne.Dir = make(map[string]*Entry, len(e.Dir))
  1478  		for k, v := range e.Dir {
  1479  			de := v.dup()
  1480  			de.Parent = &ne
  1481  			ne.Dir[k] = de
  1482  		}
  1483  	}
  1484  
  1485  	ne.Extra = make(map[string][]interface{})
  1486  	for k, v := range e.Extra {
  1487  		ne.Extra[k] = v
  1488  	}
  1489  
  1490  	return &ne
  1491  }
  1492  
  1493  // merge merges a duplicate of oe.Dir into e.Dir, setting the prefix of each
  1494  // element to prefix, if not nil.  It is an error if e and oe contain common
  1495  // elements.
  1496  func (e *Entry) merge(prefix *Value, namespace *Value, oe *Entry) {
  1497  	e.importErrors(oe)
  1498  	for k, v := range oe.Dir {
  1499  		v := v.dup()
  1500  		if prefix != nil {
  1501  			v.Prefix = prefix
  1502  		}
  1503  		if namespace != nil {
  1504  			v.namespace = namespace
  1505  		}
  1506  		if se := e.Dir[k]; se != nil {
  1507  			er := newError(oe.Node, `Duplicate node %q in %q from:
  1508     %s: %s
  1509     %s: %s`, k, e.Name, Source(v.Node), v.Name, Source(se.Node), se.Name)
  1510  			e.addError(er.Errors[0])
  1511  		} else {
  1512  			v.Parent = e
  1513  			v.Exts = append(v.Exts, oe.Exts...)
  1514  			for lk := range oe.Extra {
  1515  				v.Extra[lk] = append(v.Extra[lk], oe.Extra[lk]...)
  1516  			}
  1517  			e.Dir[k] = v
  1518  		}
  1519  	}
  1520  }
  1521  
  1522  // nless returns -1 if a is less than b, 0 if a == b, and 1 if a > b.
  1523  // If a and b are both numeric, then nless compares them as numbers,
  1524  // otherwise they are compared lexicographically.
  1525  func nless(a, b string) int {
  1526  	an, ae := strconv.Atoi(a)
  1527  	bn, be := strconv.Atoi(b)
  1528  	switch {
  1529  	case ae == nil && be == nil:
  1530  		switch {
  1531  		case an < bn:
  1532  			return -1
  1533  		case an > bn:
  1534  			return 1
  1535  		default:
  1536  			return 0
  1537  		}
  1538  	case a < b:
  1539  		return -1
  1540  	case a > b:
  1541  		return 1
  1542  	default:
  1543  		return 0
  1544  	}
  1545  }
  1546  
  1547  type sError struct {
  1548  	s   string
  1549  	err error
  1550  }
  1551  
  1552  type sortedErrors []sError
  1553  
  1554  func (s sortedErrors) Len() int      { return len(s) }
  1555  func (s sortedErrors) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  1556  func (s sortedErrors) Less(i, j int) bool {
  1557  	// We expect the error strings to be composed of error messages,
  1558  	// line numbers, etc. delimited by ":".
  1559  	const errorSplitCount = 4
  1560  	fi := strings.SplitN(s[i].s, ":", errorSplitCount)
  1561  	fj := strings.SplitN(s[j].s, ":", errorSplitCount)
  1562  	// First, order the errors by the file name.
  1563  	if fi[0] < fj[0] {
  1564  		return true
  1565  	}
  1566  	if fi[0] > fj[0] {
  1567  		return false
  1568  	}
  1569  
  1570  	// compare remaining indices of the error string slices
  1571  	// in order to create a total ordering.
  1572  	for i := 1; i < errorSplitCount; i++ {
  1573  		switch {
  1574  		// Handle when an expected index doesn't exist.
  1575  		case len(fj) == i:
  1576  			return false
  1577  		case len(fi) == i:
  1578  			return true
  1579  		}
  1580  
  1581  		switch nless(fi[i], fj[i]) {
  1582  		case -1:
  1583  			return true
  1584  		case 1:
  1585  			return false
  1586  		}
  1587  	}
  1588  	return false
  1589  }
  1590  
  1591  // errorSort sorts the strings in the errors slice assuming each line starts
  1592  // with file:line:col.  Line and column number are sorted numerically.
  1593  // Duplicate errors are stripped.
  1594  func errorSort(errors []error) []error {
  1595  	switch len(errors) {
  1596  	case 0:
  1597  		return nil
  1598  	case 1:
  1599  		return errors
  1600  	}
  1601  	elist := make(sortedErrors, len(errors))
  1602  	for x, err := range errors {
  1603  		elist[x] = sError{err.Error(), err}
  1604  	}
  1605  	sort.Sort(elist)
  1606  	errors = make([]error, len(errors))
  1607  	i := 0
  1608  	for _, err := range elist {
  1609  		if i > 0 && reflect.DeepEqual(err.err, errors[i-1]) {
  1610  			continue
  1611  		}
  1612  		errors[i] = err.err
  1613  		i++
  1614  	}
  1615  	return errors[:i]
  1616  }
  1617  
  1618  // SingleDefaultValue returns the single schema default value for e and a bool
  1619  // indicating whether the entry contains one and only one default value. The
  1620  // empty string is returned when the entry has zero or multiple default values.
  1621  // This function is useful for determining the default values of a
  1622  // non-leaf-list leaf entry.  If the leaf has no explicit default, its type
  1623  // default (if any) will be used.
  1624  //
  1625  // For a leaf-list entry, use DefaultValues() instead.
  1626  func (e *Entry) SingleDefaultValue() (string, bool) {
  1627  	if dvals := e.DefaultValues(); len(dvals) == 1 {
  1628  		return dvals[0], true
  1629  	}
  1630  	return "", false
  1631  }
  1632  
  1633  // DefaultValues returns all default values for the leaf entry. This is useful
  1634  // for determining the default values for a leaf-list, which may have more than
  1635  // one default value. If the entry has no explicit default, its type default
  1636  // (if any) will be used. nil is returned when no default value exists.
  1637  //
  1638  // For a leaf entry, use SingleDefaultValue() instead.
  1639  func (e *Entry) DefaultValues() []string {
  1640  	if len(e.Default) > 0 {
  1641  		return append([]string{}, e.Default...)
  1642  	}
  1643  
  1644  	if typ := e.Type; typ != nil && typ.HasDefault {
  1645  		switch leaf := e.Node.(type) {
  1646  		case *Leaf:
  1647  			switch {
  1648  			case e.IsLeaf() && (leaf.Mandatory == nil || leaf.Mandatory.Name == "false"), e.IsLeafList() && e.ListAttr.MinElements == 0:
  1649  				return []string{typ.Default}
  1650  			}
  1651  		}
  1652  	}
  1653  	return nil
  1654  }