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