1*4947cdc7SCole Faust// Copyright 2017 The Bazel Authors. All rights reserved. 2*4947cdc7SCole Faust// Use of this source code is governed by a BSD-style 3*4947cdc7SCole Faust// license that can be found in the LICENSE file. 4*4947cdc7SCole Faust 5*4947cdc7SCole Faustpackage syntax 6*4947cdc7SCole Faust 7*4947cdc7SCole Faust// Walk traverses a syntax tree in depth-first order. 8*4947cdc7SCole Faust// It starts by calling f(n); n must not be nil. 9*4947cdc7SCole Faust// If f returns true, Walk calls itself 10*4947cdc7SCole Faust// recursively for each non-nil child of n. 11*4947cdc7SCole Faust// Walk then calls f(nil). 12*4947cdc7SCole Faustfunc Walk(n Node, f func(Node) bool) { 13*4947cdc7SCole Faust if n == nil { 14*4947cdc7SCole Faust panic("nil") 15*4947cdc7SCole Faust } 16*4947cdc7SCole Faust if !f(n) { 17*4947cdc7SCole Faust return 18*4947cdc7SCole Faust } 19*4947cdc7SCole Faust 20*4947cdc7SCole Faust // TODO(adonovan): opt: order cases using profile data. 21*4947cdc7SCole Faust switch n := n.(type) { 22*4947cdc7SCole Faust case *File: 23*4947cdc7SCole Faust walkStmts(n.Stmts, f) 24*4947cdc7SCole Faust 25*4947cdc7SCole Faust case *ExprStmt: 26*4947cdc7SCole Faust Walk(n.X, f) 27*4947cdc7SCole Faust 28*4947cdc7SCole Faust case *BranchStmt: 29*4947cdc7SCole Faust // no-op 30*4947cdc7SCole Faust 31*4947cdc7SCole Faust case *IfStmt: 32*4947cdc7SCole Faust Walk(n.Cond, f) 33*4947cdc7SCole Faust walkStmts(n.True, f) 34*4947cdc7SCole Faust walkStmts(n.False, f) 35*4947cdc7SCole Faust 36*4947cdc7SCole Faust case *AssignStmt: 37*4947cdc7SCole Faust Walk(n.LHS, f) 38*4947cdc7SCole Faust Walk(n.RHS, f) 39*4947cdc7SCole Faust 40*4947cdc7SCole Faust case *DefStmt: 41*4947cdc7SCole Faust Walk(n.Name, f) 42*4947cdc7SCole Faust for _, param := range n.Params { 43*4947cdc7SCole Faust Walk(param, f) 44*4947cdc7SCole Faust } 45*4947cdc7SCole Faust walkStmts(n.Body, f) 46*4947cdc7SCole Faust 47*4947cdc7SCole Faust case *ForStmt: 48*4947cdc7SCole Faust Walk(n.Vars, f) 49*4947cdc7SCole Faust Walk(n.X, f) 50*4947cdc7SCole Faust walkStmts(n.Body, f) 51*4947cdc7SCole Faust 52*4947cdc7SCole Faust case *ReturnStmt: 53*4947cdc7SCole Faust if n.Result != nil { 54*4947cdc7SCole Faust Walk(n.Result, f) 55*4947cdc7SCole Faust } 56*4947cdc7SCole Faust 57*4947cdc7SCole Faust case *LoadStmt: 58*4947cdc7SCole Faust Walk(n.Module, f) 59*4947cdc7SCole Faust for _, from := range n.From { 60*4947cdc7SCole Faust Walk(from, f) 61*4947cdc7SCole Faust } 62*4947cdc7SCole Faust for _, to := range n.To { 63*4947cdc7SCole Faust Walk(to, f) 64*4947cdc7SCole Faust } 65*4947cdc7SCole Faust 66*4947cdc7SCole Faust case *Ident, *Literal: 67*4947cdc7SCole Faust // no-op 68*4947cdc7SCole Faust 69*4947cdc7SCole Faust case *ListExpr: 70*4947cdc7SCole Faust for _, x := range n.List { 71*4947cdc7SCole Faust Walk(x, f) 72*4947cdc7SCole Faust } 73*4947cdc7SCole Faust 74*4947cdc7SCole Faust case *ParenExpr: 75*4947cdc7SCole Faust Walk(n.X, f) 76*4947cdc7SCole Faust 77*4947cdc7SCole Faust case *CondExpr: 78*4947cdc7SCole Faust Walk(n.Cond, f) 79*4947cdc7SCole Faust Walk(n.True, f) 80*4947cdc7SCole Faust Walk(n.False, f) 81*4947cdc7SCole Faust 82*4947cdc7SCole Faust case *IndexExpr: 83*4947cdc7SCole Faust Walk(n.X, f) 84*4947cdc7SCole Faust Walk(n.Y, f) 85*4947cdc7SCole Faust 86*4947cdc7SCole Faust case *DictEntry: 87*4947cdc7SCole Faust Walk(n.Key, f) 88*4947cdc7SCole Faust Walk(n.Value, f) 89*4947cdc7SCole Faust 90*4947cdc7SCole Faust case *SliceExpr: 91*4947cdc7SCole Faust Walk(n.X, f) 92*4947cdc7SCole Faust if n.Lo != nil { 93*4947cdc7SCole Faust Walk(n.Lo, f) 94*4947cdc7SCole Faust } 95*4947cdc7SCole Faust if n.Hi != nil { 96*4947cdc7SCole Faust Walk(n.Hi, f) 97*4947cdc7SCole Faust } 98*4947cdc7SCole Faust if n.Step != nil { 99*4947cdc7SCole Faust Walk(n.Step, f) 100*4947cdc7SCole Faust } 101*4947cdc7SCole Faust 102*4947cdc7SCole Faust case *Comprehension: 103*4947cdc7SCole Faust Walk(n.Body, f) 104*4947cdc7SCole Faust for _, clause := range n.Clauses { 105*4947cdc7SCole Faust Walk(clause, f) 106*4947cdc7SCole Faust } 107*4947cdc7SCole Faust 108*4947cdc7SCole Faust case *IfClause: 109*4947cdc7SCole Faust Walk(n.Cond, f) 110*4947cdc7SCole Faust 111*4947cdc7SCole Faust case *ForClause: 112*4947cdc7SCole Faust Walk(n.Vars, f) 113*4947cdc7SCole Faust Walk(n.X, f) 114*4947cdc7SCole Faust 115*4947cdc7SCole Faust case *TupleExpr: 116*4947cdc7SCole Faust for _, x := range n.List { 117*4947cdc7SCole Faust Walk(x, f) 118*4947cdc7SCole Faust } 119*4947cdc7SCole Faust 120*4947cdc7SCole Faust case *DictExpr: 121*4947cdc7SCole Faust for _, entry := range n.List { 122*4947cdc7SCole Faust entry := entry.(*DictEntry) 123*4947cdc7SCole Faust Walk(entry.Key, f) 124*4947cdc7SCole Faust Walk(entry.Value, f) 125*4947cdc7SCole Faust } 126*4947cdc7SCole Faust 127*4947cdc7SCole Faust case *UnaryExpr: 128*4947cdc7SCole Faust if n.X != nil { 129*4947cdc7SCole Faust Walk(n.X, f) 130*4947cdc7SCole Faust } 131*4947cdc7SCole Faust 132*4947cdc7SCole Faust case *BinaryExpr: 133*4947cdc7SCole Faust Walk(n.X, f) 134*4947cdc7SCole Faust Walk(n.Y, f) 135*4947cdc7SCole Faust 136*4947cdc7SCole Faust case *DotExpr: 137*4947cdc7SCole Faust Walk(n.X, f) 138*4947cdc7SCole Faust Walk(n.Name, f) 139*4947cdc7SCole Faust 140*4947cdc7SCole Faust case *CallExpr: 141*4947cdc7SCole Faust Walk(n.Fn, f) 142*4947cdc7SCole Faust for _, arg := range n.Args { 143*4947cdc7SCole Faust Walk(arg, f) 144*4947cdc7SCole Faust } 145*4947cdc7SCole Faust 146*4947cdc7SCole Faust case *LambdaExpr: 147*4947cdc7SCole Faust for _, param := range n.Params { 148*4947cdc7SCole Faust Walk(param, f) 149*4947cdc7SCole Faust } 150*4947cdc7SCole Faust Walk(n.Body, f) 151*4947cdc7SCole Faust 152*4947cdc7SCole Faust default: 153*4947cdc7SCole Faust panic(n) 154*4947cdc7SCole Faust } 155*4947cdc7SCole Faust 156*4947cdc7SCole Faust f(nil) 157*4947cdc7SCole Faust} 158*4947cdc7SCole Faust 159*4947cdc7SCole Faustfunc walkStmts(stmts []Stmt, f func(Node) bool) { 160*4947cdc7SCole Faust for _, stmt := range stmts { 161*4947cdc7SCole Faust Walk(stmt, f) 162*4947cdc7SCole Faust } 163*4947cdc7SCole Faust} 164