github.com/goplus/gop@v1.2.6/ast/walk.go (about) 1 /* 2 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ast 18 19 import ( 20 "fmt" 21 ) 22 23 // Visitor - A Visitor's Visit method is invoked for each node encountered by Walk. 24 // If the result visitor w is not nil, Walk visits each of the children 25 // of node with the visitor w, followed by a call of w.Visit(nil). 26 type Visitor interface { 27 Visit(node Node) (w Visitor) 28 } 29 30 // Helper functions for common node lists. They may be empty. 31 32 func walkIdentList(v Visitor, list []*Ident) { 33 for _, x := range list { 34 Walk(v, x) 35 } 36 } 37 38 func walkExprList(v Visitor, list []Expr) { 39 for _, x := range list { 40 Walk(v, x) 41 } 42 } 43 44 func walkStmtList(v Visitor, list []Stmt) { 45 for _, x := range list { 46 Walk(v, x) 47 } 48 } 49 50 func walkDeclList(v Visitor, list []Decl) { 51 for _, x := range list { 52 Walk(v, x) 53 } 54 } 55 56 // TODO(gri): Investigate if providing a closure to Walk leads to 57 // simpler use (and may help eliminate Inspect in turn). 58 59 // Walk traverses an AST in depth-first order: It starts by calling 60 // v.Visit(node); node must not be nil. If the visitor w returned by 61 // v.Visit(node) is not nil, Walk is invoked recursively with visitor 62 // w for each of the non-nil children of node, followed by a call of 63 // w.Visit(nil). 64 func Walk(v Visitor, node Node) { 65 if v = v.Visit(node); v == nil { 66 return 67 } 68 69 // walk children 70 // (the order of the cases matches the order 71 // of the corresponding node types in ast.go) 72 switch n := node.(type) { 73 // Comments and fields 74 case *Comment: 75 // nothing to do 76 77 case *CommentGroup: 78 for _, c := range n.List { 79 Walk(v, c) 80 } 81 82 case *Field: 83 if n.Doc != nil { 84 Walk(v, n.Doc) 85 } 86 walkIdentList(v, n.Names) 87 Walk(v, n.Type) 88 if n.Tag != nil { 89 Walk(v, n.Tag) 90 } 91 if n.Comment != nil { 92 Walk(v, n.Comment) 93 } 94 95 case *FieldList: 96 for _, f := range n.List { 97 Walk(v, f) 98 } 99 100 // Expressions 101 case *BadExpr, *Ident: 102 // nothing to do 103 104 case *BasicLit: 105 if n.Extra != nil { // Go+ extended 106 for _, part := range n.Extra.Parts { 107 if e, ok := part.(Expr); ok { 108 Walk(v, e) 109 } 110 } 111 } 112 113 case *Ellipsis: 114 if n.Elt != nil { 115 Walk(v, n.Elt) 116 } 117 118 case *FuncLit: 119 Walk(v, n.Type) 120 Walk(v, n.Body) 121 122 case *CompositeLit: 123 if n.Type != nil { 124 Walk(v, n.Type) 125 } 126 walkExprList(v, n.Elts) 127 128 case *ParenExpr: 129 Walk(v, n.X) 130 131 case *SelectorExpr: 132 Walk(v, n.X) 133 Walk(v, n.Sel) 134 135 case *IndexExpr: 136 Walk(v, n.X) 137 Walk(v, n.Index) 138 139 case *IndexListExpr: 140 Walk(v, n.X) 141 walkExprList(v, n.Indices) 142 143 case *SliceExpr: 144 Walk(v, n.X) 145 if n.Low != nil { 146 Walk(v, n.Low) 147 } 148 if n.High != nil { 149 Walk(v, n.High) 150 } 151 if n.Max != nil { 152 Walk(v, n.Max) 153 } 154 155 case *TypeAssertExpr: 156 Walk(v, n.X) 157 if n.Type != nil { 158 Walk(v, n.Type) 159 } 160 161 case *CallExpr: 162 Walk(v, n.Fun) 163 walkExprList(v, n.Args) 164 165 case *StarExpr: 166 Walk(v, n.X) 167 168 case *UnaryExpr: 169 Walk(v, n.X) 170 171 case *BinaryExpr: 172 Walk(v, n.X) 173 Walk(v, n.Y) 174 175 case *KeyValueExpr: 176 Walk(v, n.Key) 177 Walk(v, n.Value) 178 179 // Types 180 case *ArrayType: 181 if n.Len != nil { 182 Walk(v, n.Len) 183 } 184 Walk(v, n.Elt) 185 186 case *StructType: 187 Walk(v, n.Fields) 188 189 case *FuncType: 190 if n.Params != nil { 191 Walk(v, n.Params) 192 } 193 if n.Results != nil { 194 Walk(v, n.Results) 195 } 196 197 case *InterfaceType: 198 Walk(v, n.Methods) 199 200 case *MapType: 201 Walk(v, n.Key) 202 Walk(v, n.Value) 203 204 case *ChanType: 205 Walk(v, n.Value) 206 207 // Statements 208 case *BadStmt: 209 // nothing to do 210 211 case *DeclStmt: 212 Walk(v, n.Decl) 213 214 case *EmptyStmt: 215 // nothing to do 216 217 case *LabeledStmt: 218 Walk(v, n.Label) 219 Walk(v, n.Stmt) 220 221 case *ExprStmt: 222 Walk(v, n.X) 223 224 case *SendStmt: 225 Walk(v, n.Chan) 226 Walk(v, n.Value) 227 228 case *IncDecStmt: 229 Walk(v, n.X) 230 231 case *AssignStmt: 232 walkExprList(v, n.Lhs) 233 walkExprList(v, n.Rhs) 234 235 case *GoStmt: 236 Walk(v, n.Call) 237 238 case *DeferStmt: 239 Walk(v, n.Call) 240 241 case *ReturnStmt: 242 walkExprList(v, n.Results) 243 244 case *BranchStmt: 245 if n.Label != nil { 246 Walk(v, n.Label) 247 } 248 249 case *BlockStmt: 250 walkStmtList(v, n.List) 251 252 case *IfStmt: 253 if n.Init != nil { 254 Walk(v, n.Init) 255 } 256 Walk(v, n.Cond) 257 Walk(v, n.Body) 258 if n.Else != nil { 259 Walk(v, n.Else) 260 } 261 262 case *CaseClause: 263 walkExprList(v, n.List) 264 walkStmtList(v, n.Body) 265 266 case *SwitchStmt: 267 if n.Init != nil { 268 Walk(v, n.Init) 269 } 270 if n.Tag != nil { 271 Walk(v, n.Tag) 272 } 273 Walk(v, n.Body) 274 275 case *TypeSwitchStmt: 276 if n.Init != nil { 277 Walk(v, n.Init) 278 } 279 Walk(v, n.Assign) 280 Walk(v, n.Body) 281 282 case *CommClause: 283 if n.Comm != nil { 284 Walk(v, n.Comm) 285 } 286 walkStmtList(v, n.Body) 287 288 case *SelectStmt: 289 Walk(v, n.Body) 290 291 case *ForStmt: 292 if n.Init != nil { 293 Walk(v, n.Init) 294 } 295 if n.Cond != nil { 296 Walk(v, n.Cond) 297 } 298 if n.Post != nil { 299 Walk(v, n.Post) 300 } 301 Walk(v, n.Body) 302 303 case *RangeStmt: 304 if n.Key != nil { 305 Walk(v, n.Key) 306 } 307 if n.Value != nil { 308 Walk(v, n.Value) 309 } 310 Walk(v, n.X) 311 Walk(v, n.Body) 312 313 // Declarations 314 case *ImportSpec: 315 if n.Doc != nil { 316 Walk(v, n.Doc) 317 } 318 if n.Name != nil { 319 Walk(v, n.Name) 320 } 321 Walk(v, n.Path) 322 if n.Comment != nil { 323 Walk(v, n.Comment) 324 } 325 326 case *ValueSpec: 327 if n.Doc != nil { 328 Walk(v, n.Doc) 329 } 330 walkIdentList(v, n.Names) 331 if n.Type != nil { 332 Walk(v, n.Type) 333 } 334 walkExprList(v, n.Values) 335 if n.Comment != nil { 336 Walk(v, n.Comment) 337 } 338 339 case *TypeSpec: 340 if n.Doc != nil { 341 Walk(v, n.Doc) 342 } 343 Walk(v, n.Name) 344 Walk(v, n.Type) 345 if n.Comment != nil { 346 Walk(v, n.Comment) 347 } 348 349 case *BadDecl: 350 // nothing to do 351 352 case *GenDecl: 353 if n.Doc != nil { 354 Walk(v, n.Doc) 355 } 356 for _, s := range n.Specs { 357 Walk(v, s) 358 } 359 360 case *FuncDecl: 361 if !n.Shadow { // not a shadow entry 362 if n.Doc != nil { 363 Walk(v, n.Doc) 364 } 365 if n.Recv != nil { 366 Walk(v, n.Recv) 367 } 368 Walk(v, n.Name) 369 Walk(v, n.Type) 370 } 371 if n.Body != nil { 372 Walk(v, n.Body) 373 } 374 375 // Files and packages 376 case *File: 377 if n.Doc != nil { 378 Walk(v, n.Doc) 379 } 380 if !n.NoPkgDecl { 381 Walk(v, n.Name) 382 } 383 walkDeclList(v, n.Decls) 384 // don't walk n.Comments - they have been 385 // visited already through the individual 386 // nodes 387 388 case *Package: 389 for _, f := range n.Files { 390 Walk(v, f) 391 } 392 393 // Go+ extended expr and stmt 394 case *SliceLit: 395 walkExprList(v, n.Elts) 396 397 case *LambdaExpr: 398 walkIdentList(v, n.Lhs) 399 walkExprList(v, n.Rhs) 400 401 case *LambdaExpr2: 402 walkIdentList(v, n.Lhs) 403 Walk(v, n.Body) 404 405 case *ForPhrase: 406 if n.Key != nil { 407 Walk(v, n.Key) 408 } 409 if n.Value != nil { 410 Walk(v, n.Value) 411 } 412 if n.Init != nil { 413 Walk(v, n.Init) 414 } 415 if n.Cond != nil { 416 Walk(v, n.Cond) 417 } 418 Walk(v, n.X) 419 420 case *ComprehensionExpr: 421 if n.Elt != nil { 422 Walk(v, n.Elt) 423 } 424 for _, x := range n.Fors { 425 Walk(v, x) 426 } 427 428 case *ForPhraseStmt: 429 Walk(v, n.ForPhrase) 430 Walk(v, n.Body) 431 432 case *RangeExpr: 433 if n.First != nil { 434 Walk(v, n.First) 435 } 436 if n.Last != nil { 437 Walk(v, n.Last) 438 } 439 if n.Expr3 != nil { 440 Walk(v, n.Expr3) 441 } 442 443 case *ErrWrapExpr: 444 Walk(v, n.X) 445 if n.Default != nil { 446 Walk(v, n.Default) 447 } 448 449 case *OverloadFuncDecl: 450 if n.Doc != nil { 451 Walk(v, n.Doc) 452 } 453 if n.Recv != nil { 454 Walk(v, n.Recv) 455 } 456 Walk(v, n.Name) 457 walkExprList(v, n.Funcs) 458 459 case *EnvExpr: 460 Walk(v, n.Name) 461 462 default: 463 panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) 464 } 465 466 v.Visit(nil) 467 } 468 469 type inspector func(Node) bool 470 471 func (f inspector) Visit(node Node) Visitor { 472 if f(node) { 473 return f 474 } 475 return nil 476 } 477 478 // Inspect traverses an AST in depth-first order: It starts by calling 479 // f(node); node must not be nil. If f returns true, Inspect invokes f 480 // recursively for each of the non-nil children of node, followed by a 481 // call of f(nil). 482 func Inspect(node Node, f func(Node) bool) { 483 Walk(inspector(f), node) 484 }