github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/go/ast/walk.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ast 6 7 import "fmt" 8 9 // A Visitor's Visit method is invoked for each node encountered by Walk. 10 // If the result visitor w is not nil, Walk visits each of the children 11 // of node with the visitor w, followed by a call of w.Visit(nil). 12 type Visitor interface { 13 Visit(node Node) (w Visitor) 14 } 15 16 // Helper functions for common node lists. They may be empty. 17 18 func walkIdentList(v Visitor, list []*Ident) { 19 for _, x := range list { 20 Walk(v, x) 21 } 22 } 23 24 func walkExprList(v Visitor, list []Expr) { 25 for _, x := range list { 26 Walk(v, x) 27 } 28 } 29 30 func walkStmtList(v Visitor, list []Stmt) { 31 for _, x := range list { 32 Walk(v, x) 33 } 34 } 35 36 func walkDeclList(v Visitor, list []Decl) { 37 for _, x := range list { 38 Walk(v, x) 39 } 40 } 41 42 // TODO(gri): Investigate if providing a closure to Walk leads to 43 // simpler use (and may help eliminate Inspect in turn). 44 45 // Walk traverses an AST in depth-first order: It starts by calling 46 // v.Visit(node); node must not be nil. If the visitor w returned by 47 // v.Visit(node) is not nil, Walk is invoked recursively with visitor 48 // w for each of the non-nil children of node, followed by a call of 49 // w.Visit(nil). 50 // 51 func Walk(v Visitor, node Node) { 52 if v = v.Visit(node); v == nil { 53 return 54 } 55 56 // walk children 57 // (the order of the cases matches the order 58 // of the corresponding node types in ast.go) 59 switch n := node.(type) { 60 // Comments and fields 61 case *Comment: 62 // nothing to do 63 64 case *CommentGroup: 65 for _, c := range n.List { 66 Walk(v, c) 67 } 68 69 case *Field: 70 if n.Doc != nil { 71 Walk(v, n.Doc) 72 } 73 walkIdentList(v, n.Names) 74 Walk(v, n.Type) 75 if n.Tag != nil { 76 Walk(v, n.Tag) 77 } 78 if n.Comment != nil { 79 Walk(v, n.Comment) 80 } 81 82 case *FieldList: 83 for _, f := range n.List { 84 Walk(v, f) 85 } 86 87 // Expressions 88 case *BadExpr, *Ident, *BasicLit: 89 // nothing to do 90 91 case *Ellipsis: 92 if n.Elt != nil { 93 Walk(v, n.Elt) 94 } 95 96 case *FuncLit: 97 Walk(v, n.Type) 98 Walk(v, n.Body) 99 100 case *CompositeLit: 101 if n.Type != nil { 102 Walk(v, n.Type) 103 } 104 walkExprList(v, n.Elts) 105 106 case *ParenExpr: 107 Walk(v, n.X) 108 109 case *SelectorExpr: 110 Walk(v, n.X) 111 Walk(v, n.Sel) 112 113 case *IndexExpr: 114 Walk(v, n.X) 115 Walk(v, n.Index) 116 117 case *SliceExpr: 118 Walk(v, n.X) 119 if n.Low != nil { 120 Walk(v, n.Low) 121 } 122 if n.High != nil { 123 Walk(v, n.High) 124 } 125 if n.Max != nil { 126 Walk(v, n.Max) 127 } 128 129 case *TypeAssertExpr: 130 Walk(v, n.X) 131 if n.Type != nil { 132 Walk(v, n.Type) 133 } 134 135 case *CallExpr: 136 Walk(v, n.Fun) 137 walkExprList(v, n.Args) 138 139 case *StarExpr: 140 Walk(v, n.X) 141 142 case *UnaryExpr: 143 Walk(v, n.X) 144 145 case *BinaryExpr: 146 Walk(v, n.X) 147 Walk(v, n.Y) 148 149 case *KeyValueExpr: 150 Walk(v, n.Key) 151 Walk(v, n.Value) 152 153 // Types 154 case *ArrayType: 155 if n.Len != nil { 156 Walk(v, n.Len) 157 } 158 Walk(v, n.Elt) 159 160 case *StructType: 161 Walk(v, n.Fields) 162 163 case *FuncType: 164 if n.Params != nil { 165 Walk(v, n.Params) 166 } 167 if n.Results != nil { 168 Walk(v, n.Results) 169 } 170 171 case *InterfaceType: 172 Walk(v, n.Methods) 173 174 case *MapType: 175 Walk(v, n.Key) 176 Walk(v, n.Value) 177 178 case *ChanType: 179 Walk(v, n.Value) 180 181 // Statements 182 case *BadStmt: 183 // nothing to do 184 185 case *DeclStmt: 186 Walk(v, n.Decl) 187 188 case *EmptyStmt: 189 // nothing to do 190 191 case *LabeledStmt: 192 Walk(v, n.Label) 193 Walk(v, n.Stmt) 194 195 case *ExprStmt: 196 Walk(v, n.X) 197 198 case *SendStmt: 199 Walk(v, n.Chan) 200 Walk(v, n.Value) 201 202 case *IncDecStmt: 203 Walk(v, n.X) 204 205 case *AssignStmt: 206 walkExprList(v, n.Lhs) 207 walkExprList(v, n.Rhs) 208 209 case *GoStmt: 210 Walk(v, n.Call) 211 212 case *DeferStmt: 213 Walk(v, n.Call) 214 215 case *ReturnStmt: 216 walkExprList(v, n.Results) 217 218 case *BranchStmt: 219 if n.Label != nil { 220 Walk(v, n.Label) 221 } 222 223 case *BlockStmt: 224 walkStmtList(v, n.List) 225 226 case *IfStmt: 227 if n.Init != nil { 228 Walk(v, n.Init) 229 } 230 Walk(v, n.Cond) 231 Walk(v, n.Body) 232 if n.Else != nil { 233 Walk(v, n.Else) 234 } 235 236 case *CaseClause: 237 walkExprList(v, n.List) 238 walkStmtList(v, n.Body) 239 240 case *SwitchStmt: 241 if n.Init != nil { 242 Walk(v, n.Init) 243 } 244 if n.Tag != nil { 245 Walk(v, n.Tag) 246 } 247 Walk(v, n.Body) 248 249 case *TypeSwitchStmt: 250 if n.Init != nil { 251 Walk(v, n.Init) 252 } 253 Walk(v, n.Assign) 254 Walk(v, n.Body) 255 256 case *CommClause: 257 if n.Comm != nil { 258 Walk(v, n.Comm) 259 } 260 walkStmtList(v, n.Body) 261 262 case *SelectStmt: 263 Walk(v, n.Body) 264 265 case *ForStmt: 266 if n.Init != nil { 267 Walk(v, n.Init) 268 } 269 if n.Cond != nil { 270 Walk(v, n.Cond) 271 } 272 if n.Post != nil { 273 Walk(v, n.Post) 274 } 275 Walk(v, n.Body) 276 277 case *RangeStmt: 278 if n.Key != nil { 279 Walk(v, n.Key) 280 } 281 if n.Value != nil { 282 Walk(v, n.Value) 283 } 284 Walk(v, n.X) 285 Walk(v, n.Body) 286 287 // Declarations 288 case *ImportSpec: 289 if n.Doc != nil { 290 Walk(v, n.Doc) 291 } 292 if n.Name != nil { 293 Walk(v, n.Name) 294 } 295 Walk(v, n.Path) 296 if n.Comment != nil { 297 Walk(v, n.Comment) 298 } 299 300 case *ValueSpec: 301 if n.Doc != nil { 302 Walk(v, n.Doc) 303 } 304 walkIdentList(v, n.Names) 305 if n.Type != nil { 306 Walk(v, n.Type) 307 } 308 walkExprList(v, n.Values) 309 if n.Comment != nil { 310 Walk(v, n.Comment) 311 } 312 313 case *TypeSpec: 314 if n.Doc != nil { 315 Walk(v, n.Doc) 316 } 317 Walk(v, n.Name) 318 Walk(v, n.Type) 319 if n.Comment != nil { 320 Walk(v, n.Comment) 321 } 322 323 case *BadDecl: 324 // nothing to do 325 326 case *GenDecl: 327 if n.Doc != nil { 328 Walk(v, n.Doc) 329 } 330 for _, s := range n.Specs { 331 Walk(v, s) 332 } 333 334 case *FuncDecl: 335 if n.Doc != nil { 336 Walk(v, n.Doc) 337 } 338 if n.Recv != nil { 339 Walk(v, n.Recv) 340 } 341 Walk(v, n.Name) 342 Walk(v, n.Type) 343 if n.Body != nil { 344 Walk(v, n.Body) 345 } 346 347 // Files and packages 348 case *File: 349 if n.Doc != nil { 350 Walk(v, n.Doc) 351 } 352 Walk(v, n.Name) 353 walkDeclList(v, n.Decls) 354 // don't walk n.Comments - they have been 355 // visited already through the individual 356 // nodes 357 358 case *Package: 359 for _, f := range n.Files { 360 Walk(v, f) 361 } 362 363 default: 364 panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) 365 } 366 367 v.Visit(nil) 368 } 369 370 type inspector func(Node) bool 371 372 func (f inspector) Visit(node Node) Visitor { 373 if f(node) { 374 return f 375 } 376 return nil 377 } 378 379 // Inspect traverses an AST in depth-first order: It starts by calling 380 // f(node); node must not be nil. If f returns true, Inspect invokes f 381 // recursively for each of the non-nil children of node, followed by a 382 // call of f(nil). 383 // 384 func Inspect(node Node, f func(Node) bool) { 385 Walk(inspector(f), node) 386 }