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