src/pkg/go/ast/walk.go - The Go Programming Language

Golang

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