@@ -25,12 +25,34 @@ import (
25
25
// each of the non-nil children of node, followed by a call of after. Both
26
26
// functions may be nil. If before is nil, it is assumed to always return true.
27
27
func Walk (node Node , before func (Node ) bool , after func (Node )) {
28
- walk (& inspector {before : before , after : after }, node )
28
+ v := & inspector {before : before , after : after }
29
+ walk (node , v .Before , v .After )
29
30
}
30
31
31
32
// WalkVisitor traverses an AST in depth-first order with a [Visitor].
32
33
func WalkVisitor (node Node , visitor Visitor ) {
33
- walk (visitor , node )
34
+ v := & stackVisitor {stack : []Visitor {visitor }}
35
+ walk (node , v .Before , v .After )
36
+ }
37
+
38
+ // stackVisitor helps implement Visitor support on top of Walk.
39
+ type stackVisitor struct {
40
+ stack []Visitor
41
+ }
42
+
43
+ func (v * stackVisitor ) Before (node Node ) bool {
44
+ current := v .stack [len (v .stack )- 1 ]
45
+ next := current .Before (node )
46
+ if next == nil {
47
+ return false
48
+ }
49
+ v .stack = append (v .stack , next )
50
+ return true
51
+ }
52
+
53
+ func (v * stackVisitor ) After (node Node ) {
54
+ v .stack [len (v .stack )- 1 ] = nil // set visitor to nil so it can be garbage collected
55
+ v .stack = v .stack [:len (v .stack )- 1 ]
34
56
}
35
57
36
58
// A Visitor's before method is invoked for each node encountered by Walk.
@@ -41,25 +63,20 @@ type Visitor interface {
41
63
After (node Node )
42
64
}
43
65
44
- func walkList [N Node ](v Visitor , list []N ) {
66
+ func walkList [N Node ](list []N , before func ( Node ) bool , after func ( Node ) ) {
45
67
for _ , node := range list {
46
- walk (v , node )
68
+ walk (node , before , after )
47
69
}
48
70
}
49
71
50
- // walk traverses an AST in depth-first order: It starts by calling
51
- // v.Visit(node); node must not be nil. If the visitor w returned by
52
- // v.Visit(node) is not nil, walk is invoked recursively with visitor
53
- // w for each of the non-nil children of node, followed by a call of
54
- // w.Visit(nil).
55
- func walk (v Visitor , node Node ) {
56
- if v = v .Before (node ); v == nil {
72
+ func walk (node Node , before func (Node ) bool , after func (Node )) {
73
+ if ! before (node ) {
57
74
return
58
75
}
59
76
60
77
// TODO: record the comment groups and interleave with the values like for
61
78
// parsing and printing?
62
- walkList (v , Comments (node ))
79
+ walkList (Comments (node ), before , after )
63
80
64
81
// walk children
65
82
// (the order of the cases matches the order
@@ -70,121 +87,121 @@ func walk(v Visitor, node Node) {
70
87
// nothing to do
71
88
72
89
case * CommentGroup :
73
- walkList (v , n .List )
90
+ walkList (n .List , before , after )
74
91
75
92
case * Attribute :
76
93
// nothing to do
77
94
78
95
case * Field :
79
- walk (v , n .Label )
96
+ walk (n .Label , before , after )
80
97
if n .Value != nil {
81
- walk (v , n .Value )
98
+ walk (n .Value , before , after )
82
99
}
83
- walkList (v , n .Attrs )
100
+ walkList (n .Attrs , before , after )
84
101
85
102
case * Func :
86
- walkList (v , n .Args )
87
- walk (v , n .Ret )
103
+ walkList (n .Args , before , after )
104
+ walk (n .Ret , before , after )
88
105
89
106
case * StructLit :
90
- walkList (v , n .Elts )
107
+ walkList (n .Elts , before , after )
91
108
92
109
// Expressions
93
110
case * BottomLit , * BadExpr , * Ident , * BasicLit :
94
111
// nothing to do
95
112
96
113
case * Interpolation :
97
- walkList (v , n .Elts )
114
+ walkList (n .Elts , before , after )
98
115
99
116
case * ListLit :
100
- walkList (v , n .Elts )
117
+ walkList (n .Elts , before , after )
101
118
102
119
case * Ellipsis :
103
120
if n .Type != nil {
104
- walk (v , n .Type )
121
+ walk (n .Type , before , after )
105
122
}
106
123
107
124
case * ParenExpr :
108
- walk (v , n .X )
125
+ walk (n .X , before , after )
109
126
110
127
case * SelectorExpr :
111
- walk (v , n .X )
112
- walk (v , n .Sel )
128
+ walk (n .X , before , after )
129
+ walk (n .Sel , before , after )
113
130
114
131
case * IndexExpr :
115
- walk (v , n .X )
116
- walk (v , n .Index )
132
+ walk (n .X , before , after )
133
+ walk (n .Index , before , after )
117
134
118
135
case * SliceExpr :
119
- walk (v , n .X )
136
+ walk (n .X , before , after )
120
137
if n .Low != nil {
121
- walk (v , n .Low )
138
+ walk (n .Low , before , after )
122
139
}
123
140
if n .High != nil {
124
- walk (v , n .High )
141
+ walk (n .High , before , after )
125
142
}
126
143
127
144
case * CallExpr :
128
- walk (v , n .Fun )
129
- walkList (v , n .Args )
145
+ walk (n .Fun , before , after )
146
+ walkList (n .Args , before , after )
130
147
131
148
case * UnaryExpr :
132
- walk (v , n .X )
149
+ walk (n .X , before , after )
133
150
134
151
case * BinaryExpr :
135
- walk (v , n .X )
136
- walk (v , n .Y )
152
+ walk (n .X , before , after )
153
+ walk (n .Y , before , after )
137
154
138
155
// Declarations
139
156
case * ImportSpec :
140
157
if n .Name != nil {
141
- walk (v , n .Name )
158
+ walk (n .Name , before , after )
142
159
}
143
- walk (v , n .Path )
160
+ walk (n .Path , before , after )
144
161
145
162
case * BadDecl :
146
163
// nothing to do
147
164
148
165
case * ImportDecl :
149
- walkList (v , n .Specs )
166
+ walkList (n .Specs , before , after )
150
167
151
168
case * EmbedDecl :
152
- walk (v , n .Expr )
169
+ walk (n .Expr , before , after )
153
170
154
171
case * LetClause :
155
- walk (v , n .Ident )
156
- walk (v , n .Expr )
172
+ walk (n .Ident , before , after )
173
+ walk (n .Expr , before , after )
157
174
158
175
case * Alias :
159
- walk (v , n .Ident )
160
- walk (v , n .Expr )
176
+ walk (n .Ident , before , after )
177
+ walk (n .Expr , before , after )
161
178
162
179
case * Comprehension :
163
- walkList (v , n .Clauses )
164
- walk (v , n .Value )
180
+ walkList (n .Clauses , before , after )
181
+ walk (n .Value , before , after )
165
182
166
183
// Files and packages
167
184
case * File :
168
- walkList (v , n .Decls )
185
+ walkList (n .Decls , before , after )
169
186
170
187
case * Package :
171
- walk (v , n .Name )
188
+ walk (n .Name , before , after )
172
189
173
190
case * ForClause :
174
191
if n .Key != nil {
175
- walk (v , n .Key )
192
+ walk (n .Key , before , after )
176
193
}
177
- walk (v , n .Value )
178
- walk (v , n .Source )
194
+ walk (n .Value , before , after )
195
+ walk (n .Source , before , after )
179
196
180
197
case * IfClause :
181
- walk (v , n .Condition )
198
+ walk (n .Condition , before , after )
182
199
183
200
default :
184
201
panic (fmt .Sprintf ("Walk: unexpected node type %T" , n ))
185
202
}
186
203
187
- v . After (node )
204
+ after (node )
188
205
}
189
206
190
207
type inspector struct {
@@ -200,14 +217,14 @@ type commentFrame struct {
200
217
pos int8
201
218
}
202
219
203
- func (f * inspector ) Before (node Node ) Visitor {
220
+ func (f * inspector ) Before (node Node ) bool {
204
221
if f .before == nil || f .before (node ) {
205
222
f .commentStack = append (f .commentStack , f .current )
206
223
f .current = commentFrame {cg : Comments (node )}
207
224
f .visitComments (f .current .pos )
208
- return f
225
+ return true
209
226
}
210
- return nil
227
+ return false
211
228
}
212
229
213
230
func (f * inspector ) After (node Node ) {
0 commit comments