...

Source file src/pkg/go/ast/walk.go

     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	}
   387	

View as plain text