github.com/openconfig/goyang@v1.4.5/pkg/yang/find.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 has functions that search the AST for specified nodes. 18 19 import ( 20 "reflect" 21 "strings" 22 ) 23 24 // localPrefix returns the local prefix used by the containing (sub)module to 25 // refer to its own module. 26 func localPrefix(n Node) string { 27 return RootNode(n).GetPrefix() 28 } 29 30 // trimLocalPrefix trims the current module's prefix from the given name. If the 31 // name is not prefixed with the local module's prefix or is unprefixed 32 // entirely, then the same string is returned unchanged. 33 func trimLocalPrefix(n Node, name string) string { 34 pfx := localPrefix(n) 35 if pfx != "" { 36 pfx += ":" 37 } 38 return strings.TrimPrefix(name, pfx) 39 } 40 41 // FindGrouping finds the grouping named name according to YANG namespace rules 42 // using the input node as the initial context node. The seen parameter 43 // provides a list of the modules previously seen by FindGrouping during 44 // traversal. If the named grouping cannot be found, nil is returned. 45 // 46 // FindGrouping works by recursively looking through the context node's parent 47 // nodes for grouping fields, or in included or imported submodules/modules for 48 // externally-defined groupings. Note that any prefix in the name must match 49 // the module prefix of its import statement in the context node's module. 50 func FindGrouping(n Node, name string, seen map[string]bool) *Grouping { 51 name = trimLocalPrefix(n, name) 52 for n != nil { 53 // Grab the Grouping field of the underlying structure. n is 54 // always a pointer to a structure, 55 e := reflect.ValueOf(n).Elem() 56 v := e.FieldByName("Grouping") 57 if v.IsValid() { 58 for _, g := range v.Interface().([]*Grouping) { 59 if g.Name == name { 60 return g 61 } 62 } 63 } 64 v = e.FieldByName("Import") 65 if v.IsValid() { 66 for _, i := range v.Interface().([]*Import) { 67 // If the prefix matches the import statement, 68 // then search for the trimmed name in that module. 69 pname := strings.TrimPrefix(name, i.Prefix.Name+":") 70 if pname == name { 71 continue 72 } 73 if g := FindGrouping(i.Module, pname, seen); g != nil { 74 return g 75 } 76 } 77 } 78 v = e.FieldByName("Include") 79 if v.IsValid() { 80 for _, i := range v.Interface().([]*Include) { 81 if seen[i.Module.Name] { 82 // Prevent infinite loops in the case that we have already looked at 83 // this submodule. This occurs where submodules have include statements 84 // in them, or there is a circular dependency. 85 continue 86 } 87 seen[i.Module.Name] = true 88 if g := FindGrouping(i.Module, name, seen); g != nil { 89 return g 90 } 91 } 92 } 93 n = n.ParentNode() 94 } 95 return nil 96 }