...

Source file src/go/ast/walk.go

Documentation: go/ast

		 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  // A Visitor's Visit method is invoked for each node encountered by Walk.
		 8  // If the result visitor w is not nil, Walk visits each of the children
		 9  // of node with the visitor w, followed by a call of w.Visit(nil).
		10  type Visitor interface {
		11  	Visit(node Node) (w Visitor)
		12  }
		13  
		14  // Helper functions for common node lists. They may be empty.
		15  
		16  func walkIdentList(v Visitor, list []*Ident) {
		17  	for _, x := range list {
		18  		Walk(v, x)
		19  	}
		20  }
		21  
		22  func walkExprList(v Visitor, list []Expr) {
		23  	for _, x := range list {
		24  		Walk(v, x)
		25  	}
		26  }
		27  
		28  func walkStmtList(v Visitor, list []Stmt) {
		29  	for _, x := range list {
		30  		Walk(v, x)
		31  	}
		32  }
		33  
		34  func walkDeclList(v Visitor, list []Decl) {
		35  	for _, x := range list {
		36  		Walk(v, x)
		37  	}
		38  }
		39  
		40  // TODO(gri): Investigate if providing a closure to Walk leads to
		41  //						simpler use (and may help eliminate Inspect in turn).
		42  
		43  // Walk traverses an AST in depth-first order: It starts by calling
		44  // v.Visit(node); node must not be nil. If the visitor w returned by
		45  // v.Visit(node) is not nil, Walk is invoked recursively with visitor
		46  // w for each of the non-nil children of node, followed by a call of
		47  // w.Visit(nil).
		48  //
		49  func Walk(v Visitor, node Node) {
		50  	if v = v.Visit(node); v == nil {
		51  		return
		52  	}
		53  
		54  	// walk children
		55  	// (the order of the cases matches the order
		56  	// of the corresponding node types in ast.go)
		57  	switch n := node.(type) {
		58  	// Comments and fields
		59  	case *Comment:
		60  		// nothing to do
		61  
		62  	case *CommentGroup:
		63  		for _, c := range n.List {
		64  			Walk(v, c)
		65  		}
		66  
		67  	case *Field:
		68  		if n.Doc != nil {
		69  			Walk(v, n.Doc)
		70  		}
		71  		walkIdentList(v, n.Names)
		72  		if n.Type != nil {
		73  			Walk(v, n.Type)
		74  		}
		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  		walkFuncTypeParams(v, n)
	 165  		if n.Params != nil {
	 166  			Walk(v, n.Params)
	 167  		}
	 168  		if n.Results != nil {
	 169  			Walk(v, n.Results)
	 170  		}
	 171  
	 172  	case *InterfaceType:
	 173  		Walk(v, n.Methods)
	 174  
	 175  	case *MapType:
	 176  		Walk(v, n.Key)
	 177  		Walk(v, n.Value)
	 178  
	 179  	case *ChanType:
	 180  		Walk(v, n.Value)
	 181  
	 182  	// Statements
	 183  	case *BadStmt:
	 184  		// nothing to do
	 185  
	 186  	case *DeclStmt:
	 187  		Walk(v, n.Decl)
	 188  
	 189  	case *EmptyStmt:
	 190  		// nothing to do
	 191  
	 192  	case *LabeledStmt:
	 193  		Walk(v, n.Label)
	 194  		Walk(v, n.Stmt)
	 195  
	 196  	case *ExprStmt:
	 197  		Walk(v, n.X)
	 198  
	 199  	case *SendStmt:
	 200  		Walk(v, n.Chan)
	 201  		Walk(v, n.Value)
	 202  
	 203  	case *IncDecStmt:
	 204  		Walk(v, n.X)
	 205  
	 206  	case *AssignStmt:
	 207  		walkExprList(v, n.Lhs)
	 208  		walkExprList(v, n.Rhs)
	 209  
	 210  	case *GoStmt:
	 211  		Walk(v, n.Call)
	 212  
	 213  	case *DeferStmt:
	 214  		Walk(v, n.Call)
	 215  
	 216  	case *ReturnStmt:
	 217  		walkExprList(v, n.Results)
	 218  
	 219  	case *BranchStmt:
	 220  		if n.Label != nil {
	 221  			Walk(v, n.Label)
	 222  		}
	 223  
	 224  	case *BlockStmt:
	 225  		walkStmtList(v, n.List)
	 226  
	 227  	case *IfStmt:
	 228  		if n.Init != nil {
	 229  			Walk(v, n.Init)
	 230  		}
	 231  		Walk(v, n.Cond)
	 232  		Walk(v, n.Body)
	 233  		if n.Else != nil {
	 234  			Walk(v, n.Else)
	 235  		}
	 236  
	 237  	case *CaseClause:
	 238  		walkExprList(v, n.List)
	 239  		walkStmtList(v, n.Body)
	 240  
	 241  	case *SwitchStmt:
	 242  		if n.Init != nil {
	 243  			Walk(v, n.Init)
	 244  		}
	 245  		if n.Tag != nil {
	 246  			Walk(v, n.Tag)
	 247  		}
	 248  		Walk(v, n.Body)
	 249  
	 250  	case *TypeSwitchStmt:
	 251  		if n.Init != nil {
	 252  			Walk(v, n.Init)
	 253  		}
	 254  		Walk(v, n.Assign)
	 255  		Walk(v, n.Body)
	 256  
	 257  	case *CommClause:
	 258  		if n.Comm != nil {
	 259  			Walk(v, n.Comm)
	 260  		}
	 261  		walkStmtList(v, n.Body)
	 262  
	 263  	case *SelectStmt:
	 264  		Walk(v, n.Body)
	 265  
	 266  	case *ForStmt:
	 267  		if n.Init != nil {
	 268  			Walk(v, n.Init)
	 269  		}
	 270  		if n.Cond != nil {
	 271  			Walk(v, n.Cond)
	 272  		}
	 273  		if n.Post != nil {
	 274  			Walk(v, n.Post)
	 275  		}
	 276  		Walk(v, n.Body)
	 277  
	 278  	case *RangeStmt:
	 279  		if n.Key != nil {
	 280  			Walk(v, n.Key)
	 281  		}
	 282  		if n.Value != nil {
	 283  			Walk(v, n.Value)
	 284  		}
	 285  		Walk(v, n.X)
	 286  		Walk(v, n.Body)
	 287  
	 288  	// Declarations
	 289  	case *ImportSpec:
	 290  		if n.Doc != nil {
	 291  			Walk(v, n.Doc)
	 292  		}
	 293  		if n.Name != nil {
	 294  			Walk(v, n.Name)
	 295  		}
	 296  		Walk(v, n.Path)
	 297  		if n.Comment != nil {
	 298  			Walk(v, n.Comment)
	 299  		}
	 300  
	 301  	case *ValueSpec:
	 302  		if n.Doc != nil {
	 303  			Walk(v, n.Doc)
	 304  		}
	 305  		walkIdentList(v, n.Names)
	 306  		if n.Type != nil {
	 307  			Walk(v, n.Type)
	 308  		}
	 309  		walkExprList(v, n.Values)
	 310  		if n.Comment != nil {
	 311  			Walk(v, n.Comment)
	 312  		}
	 313  
	 314  	case *TypeSpec:
	 315  		if n.Doc != nil {
	 316  			Walk(v, n.Doc)
	 317  		}
	 318  		Walk(v, n.Name)
	 319  		walkTypeSpecParams(v, n)
	 320  		Walk(v, n.Type)
	 321  		if n.Comment != nil {
	 322  			Walk(v, n.Comment)
	 323  		}
	 324  
	 325  	case *BadDecl:
	 326  		// nothing to do
	 327  
	 328  	case *GenDecl:
	 329  		if n.Doc != nil {
	 330  			Walk(v, n.Doc)
	 331  		}
	 332  		for _, s := range n.Specs {
	 333  			Walk(v, s)
	 334  		}
	 335  
	 336  	case *FuncDecl:
	 337  		if n.Doc != nil {
	 338  			Walk(v, n.Doc)
	 339  		}
	 340  		if n.Recv != nil {
	 341  			Walk(v, n.Recv)
	 342  		}
	 343  		Walk(v, n.Name)
	 344  		Walk(v, n.Type)
	 345  		if n.Body != nil {
	 346  			Walk(v, n.Body)
	 347  		}
	 348  
	 349  	// Files and packages
	 350  	case *File:
	 351  		if n.Doc != nil {
	 352  			Walk(v, n.Doc)
	 353  		}
	 354  		Walk(v, n.Name)
	 355  		walkDeclList(v, n.Decls)
	 356  		// don't walk n.Comments - they have been
	 357  		// visited already through the individual
	 358  		// nodes
	 359  
	 360  	case *Package:
	 361  		for _, f := range n.Files {
	 362  			Walk(v, f)
	 363  		}
	 364  
	 365  	default:
	 366  		walkOtherNodes(v, n)
	 367  	}
	 368  
	 369  	v.Visit(nil)
	 370  }
	 371  
	 372  type inspector func(Node) bool
	 373  
	 374  func (f inspector) Visit(node Node) Visitor {
	 375  	if f(node) {
	 376  		return f
	 377  	}
	 378  	return nil
	 379  }
	 380  
	 381  // Inspect traverses an AST in depth-first order: It starts by calling
	 382  // f(node); node must not be nil. If f returns true, Inspect invokes f
	 383  // recursively for each of the non-nil children of node, followed by a
	 384  // call of f(nil).
	 385  //
	 386  func Inspect(node Node, f func(Node) bool) {
	 387  	Walk(inspector(f), node)
	 388  }
	 389  

View as plain text