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  }