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