github.com/goplus/gop@v1.2.6/ast/walk.go (about)

     1  /*
     2   * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ast
    18  
    19  import (
    20  	"fmt"
    21  )
    22  
    23  // Visitor - A Visitor's Visit method is invoked for each node encountered by Walk.
    24  // If the result visitor w is not nil, Walk visits each of the children
    25  // of node with the visitor w, followed by a call of w.Visit(nil).
    26  type Visitor interface {
    27  	Visit(node Node) (w Visitor)
    28  }
    29  
    30  // Helper functions for common node lists. They may be empty.
    31  
    32  func walkIdentList(v Visitor, list []*Ident) {
    33  	for _, x := range list {
    34  		Walk(v, x)
    35  	}
    36  }
    37  
    38  func walkExprList(v Visitor, list []Expr) {
    39  	for _, x := range list {
    40  		Walk(v, x)
    41  	}
    42  }
    43  
    44  func walkStmtList(v Visitor, list []Stmt) {
    45  	for _, x := range list {
    46  		Walk(v, x)
    47  	}
    48  }
    49  
    50  func walkDeclList(v Visitor, list []Decl) {
    51  	for _, x := range list {
    52  		Walk(v, x)
    53  	}
    54  }
    55  
    56  // TODO(gri): Investigate if providing a closure to Walk leads to
    57  //            simpler use (and may help eliminate Inspect in turn).
    58  
    59  // Walk traverses an AST in depth-first order: It starts by calling
    60  // v.Visit(node); node must not be nil. If the visitor w returned by
    61  // v.Visit(node) is not nil, Walk is invoked recursively with visitor
    62  // w for each of the non-nil children of node, followed by a call of
    63  // w.Visit(nil).
    64  func Walk(v Visitor, node Node) {
    65  	if v = v.Visit(node); v == nil {
    66  		return
    67  	}
    68  
    69  	// walk children
    70  	// (the order of the cases matches the order
    71  	// of the corresponding node types in ast.go)
    72  	switch n := node.(type) {
    73  	// Comments and fields
    74  	case *Comment:
    75  		// nothing to do
    76  
    77  	case *CommentGroup:
    78  		for _, c := range n.List {
    79  			Walk(v, c)
    80  		}
    81  
    82  	case *Field:
    83  		if n.Doc != nil {
    84  			Walk(v, n.Doc)
    85  		}
    86  		walkIdentList(v, n.Names)
    87  		Walk(v, n.Type)
    88  		if n.Tag != nil {
    89  			Walk(v, n.Tag)
    90  		}
    91  		if n.Comment != nil {
    92  			Walk(v, n.Comment)
    93  		}
    94  
    95  	case *FieldList:
    96  		for _, f := range n.List {
    97  			Walk(v, f)
    98  		}
    99  
   100  	// Expressions
   101  	case *BadExpr, *Ident:
   102  		// nothing to do
   103  
   104  	case *BasicLit:
   105  		if n.Extra != nil { // Go+ extended
   106  			for _, part := range n.Extra.Parts {
   107  				if e, ok := part.(Expr); ok {
   108  					Walk(v, e)
   109  				}
   110  			}
   111  		}
   112  
   113  	case *Ellipsis:
   114  		if n.Elt != nil {
   115  			Walk(v, n.Elt)
   116  		}
   117  
   118  	case *FuncLit:
   119  		Walk(v, n.Type)
   120  		Walk(v, n.Body)
   121  
   122  	case *CompositeLit:
   123  		if n.Type != nil {
   124  			Walk(v, n.Type)
   125  		}
   126  		walkExprList(v, n.Elts)
   127  
   128  	case *ParenExpr:
   129  		Walk(v, n.X)
   130  
   131  	case *SelectorExpr:
   132  		Walk(v, n.X)
   133  		Walk(v, n.Sel)
   134  
   135  	case *IndexExpr:
   136  		Walk(v, n.X)
   137  		Walk(v, n.Index)
   138  
   139  	case *IndexListExpr:
   140  		Walk(v, n.X)
   141  		walkExprList(v, n.Indices)
   142  
   143  	case *SliceExpr:
   144  		Walk(v, n.X)
   145  		if n.Low != nil {
   146  			Walk(v, n.Low)
   147  		}
   148  		if n.High != nil {
   149  			Walk(v, n.High)
   150  		}
   151  		if n.Max != nil {
   152  			Walk(v, n.Max)
   153  		}
   154  
   155  	case *TypeAssertExpr:
   156  		Walk(v, n.X)
   157  		if n.Type != nil {
   158  			Walk(v, n.Type)
   159  		}
   160  
   161  	case *CallExpr:
   162  		Walk(v, n.Fun)
   163  		walkExprList(v, n.Args)
   164  
   165  	case *StarExpr:
   166  		Walk(v, n.X)
   167  
   168  	case *UnaryExpr:
   169  		Walk(v, n.X)
   170  
   171  	case *BinaryExpr:
   172  		Walk(v, n.X)
   173  		Walk(v, n.Y)
   174  
   175  	case *KeyValueExpr:
   176  		Walk(v, n.Key)
   177  		Walk(v, n.Value)
   178  
   179  	// Types
   180  	case *ArrayType:
   181  		if n.Len != nil {
   182  			Walk(v, n.Len)
   183  		}
   184  		Walk(v, n.Elt)
   185  
   186  	case *StructType:
   187  		Walk(v, n.Fields)
   188  
   189  	case *FuncType:
   190  		if n.Params != nil {
   191  			Walk(v, n.Params)
   192  		}
   193  		if n.Results != nil {
   194  			Walk(v, n.Results)
   195  		}
   196  
   197  	case *InterfaceType:
   198  		Walk(v, n.Methods)
   199  
   200  	case *MapType:
   201  		Walk(v, n.Key)
   202  		Walk(v, n.Value)
   203  
   204  	case *ChanType:
   205  		Walk(v, n.Value)
   206  
   207  	// Statements
   208  	case *BadStmt:
   209  		// nothing to do
   210  
   211  	case *DeclStmt:
   212  		Walk(v, n.Decl)
   213  
   214  	case *EmptyStmt:
   215  		// nothing to do
   216  
   217  	case *LabeledStmt:
   218  		Walk(v, n.Label)
   219  		Walk(v, n.Stmt)
   220  
   221  	case *ExprStmt:
   222  		Walk(v, n.X)
   223  
   224  	case *SendStmt:
   225  		Walk(v, n.Chan)
   226  		Walk(v, n.Value)
   227  
   228  	case *IncDecStmt:
   229  		Walk(v, n.X)
   230  
   231  	case *AssignStmt:
   232  		walkExprList(v, n.Lhs)
   233  		walkExprList(v, n.Rhs)
   234  
   235  	case *GoStmt:
   236  		Walk(v, n.Call)
   237  
   238  	case *DeferStmt:
   239  		Walk(v, n.Call)
   240  
   241  	case *ReturnStmt:
   242  		walkExprList(v, n.Results)
   243  
   244  	case *BranchStmt:
   245  		if n.Label != nil {
   246  			Walk(v, n.Label)
   247  		}
   248  
   249  	case *BlockStmt:
   250  		walkStmtList(v, n.List)
   251  
   252  	case *IfStmt:
   253  		if n.Init != nil {
   254  			Walk(v, n.Init)
   255  		}
   256  		Walk(v, n.Cond)
   257  		Walk(v, n.Body)
   258  		if n.Else != nil {
   259  			Walk(v, n.Else)
   260  		}
   261  
   262  	case *CaseClause:
   263  		walkExprList(v, n.List)
   264  		walkStmtList(v, n.Body)
   265  
   266  	case *SwitchStmt:
   267  		if n.Init != nil {
   268  			Walk(v, n.Init)
   269  		}
   270  		if n.Tag != nil {
   271  			Walk(v, n.Tag)
   272  		}
   273  		Walk(v, n.Body)
   274  
   275  	case *TypeSwitchStmt:
   276  		if n.Init != nil {
   277  			Walk(v, n.Init)
   278  		}
   279  		Walk(v, n.Assign)
   280  		Walk(v, n.Body)
   281  
   282  	case *CommClause:
   283  		if n.Comm != nil {
   284  			Walk(v, n.Comm)
   285  		}
   286  		walkStmtList(v, n.Body)
   287  
   288  	case *SelectStmt:
   289  		Walk(v, n.Body)
   290  
   291  	case *ForStmt:
   292  		if n.Init != nil {
   293  			Walk(v, n.Init)
   294  		}
   295  		if n.Cond != nil {
   296  			Walk(v, n.Cond)
   297  		}
   298  		if n.Post != nil {
   299  			Walk(v, n.Post)
   300  		}
   301  		Walk(v, n.Body)
   302  
   303  	case *RangeStmt:
   304  		if n.Key != nil {
   305  			Walk(v, n.Key)
   306  		}
   307  		if n.Value != nil {
   308  			Walk(v, n.Value)
   309  		}
   310  		Walk(v, n.X)
   311  		Walk(v, n.Body)
   312  
   313  	// Declarations
   314  	case *ImportSpec:
   315  		if n.Doc != nil {
   316  			Walk(v, n.Doc)
   317  		}
   318  		if n.Name != nil {
   319  			Walk(v, n.Name)
   320  		}
   321  		Walk(v, n.Path)
   322  		if n.Comment != nil {
   323  			Walk(v, n.Comment)
   324  		}
   325  
   326  	case *ValueSpec:
   327  		if n.Doc != nil {
   328  			Walk(v, n.Doc)
   329  		}
   330  		walkIdentList(v, n.Names)
   331  		if n.Type != nil {
   332  			Walk(v, n.Type)
   333  		}
   334  		walkExprList(v, n.Values)
   335  		if n.Comment != nil {
   336  			Walk(v, n.Comment)
   337  		}
   338  
   339  	case *TypeSpec:
   340  		if n.Doc != nil {
   341  			Walk(v, n.Doc)
   342  		}
   343  		Walk(v, n.Name)
   344  		Walk(v, n.Type)
   345  		if n.Comment != nil {
   346  			Walk(v, n.Comment)
   347  		}
   348  
   349  	case *BadDecl:
   350  		// nothing to do
   351  
   352  	case *GenDecl:
   353  		if n.Doc != nil {
   354  			Walk(v, n.Doc)
   355  		}
   356  		for _, s := range n.Specs {
   357  			Walk(v, s)
   358  		}
   359  
   360  	case *FuncDecl:
   361  		if !n.Shadow { // not a shadow entry
   362  			if n.Doc != nil {
   363  				Walk(v, n.Doc)
   364  			}
   365  			if n.Recv != nil {
   366  				Walk(v, n.Recv)
   367  			}
   368  			Walk(v, n.Name)
   369  			Walk(v, n.Type)
   370  		}
   371  		if n.Body != nil {
   372  			Walk(v, n.Body)
   373  		}
   374  
   375  	// Files and packages
   376  	case *File:
   377  		if n.Doc != nil {
   378  			Walk(v, n.Doc)
   379  		}
   380  		if !n.NoPkgDecl {
   381  			Walk(v, n.Name)
   382  		}
   383  		walkDeclList(v, n.Decls)
   384  		// don't walk n.Comments - they have been
   385  		// visited already through the individual
   386  		// nodes
   387  
   388  	case *Package:
   389  		for _, f := range n.Files {
   390  			Walk(v, f)
   391  		}
   392  
   393  	// Go+ extended expr and stmt
   394  	case *SliceLit:
   395  		walkExprList(v, n.Elts)
   396  
   397  	case *LambdaExpr:
   398  		walkIdentList(v, n.Lhs)
   399  		walkExprList(v, n.Rhs)
   400  
   401  	case *LambdaExpr2:
   402  		walkIdentList(v, n.Lhs)
   403  		Walk(v, n.Body)
   404  
   405  	case *ForPhrase:
   406  		if n.Key != nil {
   407  			Walk(v, n.Key)
   408  		}
   409  		if n.Value != nil {
   410  			Walk(v, n.Value)
   411  		}
   412  		if n.Init != nil {
   413  			Walk(v, n.Init)
   414  		}
   415  		if n.Cond != nil {
   416  			Walk(v, n.Cond)
   417  		}
   418  		Walk(v, n.X)
   419  
   420  	case *ComprehensionExpr:
   421  		if n.Elt != nil {
   422  			Walk(v, n.Elt)
   423  		}
   424  		for _, x := range n.Fors {
   425  			Walk(v, x)
   426  		}
   427  
   428  	case *ForPhraseStmt:
   429  		Walk(v, n.ForPhrase)
   430  		Walk(v, n.Body)
   431  
   432  	case *RangeExpr:
   433  		if n.First != nil {
   434  			Walk(v, n.First)
   435  		}
   436  		if n.Last != nil {
   437  			Walk(v, n.Last)
   438  		}
   439  		if n.Expr3 != nil {
   440  			Walk(v, n.Expr3)
   441  		}
   442  
   443  	case *ErrWrapExpr:
   444  		Walk(v, n.X)
   445  		if n.Default != nil {
   446  			Walk(v, n.Default)
   447  		}
   448  
   449  	case *OverloadFuncDecl:
   450  		if n.Doc != nil {
   451  			Walk(v, n.Doc)
   452  		}
   453  		if n.Recv != nil {
   454  			Walk(v, n.Recv)
   455  		}
   456  		Walk(v, n.Name)
   457  		walkExprList(v, n.Funcs)
   458  
   459  	case *EnvExpr:
   460  		Walk(v, n.Name)
   461  
   462  	default:
   463  		panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
   464  	}
   465  
   466  	v.Visit(nil)
   467  }
   468  
   469  type inspector func(Node) bool
   470  
   471  func (f inspector) Visit(node Node) Visitor {
   472  	if f(node) {
   473  		return f
   474  	}
   475  	return nil
   476  }
   477  
   478  // Inspect traverses an AST in depth-first order: It starts by calling
   479  // f(node); node must not be nil. If f returns true, Inspect invokes f
   480  // recursively for each of the non-nil children of node, followed by a
   481  // call of f(nil).
   482  func Inspect(node Node, f func(Node) bool) {
   483  	Walk(inspector(f), node)
   484  }