Black Lives Matter. Support the Equal Justice Initiative.

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