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 }