github.com/openconfig/goyang@v1.4.5/pkg/yang/types.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  // This file implements the functions relating to types and typedefs.
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"regexp/syntax"
    23  	"sync"
    24  )
    25  
    26  // A typeDictionary is a dictionary of all Typedefs defined in all Typedefers.
    27  // A map of Nodes is used rather than a map of Typedefers to simplify usage
    28  // when traversing up a Node tree.
    29  type typeDictionary struct {
    30  	mu   sync.Mutex
    31  	dict map[Node]map[string]*Typedef
    32  	// identities contains a dictionary of resolved identities.
    33  	identities identityDictionary
    34  }
    35  
    36  func newTypeDictionary() *typeDictionary {
    37  	return &typeDictionary{
    38  		dict:       map[Node]map[string]*Typedef{},
    39  		identities: identityDictionary{dict: map[string]resolvedIdentity{}},
    40  	}
    41  }
    42  
    43  // add adds an entry to the typeDictionary d.
    44  func (d *typeDictionary) add(n Node, name string, td *Typedef) {
    45  	defer d.mu.Unlock()
    46  	d.mu.Lock()
    47  	if d.dict[n] == nil {
    48  		d.dict[n] = map[string]*Typedef{}
    49  	}
    50  	d.dict[n][name] = td
    51  }
    52  
    53  // find returns the Typedef name define in node n, or nil.
    54  func (d *typeDictionary) find(n Node, name string) *Typedef {
    55  	defer d.mu.Unlock()
    56  	d.mu.Lock()
    57  	if d.dict[n] == nil {
    58  		return nil
    59  	}
    60  	return d.dict[n][name]
    61  }
    62  
    63  // findExternal finds the externally-defined typedef name in a module imported
    64  // by n's root with the specified prefix.
    65  func (d *typeDictionary) findExternal(n Node, prefix, name string) (*Typedef, error) {
    66  	root := FindModuleByPrefix(n, prefix)
    67  	if root == nil {
    68  		return nil, fmt.Errorf("%s: unknown prefix: %s for type %s", Source(n), prefix, name)
    69  	}
    70  	if td := d.find(root, name); td != nil {
    71  		return td, nil
    72  	}
    73  	if prefix != "" {
    74  		name = prefix + ":" + name
    75  	}
    76  	return nil, fmt.Errorf("%s: unknown type %s", Source(n), name)
    77  }
    78  
    79  // typedefs returns a slice of all typedefs in d.
    80  func (d *typeDictionary) typedefs() []*Typedef {
    81  	var tds []*Typedef
    82  	defer d.mu.Unlock()
    83  	d.mu.Lock()
    84  	for _, dict := range d.dict {
    85  		for _, td := range dict {
    86  			tds = append(tds, td)
    87  		}
    88  	}
    89  	return tds
    90  }
    91  
    92  // addTypedefs is called from BuildAST after each Typedefer is defined.  There
    93  // are no error conditions in this process as it is simply used to build up the
    94  // typedef dictionary.
    95  func (d *typeDictionary) addTypedefs(t Typedefer) {
    96  	for _, td := range t.Typedefs() {
    97  		d.add(t, td.Name, td)
    98  	}
    99  }
   100  
   101  // resolveTypedefs is called after all of modules and submodules have been read,
   102  // as well as their imports and includes.  It resolves all typedefs found in all
   103  // modules and submodules read in.
   104  func (d *typeDictionary) resolveTypedefs() []error {
   105  	var errs []error
   106  
   107  	// When resolve typedefs, we may need to look up other typedefs.
   108  	// We gather all typedefs into a slice so we don't deadlock on
   109  	// typeDict.
   110  	for _, td := range d.typedefs() {
   111  		errs = append(errs, td.resolve(d)...)
   112  	}
   113  	return errs
   114  }
   115  
   116  // resolve creates a YangType for t, if not already done.  Resolving t
   117  // requires resolving the Type that t is based on.
   118  func (t *Typedef) resolve(d *typeDictionary) []error {
   119  	// If we have no parent we are a base type and
   120  	// are already resolved.
   121  	if t.Parent == nil || t.YangType != nil {
   122  		return nil
   123  	}
   124  
   125  	if errs := t.Type.resolve(d); len(errs) != 0 {
   126  		return errs
   127  	}
   128  
   129  	// Make a copy of the YangType we are based on and then
   130  	// update it with local information.
   131  	y := *t.Type.YangType
   132  	y.Name = t.Name
   133  	y.Base = t.Type
   134  
   135  	if t.Units != nil {
   136  		y.Units = t.Units.Name
   137  	}
   138  	if t.Default != nil {
   139  		y.HasDefault = true
   140  		y.Default = t.Default.Name
   141  	}
   142  
   143  	if t.Type.IdentityBase != nil {
   144  		// We need to copy over the IdentityBase statement if the type has one
   145  		if idBase, err := RootNode(t).findIdentityBase(t.Type.IdentityBase.Name); err == nil {
   146  			y.IdentityBase = idBase.Identity
   147  		} else {
   148  			return []error{fmt.Errorf("could not resolve identity base for typedef: %s", t.Type.IdentityBase.Name)}
   149  		}
   150  	}
   151  
   152  	// If we changed something, we are the new root.
   153  	if y.Root == t.Type.YangType || !y.Equal(y.Root) {
   154  		y.Root = &y
   155  	}
   156  	t.YangType = &y
   157  	return nil
   158  }
   159  
   160  // resolve resolves Type t, as well as the underlying typedef for t.  If t
   161  // cannot be resolved then one or more errors are returned.
   162  func (t *Type) resolve(d *typeDictionary) (errs []error) {
   163  	if t.YangType != nil {
   164  		return nil
   165  	}
   166  
   167  	// If t.Name is a base type then td will not be nil, otherwise
   168  	// td will be nil and of type *Typedef.
   169  	td := BaseTypedefs[t.Name]
   170  
   171  	prefix, name := getPrefix(t.Name)
   172  	root := RootNode(t)
   173  	rootPrefix := root.GetPrefix()
   174  
   175  	source := "unknown"
   176  check:
   177  	switch {
   178  	case td != nil:
   179  		source = "builtin"
   180  		// This was a base type
   181  	case prefix == "" || rootPrefix == prefix:
   182  		source = "local"
   183  		// If we have no prefix, or the prefix is what we call our own
   184  		// root, then we look in our ancestors for a typedef of name.
   185  		for n := Node(t); n != nil; n = n.ParentNode() {
   186  			if td = d.find(n, name); td != nil {
   187  				break check
   188  			}
   189  		}
   190  		// We need to check our sub-modules as well
   191  		for _, in := range root.Include {
   192  			if td = d.find(in.Module, name); td != nil {
   193  				break check
   194  			}
   195  		}
   196  		var pname string
   197  		switch {
   198  		case prefix == "", prefix == root.Prefix.Name:
   199  			pname = root.Prefix.Name + ":" + t.Name
   200  		default:
   201  			pname = fmt.Sprintf("%s[%s]:%s", prefix, root.Prefix.Name, t.Name)
   202  		}
   203  
   204  		return []error{fmt.Errorf("%s: unknown type: %s", Source(t), pname)}
   205  
   206  	default:
   207  		source = "imported"
   208  		// prefix is not local to our module, so we have to go find
   209  		// what module it is part of and if it is defined at the top
   210  		// level of that module.
   211  		var err error
   212  		td, err = d.findExternal(t, prefix, name)
   213  		if err != nil {
   214  			return []error{err}
   215  		}
   216  	}
   217  	if errs := td.resolve(d); len(errs) > 0 {
   218  		return errs
   219  	}
   220  
   221  	// Make a copy of the typedef we are based on so we can
   222  	// augment it.
   223  	if td.YangType == nil {
   224  		return []error{fmt.Errorf("%s: no YangType defined for %s %s", Source(td), source, td.Name)}
   225  	}
   226  	y := *td.YangType
   227  
   228  	y.Base = td.Type
   229  	t.YangType = &y
   230  
   231  	if v := t.RequireInstance; v != nil {
   232  		b, err := v.asBool()
   233  		if err != nil {
   234  			errs = append(errs, err)
   235  		}
   236  		y.OptionalInstance = !b
   237  	}
   238  	if v := t.Path; v != nil {
   239  		y.Path = v.asString()
   240  	}
   241  	isDecimal64 := y.Kind == Ydecimal64 && (t.Name == "decimal64" || y.FractionDigits != 0)
   242  	switch {
   243  	case isDecimal64 && y.FractionDigits != 0:
   244  		if t.FractionDigits != nil {
   245  			return append(errs, fmt.Errorf("%s: overriding of fraction-digits not allowed", Source(t)))
   246  		}
   247  		// FractionDigits already set via type inheritance.
   248  	case isDecimal64:
   249  		// If we are directly of type decimal64 then we must specify
   250  		// fraction-digits in the range from 1-18.
   251  		i, err := t.FractionDigits.asRangeInt(1, 18)
   252  		if err != nil {
   253  			errs = append(errs, fmt.Errorf("%s: %v", Source(t), err))
   254  		}
   255  		y.FractionDigits = int(i)
   256  		// We only know to how to populate Range after knowing the
   257  		// fractional digit value.
   258  		y.Range = YangRange{{
   259  			Number{Value: AbsMinInt64, Negative: true, FractionDigits: uint8(i)},
   260  			Number{Value: MaxInt64, FractionDigits: uint8(i)},
   261  		}}
   262  	case t.FractionDigits != nil:
   263  		errs = append(errs, fmt.Errorf("%s: fraction-digits only allowed for decimal64 values", Source(t)))
   264  	case y.Kind == Yidentityref:
   265  		if source != "builtin" {
   266  			// This is a typedef that refers to an identityref, so we want to simply
   267  			// maintain the base that the typedef resolution provided
   268  			break
   269  		}
   270  
   271  		if t.IdentityBase == nil {
   272  			errs = append(errs, fmt.Errorf("%s: an identityref must specify a base", Source(t)))
   273  			break
   274  		}
   275  
   276  		root := RootNode(t.Parent)
   277  		resolvedBase, baseErr := root.findIdentityBase(t.IdentityBase.Name)
   278  		if baseErr != nil {
   279  			errs = append(errs, baseErr...)
   280  			break
   281  		}
   282  
   283  		if resolvedBase.Identity == nil {
   284  			errs = append(errs, fmt.Errorf("%s: identity has a null base", t.IdentityBase.Name))
   285  			break
   286  		}
   287  		y.IdentityBase = resolvedBase.Identity
   288  	}
   289  
   290  	if t.Range != nil {
   291  		yr, err := y.Range.parseChildRanges(t.Range.Name, isDecimal64, uint8(y.FractionDigits))
   292  		switch {
   293  		case err != nil:
   294  			errs = append(errs, fmt.Errorf("%s: bad range: %v", Source(t.Range), err))
   295  		case yr.Equal(y.Range):
   296  		default:
   297  			y.Range = yr
   298  		}
   299  	}
   300  
   301  	if t.Length != nil {
   302  		parentRange := Uint64Range
   303  		if y.Length != nil {
   304  			parentRange = y.Length
   305  		}
   306  		yr, err := parentRange.parseChildRanges(t.Length.Name, false, 0)
   307  		switch {
   308  		case err != nil:
   309  			errs = append(errs, fmt.Errorf("%s: bad length: %v", Source(t.Length), err))
   310  		case yr.Equal(y.Length):
   311  		default:
   312  			for _, r := range yr {
   313  				if r.Min.Negative {
   314  					errs = append(errs, fmt.Errorf("%s: negative length: %v", Source(t.Length), yr))
   315  					break
   316  				}
   317  			}
   318  			y.Length = yr
   319  		}
   320  	}
   321  
   322  	set := func(e *EnumType, name string, value *Value) error {
   323  		if value == nil {
   324  			return e.SetNext(name)
   325  		}
   326  		n, err := ParseInt(value.Name)
   327  		if err != nil {
   328  			return err
   329  		}
   330  		i, err := n.Int()
   331  		if err != nil {
   332  			return err
   333  		}
   334  		return e.Set(name, i)
   335  	}
   336  
   337  	if len(t.Enum) > 0 {
   338  		enum := NewEnumType()
   339  		for _, e := range t.Enum {
   340  			if err := set(enum, e.Name, e.Value); err != nil {
   341  				errs = append(errs, fmt.Errorf("%s: %v", Source(e), err))
   342  			}
   343  		}
   344  		y.Enum = enum
   345  	}
   346  
   347  	if len(t.Bit) > 0 {
   348  		bit := NewBitfield()
   349  		for _, e := range t.Bit {
   350  			if err := set(bit, e.Name, e.Position); err != nil {
   351  				errs = append(errs, fmt.Errorf("%s: %v", Source(e), err))
   352  			}
   353  		}
   354  		y.Bit = bit
   355  	}
   356  
   357  	// Append any newly found patterns to the end of the list of patterns.
   358  	// Patterns are ANDed according to section 9.4.6.  If all the patterns
   359  	// declared by t were also declared by the type t is based on, then
   360  	// no patterns are added.
   361  	seenPatterns := map[string]bool{}
   362  	for _, p := range y.Pattern {
   363  		seenPatterns[p] = true
   364  	}
   365  	seenPOSIXPatterns := map[string]bool{}
   366  	for _, p := range y.POSIXPattern {
   367  		seenPOSIXPatterns[p] = true
   368  	}
   369  
   370  	// First parse out the pattern statements.
   371  	// These patterns are not checked because there is no support for W3C regexes by Go.
   372  	for _, pv := range t.Pattern {
   373  		if !seenPatterns[pv.Name] {
   374  			seenPatterns[pv.Name] = true
   375  			y.Pattern = append(y.Pattern, pv.Name)
   376  		}
   377  	}
   378  
   379  	// Then, parse out the posix-pattern statements, if they exist.
   380  	// A YANG module could make use of either or both, so we deal with each separately.
   381  	posixPatterns, err := MatchingExtensions(t, "openconfig-extensions", "posix-pattern")
   382  	if err != nil {
   383  		return []error{err}
   384  	}
   385  
   386  	checkPattern := func(n Node, p string, flags syntax.Flags) {
   387  		if _, err := syntax.Parse(p, flags); err != nil {
   388  			if re, ok := err.(*syntax.Error); ok {
   389  				// Error adds "error parsing regexp" to
   390  				// the error, re.Code is the real error.
   391  				err = errors.New(re.Code.String())
   392  			}
   393  			errs = append(errs, fmt.Errorf("%s: bad pattern: %v: %s", Source(n), err, p))
   394  		}
   395  	}
   396  	for _, ext := range posixPatterns {
   397  		checkPattern(ext, ext.Argument, syntax.POSIX)
   398  		if !seenPOSIXPatterns[ext.Argument] {
   399  			seenPOSIXPatterns[ext.Argument] = true
   400  			y.POSIXPattern = append(y.POSIXPattern, ext.Argument)
   401  		}
   402  	}
   403  
   404  	// I don't know of an easy way to use a type as a key to a map,
   405  	// so we have to check equality the hard way.
   406  looking:
   407  	for _, ut := range t.Type {
   408  		errs = append(errs, ut.resolve(d)...)
   409  		if ut.YangType != nil {
   410  			for _, yt := range y.Type {
   411  				if ut.YangType.Equal(yt) {
   412  					continue looking
   413  				}
   414  			}
   415  			y.Type = append(y.Type, ut.YangType)
   416  		}
   417  	}
   418  
   419  	// If we changed something, we are the new root.
   420  	if !y.Equal(y.Root) {
   421  		y.Root = &y
   422  	}
   423  
   424  	return errs
   425  }