Source file src/pkg/go/ast/walk.go
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 126 case *TypeAssertExpr: 127 Walk(v, n.X) 128 if n.Type != nil { 129 Walk(v, n.Type) 130 } 131 132 case *CallExpr: 133 Walk(v, n.Fun) 134 walkExprList(v, n.Args) 135 136 case *StarExpr: 137 Walk(v, n.X) 138 139 case *UnaryExpr: 140 Walk(v, n.X) 141 142 case *BinaryExpr: 143 Walk(v, n.X) 144 Walk(v, n.Y) 145 146 case *KeyValueExpr: 147 Walk(v, n.Key) 148 Walk(v, n.Value) 149 150 // Types 151 case *ArrayType: 152 if n.Len != nil { 153 Walk(v, n.Len) 154 } 155 Walk(v, n.Elt) 156 157 case *StructType: 158 Walk(v, n.Fields) 159 160 case *FuncType: 161 Walk(v, n.Params) 162 if n.Results != nil { 163 Walk(v, n.Results) 164 } 165 166 case *InterfaceType: 167 Walk(v, n.Methods) 168 169 case *MapType: 170 Walk(v, n.Key) 171 Walk(v, n.Value) 172 173 case *ChanType: 174 Walk(v, n.Value) 175 176 // Statements 177 case *BadStmt: 178 // nothing to do 179 180 case *DeclStmt: 181 Walk(v, n.Decl) 182 183 case *EmptyStmt: 184 // nothing to do 185 186 case *LabeledStmt: 187 Walk(v, n.Label) 188 Walk(v, n.Stmt) 189 190 case *ExprStmt: 191 Walk(v, n.X) 192 193 case *SendStmt: 194 Walk(v, n.Chan) 195 Walk(v, n.Value) 196 197 case *IncDecStmt: 198 Walk(v, n.X) 199 200 case *AssignStmt: 201 walkExprList(v, n.Lhs) 202 walkExprList(v, n.Rhs) 203 204 case *GoStmt: 205 Walk(v, n.Call) 206 207 case *DeferStmt: 208 Walk(v, n.Call) 209 210 case *ReturnStmt: 211 walkExprList(v, n.Results) 212 213 case *BranchStmt: 214 if n.Label != nil { 215 Walk(v, n.Label) 216 } 217 218 case *BlockStmt: 219 walkStmtList(v, n.List) 220 221 case *IfStmt: 222 if n.Init != nil { 223 Walk(v, n.Init) 224 } 225 Walk(v, n.Cond) 226 Walk(v, n.Body) 227 if n.Else != nil { 228 Walk(v, n.Else) 229 } 230 231 case *CaseClause: 232 walkExprList(v, n.List) 233 walkStmtList(v, n.Body) 234 235 case *SwitchStmt: 236 if n.Init != nil { 237 Walk(v, n.Init) 238 } 239 if n.Tag != nil { 240 Walk(v, n.Tag) 241 } 242 Walk(v, n.Body) 243 244 case *TypeSwitchStmt: 245 if n.Init != nil { 246 Walk(v, n.Init) 247 } 248 Walk(v, n.Assign) 249 Walk(v, n.Body) 250 251 case *CommClause: 252 if n.Comm != nil { 253 Walk(v, n.Comm) 254 } 255 walkStmtList(v, n.Body) 256 257 case *SelectStmt: 258 Walk(v, n.Body) 259 260 case *ForStmt: 261 if n.Init != nil { 262 Walk(v, n.Init) 263 } 264 if n.Cond != nil { 265 Walk(v, n.Cond) 266 } 267 if n.Post != nil { 268 Walk(v, n.Post) 269 } 270 Walk(v, n.Body) 271 272 case *RangeStmt: 273 Walk(v, n.Key) 274 if n.Value != nil { 275 Walk(v, n.Value) 276 } 277 Walk(v, n.X) 278 Walk(v, n.Body) 279 280 // Declarations 281 case *ImportSpec: 282 if n.Doc != nil { 283 Walk(v, n.Doc) 284 } 285 if n.Name != nil { 286 Walk(v, n.Name) 287 } 288 Walk(v, n.Path) 289 if n.Comment != nil { 290 Walk(v, n.Comment) 291 } 292 293 case *ValueSpec: 294 if n.Doc != nil { 295 Walk(v, n.Doc) 296 } 297 walkIdentList(v, n.Names) 298 if n.Type != nil { 299 Walk(v, n.Type) 300 } 301 walkExprList(v, n.Values) 302 if n.Comment != nil { 303 Walk(v, n.Comment) 304 } 305 306 case *TypeSpec: 307 if n.Doc != nil { 308 Walk(v, n.Doc) 309 } 310 Walk(v, n.Name) 311 Walk(v, n.Type) 312 if n.Comment != nil { 313 Walk(v, n.Comment) 314 } 315 316 case *BadDecl: 317 // nothing to do 318 319 case *GenDecl: 320 if n.Doc != nil { 321 Walk(v, n.Doc) 322 } 323 for _, s := range n.Specs { 324 Walk(v, s) 325 } 326 327 case *FuncDecl: 328 if n.Doc != nil { 329 Walk(v, n.Doc) 330 } 331 if n.Recv != nil { 332 Walk(v, n.Recv) 333 } 334 Walk(v, n.Name) 335 Walk(v, n.Type) 336 if n.Body != nil { 337 Walk(v, n.Body) 338 } 339 340 // Files and packages 341 case *File: 342 if n.Doc != nil { 343 Walk(v, n.Doc) 344 } 345 Walk(v, n.Name) 346 walkDeclList(v, n.Decls) 347 for _, g := range n.Comments { 348 Walk(v, g) 349 } 350 // don't walk n.Comments - they have been 351 // visited already through the individual 352 // nodes 353 354 case *Package: 355 for _, f := range n.Files { 356 Walk(v, f) 357 } 358 359 default: 360 fmt.Printf("ast.Walk: unexpected node type %T", n) 361 panic("ast.Walk") 362 } 363 364 v.Visit(nil) 365 } 366 367 type inspector func(Node) bool 368 369 func (f inspector) Visit(node Node) Visitor { 370 if f(node) { 371 return f 372 } 373 return nil 374 } 375 376 // Inspect traverses an AST in depth-first order: It starts by calling 377 // f(node); node must not be nil. If f returns true, Inspect invokes f 378 // for all the non-nil children of node, recursively. 379 // 380 func Inspect(node Node, f func(Node) bool) { 381 Walk(inspector(f), node) 382 }