blob: 1491149c6a47919e0a7f42cbadde412fd25d25f1 [file] [log] [blame]
Alan Donovan312d1a52017-10-02 10:10:28 -04001// 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
5package 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).
12func Walk(n Node, f func(Node) bool) {
alandonovan34a33192019-02-22 14:25:09 -050013 if n == nil {
14 panic("nil")
15 }
Alan Donovan312d1a52017-10-02 10:10:28 -040016 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:
Alan Donovan312d1a52017-10-02 10:10:28 -040037 Walk(n.LHS, f)
alandonovan34a33192019-02-22 14:25:09 -050038 Walk(n.RHS, f)
Alan Donovan312d1a52017-10-02 10:10:28 -040039
40 case *DefStmt:
41 Walk(n.Name, f)
alandonovan6ddc71c2019-06-04 09:08:55 -040042 for _, param := range n.Params {
Alan Donovan312d1a52017-10-02 10:10:28 -040043 Walk(param, f)
44 }
alandonovan6ddc71c2019-06-04 09:08:55 -040045 walkStmts(n.Body, f)
Alan Donovan312d1a52017-10-02 10:10:28 -040046
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
Laurent Le Brun28ceca72018-02-26 15:01:53 +010074 case *ParenExpr:
75 Walk(n.X, f)
76
Alan Donovan312d1a52017-10-02 10:10:28 -040077 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:
alandonovan34a33192019-02-22 14:25:09 -0500103 Walk(n.Body, f)
Alan Donovan312d1a52017-10-02 10:10:28 -0400104 for _, clause := range n.Clauses {
105 Walk(clause, f)
106 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400107
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:
alandonovan34a33192019-02-22 14:25:09 -0500128 if n.X != nil {
129 Walk(n.X, f)
130 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400131
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:
alandonovan6ddc71c2019-06-04 09:08:55 -0400147 for _, param := range n.Params {
Alan Donovan312d1a52017-10-02 10:10:28 -0400148 Walk(param, f)
149 }
alandonovan6ddc71c2019-06-04 09:08:55 -0400150 Walk(n.Body, f)
Alan Donovan312d1a52017-10-02 10:10:28 -0400151
152 default:
153 panic(n)
154 }
155
156 f(nil)
157}
158
159func walkStmts(stmts []Stmt, f func(Node) bool) {
160 for _, stmt := range stmts {
161 Walk(stmt, f)
162 }
163}