github.com/phpstudyer/protoreflect@v1.7.2/desc/protoparse/ast/walk.go (about) 1 package ast 2 3 // VisitFunc is used to examine a node in the AST when walking the tree. 4 // It returns true or false as to whether or not the descendants of the 5 // given node should be visited. If it returns true, the node's children 6 // will be visisted; if false, they will not. When returning true, it 7 // can also return a new VisitFunc to use for the children. If it returns 8 // (true, nil), then the current function will be re-used when visiting 9 // the children. 10 // 11 // See also the Visitor type. 12 type VisitFunc func(Node) (bool, VisitFunc) 13 14 // Walk conducts a walk of the AST rooted at the given root using the 15 // given function. It performs a "pre-order traversal", visiting a 16 // given AST node before it visits that node's descendants. 17 func Walk(root Node, v VisitFunc) { 18 ok, next := v(root) 19 if !ok { 20 return 21 } 22 if next != nil { 23 v = next 24 } 25 if comp, ok := root.(CompositeNode); ok { 26 for _, child := range comp.Children() { 27 Walk(child, v) 28 } 29 } 30 } 31 32 // Visitor provides a technique for walking the AST that allows for 33 // dynamic dispatch, where a particular function is invoked based on 34 // the runtime type of the argument. 35 // 36 // It consists of a number of functions, each of which matches a 37 // concrete Node type. It also includes functions for sub-interfaces 38 // of Node and the Node interface itself, to be used as broader 39 // "catch all" functions. 40 // 41 // To use a visitor, provide a function for the node types of 42 // interest and pass visitor.Visit as the function to a Walk operation. 43 // When a node is traversed, the corresponding function field of 44 // the visitor is invoked, if not nil. If the function for a node's 45 // concrete type is nil/absent but the function for an interface it 46 // implements is present, that interface visit function will be used 47 // instead. If no matching function is present, the traversal will 48 // continue. If a matching function is present, it will be invoked 49 // and its response determines how the traversal proceeds. 50 // 51 // Every visit function returns (bool, *Visitor). If the bool returned 52 // is false, the visited node's descendants are skipped. Otherwise, 53 // traversal will continue into the node's children. If the returned 54 // visitor is nil, the current visitor will continue to be used. But 55 // if a non-nil visitor is returned, it will be used to visit the 56 // node's children. 57 type Visitor struct { 58 // VisitFileNode is invoked when visiting a *FileNode in the AST. 59 VisitFileNode func(*FileNode) (bool, *Visitor) 60 // VisitSyntaxNode is invoked when visiting a *SyntaxNode in the AST. 61 VisitSyntaxNode func(*SyntaxNode) (bool, *Visitor) 62 // VisitPackageNode is invoked when visiting a *PackageNode in the AST. 63 VisitPackageNode func(*PackageNode) (bool, *Visitor) 64 // VisitImportNode is invoked when visiting an *ImportNode in the AST. 65 VisitImportNode func(*ImportNode) (bool, *Visitor) 66 // VisitOptionNode is invoked when visiting an *OptionNode in the AST. 67 VisitOptionNode func(*OptionNode) (bool, *Visitor) 68 // VisitOptionNameNode is invoked when visiting an *OptionNameNode in the AST. 69 VisitOptionNameNode func(*OptionNameNode) (bool, *Visitor) 70 // VisitFieldReferenceNode is invoked when visiting a *FieldReferenceNode in the AST. 71 VisitFieldReferenceNode func(*FieldReferenceNode) (bool, *Visitor) 72 // VisitCompactOptionsNode is invoked when visiting a *CompactOptionsNode in the AST. 73 VisitCompactOptionsNode func(*CompactOptionsNode) (bool, *Visitor) 74 // VisitMessageNode is invoked when visiting a *MessageNode in the AST. 75 VisitMessageNode func(*MessageNode) (bool, *Visitor) 76 // VisitExtendNode is invoked when visiting an *ExtendNode in the AST. 77 VisitExtendNode func(*ExtendNode) (bool, *Visitor) 78 // VisitExtensionRangeNode is invoked when visiting an *ExtensionRangeNode in the AST. 79 VisitExtensionRangeNode func(*ExtensionRangeNode) (bool, *Visitor) 80 // VisitReservedNode is invoked when visiting a *ReservedNode in the AST. 81 VisitReservedNode func(*ReservedNode) (bool, *Visitor) 82 // VisitRangeNode is invoked when visiting a *RangeNode in the AST. 83 VisitRangeNode func(*RangeNode) (bool, *Visitor) 84 // VisitFieldNode is invoked when visiting a *FieldNode in the AST. 85 VisitFieldNode func(*FieldNode) (bool, *Visitor) 86 // VisitGroupNode is invoked when visiting a *GroupNode in the AST. 87 VisitGroupNode func(*GroupNode) (bool, *Visitor) 88 // VisitMapFieldNode is invoked when visiting a *MapFieldNode in the AST. 89 VisitMapFieldNode func(*MapFieldNode) (bool, *Visitor) 90 // VisitMapTypeNode is invoked when visiting a *MapTypeNode in the AST. 91 VisitMapTypeNode func(*MapTypeNode) (bool, *Visitor) 92 // VisitOneOfNode is invoked when visiting a *OneOfNode in the AST. 93 VisitOneOfNode func(*OneOfNode) (bool, *Visitor) 94 // VisitEnumNode is invoked when visiting an *EnumNode in the AST. 95 VisitEnumNode func(*EnumNode) (bool, *Visitor) 96 // VisitEnumValueNode is invoked when visiting an *EnumValueNode in the AST. 97 VisitEnumValueNode func(*EnumValueNode) (bool, *Visitor) 98 // VisitServiceNode is invoked when visiting a *ServiceNode in the AST. 99 VisitServiceNode func(*ServiceNode) (bool, *Visitor) 100 // VisitRPCNode is invoked when visiting an *RPCNode in the AST. 101 VisitRPCNode func(*RPCNode) (bool, *Visitor) 102 // VisitRPCTypeNode is invoked when visiting an *RPCTypeNode in the AST. 103 VisitRPCTypeNode func(*RPCTypeNode) (bool, *Visitor) 104 // VisitIdentNode is invoked when visiting an *IdentNode in the AST. 105 VisitIdentNode func(*IdentNode) (bool, *Visitor) 106 // VisitCompoundIdentNode is invoked when visiting a *CompoundIdentNode in the AST. 107 VisitCompoundIdentNode func(*CompoundIdentNode) (bool, *Visitor) 108 // VisitStringLiteralNode is invoked when visiting a *StringLiteralNode in the AST. 109 VisitStringLiteralNode func(*StringLiteralNode) (bool, *Visitor) 110 // VisitCompoundStringLiteralNode is invoked when visiting a *CompoundStringLiteralNode in the AST. 111 VisitCompoundStringLiteralNode func(*CompoundStringLiteralNode) (bool, *Visitor) 112 // VisitUintLiteralNode is invoked when visiting a *UintLiteralNode in the AST. 113 VisitUintLiteralNode func(*UintLiteralNode) (bool, *Visitor) 114 // VisitPositiveUintLiteralNode is invoked when visiting a *PositiveUintLiteralNode in the AST. 115 VisitPositiveUintLiteralNode func(*PositiveUintLiteralNode) (bool, *Visitor) 116 // VisitNegativeIntLiteralNode is invoked when visiting a *NegativeIntLiteralNode in the AST. 117 VisitNegativeIntLiteralNode func(*NegativeIntLiteralNode) (bool, *Visitor) 118 // VisitFloatLiteralNode is invoked when visiting a *FloatLiteralNode in the AST. 119 VisitFloatLiteralNode func(*FloatLiteralNode) (bool, *Visitor) 120 // VisitSpecialFloatLiteralNode is invoked when visiting a *SpecialFloatLiteralNode in the AST. 121 VisitSpecialFloatLiteralNode func(*SpecialFloatLiteralNode) (bool, *Visitor) 122 // VisitSignedFloatLiteralNode is invoked when visiting a *SignedFloatLiteralNode in the AST. 123 VisitSignedFloatLiteralNode func(*SignedFloatLiteralNode) (bool, *Visitor) 124 // VisitBoolLiteralNode is invoked when visiting a *BoolLiteralNode in the AST. 125 VisitBoolLiteralNode func(*BoolLiteralNode) (bool, *Visitor) 126 // VisitArrayLiteralNode is invoked when visiting an *ArrayLiteralNode in the AST. 127 VisitArrayLiteralNode func(*ArrayLiteralNode) (bool, *Visitor) 128 // VisitMessageLiteralNode is invoked when visiting a *MessageLiteralNode in the AST. 129 VisitMessageLiteralNode func(*MessageLiteralNode) (bool, *Visitor) 130 // VisitMessageFieldNode is invoked when visiting a *MessageFieldNode in the AST. 131 VisitMessageFieldNode func(*MessageFieldNode) (bool, *Visitor) 132 // VisitKeywordNode is invoked when visiting a *KeywordNode in the AST. 133 VisitKeywordNode func(*KeywordNode) (bool, *Visitor) 134 // VisitRuneNode is invoked when visiting a *RuneNode in the AST. 135 VisitRuneNode func(*RuneNode) (bool, *Visitor) 136 // VisitEmptyDeclNode is invoked when visiting a *EmptyDeclNode in the AST. 137 VisitEmptyDeclNode func(*EmptyDeclNode) (bool, *Visitor) 138 139 // VisitFieldDeclNode is invoked when visiting a FieldDeclNode in the AST. 140 // This function is used when no concrete type function is provided. If 141 // both this and VisitMessageDeclNode are provided, and a node implements 142 // both (such as *GroupNode and *MapFieldNode), this function will be 143 // invoked and not the other. 144 VisitFieldDeclNode func(FieldDeclNode) (bool, *Visitor) 145 // VisitMessageDeclNode is invoked when visiting a MessageDeclNode in the AST. 146 // This function is used when no concrete type function is provided. 147 VisitMessageDeclNode func(MessageDeclNode) (bool, *Visitor) 148 149 // VisitIdentValueNode is invoked when visiting an IdentValueNode in the AST. 150 // This function is used when no concrete type function is provided. 151 VisitIdentValueNode func(IdentValueNode) (bool, *Visitor) 152 // VisitStringValueNode is invoked when visiting a StringValueNode in the AST. 153 // This function is used when no concrete type function is provided. 154 VisitStringValueNode func(StringValueNode) (bool, *Visitor) 155 // VisitIntValueNode is invoked when visiting an IntValueNode in the AST. 156 // This function is used when no concrete type function is provided. If 157 // both this and VisitFloatValueNode are provided, and a node implements 158 // both (such as *UintLiteralNode), this function will be invoked and 159 // not the other. 160 VisitIntValueNode func(IntValueNode) (bool, *Visitor) 161 // VisitFloatValueNode is invoked when visiting a FloatValueNode in the AST. 162 // This function is used when no concrete type function is provided. 163 VisitFloatValueNode func(FloatValueNode) (bool, *Visitor) 164 // VisitValueNode is invoked when visiting a ValueNode in the AST. This 165 // function is used when no concrete type function is provided and no 166 // more specific ValueNode function is provided that matches the node. 167 VisitValueNode func(ValueNode) (bool, *Visitor) 168 169 // VisitTerminalNode is invoked when visiting a TerminalNode in the AST. 170 // This function is used when no concrete type function is provided 171 // no more specific interface type function is provided. 172 VisitTerminalNode func(TerminalNode) (bool, *Visitor) 173 // VisitCompositeNode is invoked when visiting a CompositeNode in the AST. 174 // This function is used when no concrete type function is provided 175 // no more specific interface type function is provided. 176 VisitCompositeNode func(CompositeNode) (bool, *Visitor) 177 // VisitNode is invoked when visiting a Node in the AST. This 178 // function is only used when no other more specific function is 179 // provided. 180 VisitNode func(Node) (bool, *Visitor) 181 } 182 183 // Visit provides the Visitor's implementation of VisitFunc, to be 184 // used with Walk operations. 185 func (v *Visitor) Visit(n Node) (bool, VisitFunc) { 186 var ok, matched bool 187 var next *Visitor 188 switch n := n.(type) { 189 case *FileNode: 190 if v.VisitFileNode != nil { 191 matched = true 192 ok, next = v.VisitFileNode(n) 193 } 194 case *SyntaxNode: 195 if v.VisitSyntaxNode != nil { 196 matched = true 197 ok, next = v.VisitSyntaxNode(n) 198 } 199 case *PackageNode: 200 if v.VisitPackageNode != nil { 201 matched = true 202 ok, next = v.VisitPackageNode(n) 203 } 204 case *ImportNode: 205 if v.VisitImportNode != nil { 206 matched = true 207 ok, next = v.VisitImportNode(n) 208 } 209 case *OptionNode: 210 if v.VisitOptionNode != nil { 211 matched = true 212 ok, next = v.VisitOptionNode(n) 213 } 214 case *OptionNameNode: 215 if v.VisitOptionNameNode != nil { 216 matched = true 217 ok, next = v.VisitOptionNameNode(n) 218 } 219 case *FieldReferenceNode: 220 if v.VisitFieldReferenceNode != nil { 221 matched = true 222 ok, next = v.VisitFieldReferenceNode(n) 223 } 224 case *CompactOptionsNode: 225 if v.VisitCompactOptionsNode != nil { 226 matched = true 227 ok, next = v.VisitCompactOptionsNode(n) 228 } 229 case *MessageNode: 230 if v.VisitMessageNode != nil { 231 matched = true 232 ok, next = v.VisitMessageNode(n) 233 } 234 case *ExtendNode: 235 if v.VisitExtendNode != nil { 236 matched = true 237 ok, next = v.VisitExtendNode(n) 238 } 239 case *ExtensionRangeNode: 240 if v.VisitExtensionRangeNode != nil { 241 matched = true 242 ok, next = v.VisitExtensionRangeNode(n) 243 } 244 case *ReservedNode: 245 if v.VisitReservedNode != nil { 246 matched = true 247 ok, next = v.VisitReservedNode(n) 248 } 249 case *RangeNode: 250 if v.VisitRangeNode != nil { 251 matched = true 252 ok, next = v.VisitRangeNode(n) 253 } 254 case *FieldNode: 255 if v.VisitFieldNode != nil { 256 matched = true 257 ok, next = v.VisitFieldNode(n) 258 } 259 case *GroupNode: 260 if v.VisitGroupNode != nil { 261 matched = true 262 ok, next = v.VisitGroupNode(n) 263 } 264 case *MapFieldNode: 265 if v.VisitMapFieldNode != nil { 266 matched = true 267 ok, next = v.VisitMapFieldNode(n) 268 } 269 case *MapTypeNode: 270 if v.VisitMapTypeNode != nil { 271 matched = true 272 ok, next = v.VisitMapTypeNode(n) 273 } 274 case *OneOfNode: 275 if v.VisitOneOfNode != nil { 276 matched = true 277 ok, next = v.VisitOneOfNode(n) 278 } 279 case *EnumNode: 280 if v.VisitEnumNode != nil { 281 matched = true 282 ok, next = v.VisitEnumNode(n) 283 } 284 case *EnumValueNode: 285 if v.VisitEnumValueNode != nil { 286 matched = true 287 ok, next = v.VisitEnumValueNode(n) 288 } 289 case *ServiceNode: 290 if v.VisitServiceNode != nil { 291 matched = true 292 ok, next = v.VisitServiceNode(n) 293 } 294 case *RPCNode: 295 if v.VisitRPCNode != nil { 296 matched = true 297 ok, next = v.VisitRPCNode(n) 298 } 299 case *RPCTypeNode: 300 if v.VisitRPCTypeNode != nil { 301 matched = true 302 ok, next = v.VisitRPCTypeNode(n) 303 } 304 case *IdentNode: 305 if v.VisitIdentNode != nil { 306 matched = true 307 ok, next = v.VisitIdentNode(n) 308 } 309 case *CompoundIdentNode: 310 if v.VisitCompoundIdentNode != nil { 311 matched = true 312 ok, next = v.VisitCompoundIdentNode(n) 313 } 314 case *StringLiteralNode: 315 if v.VisitStringLiteralNode != nil { 316 matched = true 317 ok, next = v.VisitStringLiteralNode(n) 318 } 319 case *CompoundStringLiteralNode: 320 if v.VisitCompoundStringLiteralNode != nil { 321 matched = true 322 ok, next = v.VisitCompoundStringLiteralNode(n) 323 } 324 case *UintLiteralNode: 325 if v.VisitUintLiteralNode != nil { 326 matched = true 327 ok, next = v.VisitUintLiteralNode(n) 328 } 329 case *PositiveUintLiteralNode: 330 if v.VisitPositiveUintLiteralNode != nil { 331 matched = true 332 ok, next = v.VisitPositiveUintLiteralNode(n) 333 } 334 case *NegativeIntLiteralNode: 335 if v.VisitNegativeIntLiteralNode != nil { 336 matched = true 337 ok, next = v.VisitNegativeIntLiteralNode(n) 338 } 339 case *FloatLiteralNode: 340 if v.VisitFloatLiteralNode != nil { 341 matched = true 342 ok, next = v.VisitFloatLiteralNode(n) 343 } 344 case *SpecialFloatLiteralNode: 345 if v.VisitSpecialFloatLiteralNode != nil { 346 matched = true 347 ok, next = v.VisitSpecialFloatLiteralNode(n) 348 } 349 case *SignedFloatLiteralNode: 350 if v.VisitSignedFloatLiteralNode != nil { 351 matched = true 352 ok, next = v.VisitSignedFloatLiteralNode(n) 353 } 354 case *BoolLiteralNode: 355 if v.VisitBoolLiteralNode != nil { 356 matched = true 357 ok, next = v.VisitBoolLiteralNode(n) 358 } 359 case *ArrayLiteralNode: 360 if v.VisitArrayLiteralNode != nil { 361 matched = true 362 ok, next = v.VisitArrayLiteralNode(n) 363 } 364 case *MessageLiteralNode: 365 if v.VisitMessageLiteralNode != nil { 366 matched = true 367 ok, next = v.VisitMessageLiteralNode(n) 368 } 369 case *MessageFieldNode: 370 if v.VisitMessageFieldNode != nil { 371 matched = true 372 ok, next = v.VisitMessageFieldNode(n) 373 } 374 case *KeywordNode: 375 if v.VisitKeywordNode != nil { 376 matched = true 377 ok, next = v.VisitKeywordNode(n) 378 } 379 case *RuneNode: 380 if v.VisitRuneNode != nil { 381 matched = true 382 ok, next = v.VisitRuneNode(n) 383 } 384 case *EmptyDeclNode: 385 if v.VisitEmptyDeclNode != nil { 386 matched = true 387 ok, next = v.VisitEmptyDeclNode(n) 388 } 389 } 390 391 if !matched { 392 // Visitor provided no concrete type visit function, so 393 // check interface types. We do this in several passes 394 // to provide "priority" for matched interfaces for nodes 395 // that actually implement more than one interface. 396 // 397 // For example, StringLiteralNode implements both 398 // StringValueNode and ValueNode. Both cases could match 399 // so the first case is what would match. So if we want 400 // to test against either, they need to be in different 401 // switch statements. 402 switch n := n.(type) { 403 case FieldDeclNode: 404 if v.VisitFieldDeclNode != nil { 405 matched = true 406 ok, next = v.VisitFieldDeclNode(n) 407 } 408 case IdentValueNode: 409 if v.VisitIdentValueNode != nil { 410 matched = true 411 ok, next = v.VisitIdentValueNode(n) 412 } 413 case StringValueNode: 414 if v.VisitStringValueNode != nil { 415 matched = true 416 ok, next = v.VisitStringValueNode(n) 417 } 418 case IntValueNode: 419 if v.VisitIntValueNode != nil { 420 matched = true 421 ok, next = v.VisitIntValueNode(n) 422 } 423 } 424 } 425 426 if !matched { 427 // These two are excluded from the above switch so that 428 // if visitor provides both VisitIntValueNode and 429 // VisitFloatValueNode, we'll prefer VisitIntValueNode 430 // for *UintLiteralNode (which implements both). Similarly, 431 // that way we prefer VisitFieldDeclNode over 432 // VisitMessageDeclNode when visiting a *GroupNode. 433 switch n := n.(type) { 434 case FloatValueNode: 435 if v.VisitFloatValueNode != nil { 436 matched = true 437 ok, next = v.VisitFloatValueNode(n) 438 } 439 case MessageDeclNode: 440 if v.VisitMessageDeclNode != nil { 441 matched = true 442 ok, next = v.VisitMessageDeclNode(n) 443 } 444 } 445 } 446 447 if !matched { 448 switch n := n.(type) { 449 case ValueNode: 450 if v.VisitValueNode != nil { 451 matched = true 452 ok, next = v.VisitValueNode(n) 453 } 454 } 455 } 456 457 if !matched { 458 switch n := n.(type) { 459 case TerminalNode: 460 if v.VisitTerminalNode != nil { 461 matched = true 462 ok, next = v.VisitTerminalNode(n) 463 } 464 case CompositeNode: 465 if v.VisitCompositeNode != nil { 466 matched = true 467 ok, next = v.VisitCompositeNode(n) 468 } 469 } 470 } 471 472 if !matched { 473 // finally, fallback to most generic visit function 474 if v.VisitNode != nil { 475 matched = true 476 ok, next = v.VisitNode(n) 477 } 478 } 479 480 if !matched { 481 // keep descending with the current visitor 482 return true, nil 483 } 484 485 if !ok { 486 return false, nil 487 } 488 if next != nil { 489 return true, next.Visit 490 } 491 return true, v.Visit 492 }