Skip to content

Commit fd64550

Browse files
committed
cue/ast: don't walk comments twice
I was surprised by the exported Walk function using the inspector type to then call the unexported walk function, rather than having a single Walk function without any intermediary state. From reading the code, it seems like the reason was to interleave visiting the node comments with the node contents themselves. However, we were also visiting the node comments in their entirety as part of walk, meaning we were visiting each comment twice. Moreover, there weren't any tests for this interleaving of comments, and I'm fairly sure that the logic wasn't sound, as the Token method which is meant to advance relative token positions was never called. On top of that, cue/ast is currently not able to represent comments which follow an entire node on a new line, as it can only represent inline comments or comments after a fixed number of tokens. It seems best to delete this untested and likely broken code for now, and attempt interleaving the visiting of comments again in the future once we have tests and better support for relative comment positions in cue/ast. For the time being, it seems like none of our walk API uses were interested in comments at all, so there are no visible changes. The fact that no user reported the double-walking of comments also seems to indicate that very few users relied on comment walking. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I7d43f5327dcdfc927d2d98c8978476a6da264c56 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194083 Reviewed-by: Roger Peppe <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 30f7d28 commit fd64550

File tree

1 file changed

+39
-104
lines changed

1 file changed

+39
-104
lines changed

cue/ast/walk.go

Lines changed: 39 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,12 @@ package ast
1616

1717
import (
1818
"fmt"
19-
20-
"cuelang.org/go/cue/token"
2119
)
2220

23-
// Walk traverses an AST in depth-first order: It starts by calling f(node);
24-
// node must not be nil. If before returns true, Walk invokes f recursively for
25-
// each of the non-nil children of node, followed by a call of after. Both
26-
// functions may be nil. If before is nil, it is assumed to always return true.
27-
func Walk(node Node, before func(Node) bool, after func(Node)) {
28-
v := &inspector{before: before, after: after}
29-
walk(node, v.Before, v.After)
30-
}
31-
3221
// WalkVisitor traverses an AST in depth-first order with a [Visitor].
3322
func WalkVisitor(node Node, visitor Visitor) {
3423
v := &stackVisitor{stack: []Visitor{visitor}}
35-
walk(node, v.Before, v.After)
24+
Walk(node, v.Before, v.After)
3625
}
3726

3827
// stackVisitor helps implement Visitor support on top of Walk.
@@ -65,12 +54,16 @@ type Visitor interface {
6554

6655
func walkList[N Node](list []N, before func(Node) bool, after func(Node)) {
6756
for _, node := range list {
68-
walk(node, before, after)
57+
Walk(node, before, after)
6958
}
7059
}
7160

72-
func walk(node Node, before func(Node) bool, after func(Node)) {
73-
if !before(node) {
61+
// Walk traverses an AST in depth-first order: It starts by calling f(node);
62+
// node must not be nil. If before returns true, Walk invokes f recursively for
63+
// each of the non-nil children of node, followed by a call of after. Both
64+
// functions may be nil. If before is nil, it is assumed to always return true.
65+
func Walk(node Node, before func(Node) bool, after func(Node)) {
66+
if before != nil && !before(node) {
7467
return
7568
}
7669

@@ -93,15 +86,15 @@ func walk(node Node, before func(Node) bool, after func(Node)) {
9386
// nothing to do
9487

9588
case *Field:
96-
walk(n.Label, before, after)
89+
Walk(n.Label, before, after)
9790
if n.Value != nil {
98-
walk(n.Value, before, after)
91+
Walk(n.Value, before, after)
9992
}
10093
walkList(n.Attrs, before, after)
10194

10295
case *Func:
10396
walkList(n.Args, before, after)
104-
walk(n.Ret, before, after)
97+
Walk(n.Ret, before, after)
10598

10699
case *StructLit:
107100
walkList(n.Elts, before, after)
@@ -118,46 +111,46 @@ func walk(node Node, before func(Node) bool, after func(Node)) {
118111

119112
case *Ellipsis:
120113
if n.Type != nil {
121-
walk(n.Type, before, after)
114+
Walk(n.Type, before, after)
122115
}
123116

124117
case *ParenExpr:
125-
walk(n.X, before, after)
118+
Walk(n.X, before, after)
126119

127120
case *SelectorExpr:
128-
walk(n.X, before, after)
129-
walk(n.Sel, before, after)
121+
Walk(n.X, before, after)
122+
Walk(n.Sel, before, after)
130123

131124
case *IndexExpr:
132-
walk(n.X, before, after)
133-
walk(n.Index, before, after)
125+
Walk(n.X, before, after)
126+
Walk(n.Index, before, after)
134127

135128
case *SliceExpr:
136-
walk(n.X, before, after)
129+
Walk(n.X, before, after)
137130
if n.Low != nil {
138-
walk(n.Low, before, after)
131+
Walk(n.Low, before, after)
139132
}
140133
if n.High != nil {
141-
walk(n.High, before, after)
134+
Walk(n.High, before, after)
142135
}
143136

144137
case *CallExpr:
145-
walk(n.Fun, before, after)
138+
Walk(n.Fun, before, after)
146139
walkList(n.Args, before, after)
147140

148141
case *UnaryExpr:
149-
walk(n.X, before, after)
142+
Walk(n.X, before, after)
150143

151144
case *BinaryExpr:
152-
walk(n.X, before, after)
153-
walk(n.Y, before, after)
145+
Walk(n.X, before, after)
146+
Walk(n.Y, before, after)
154147

155148
// Declarations
156149
case *ImportSpec:
157150
if n.Name != nil {
158-
walk(n.Name, before, after)
151+
Walk(n.Name, before, after)
159152
}
160-
walk(n.Path, before, after)
153+
Walk(n.Path, before, after)
161154

162155
case *BadDecl:
163156
// nothing to do
@@ -166,100 +159,42 @@ func walk(node Node, before func(Node) bool, after func(Node)) {
166159
walkList(n.Specs, before, after)
167160

168161
case *EmbedDecl:
169-
walk(n.Expr, before, after)
162+
Walk(n.Expr, before, after)
170163

171164
case *LetClause:
172-
walk(n.Ident, before, after)
173-
walk(n.Expr, before, after)
165+
Walk(n.Ident, before, after)
166+
Walk(n.Expr, before, after)
174167

175168
case *Alias:
176-
walk(n.Ident, before, after)
177-
walk(n.Expr, before, after)
169+
Walk(n.Ident, before, after)
170+
Walk(n.Expr, before, after)
178171

179172
case *Comprehension:
180173
walkList(n.Clauses, before, after)
181-
walk(n.Value, before, after)
174+
Walk(n.Value, before, after)
182175

183176
// Files and packages
184177
case *File:
185178
walkList(n.Decls, before, after)
186179

187180
case *Package:
188-
walk(n.Name, before, after)
181+
Walk(n.Name, before, after)
189182

190183
case *ForClause:
191184
if n.Key != nil {
192-
walk(n.Key, before, after)
185+
Walk(n.Key, before, after)
193186
}
194-
walk(n.Value, before, after)
195-
walk(n.Source, before, after)
187+
Walk(n.Value, before, after)
188+
Walk(n.Source, before, after)
196189

197190
case *IfClause:
198-
walk(n.Condition, before, after)
191+
Walk(n.Condition, before, after)
199192

200193
default:
201194
panic(fmt.Sprintf("Walk: unexpected node type %T", n))
202195
}
203196

204-
after(node)
205-
}
206-
207-
type inspector struct {
208-
before func(Node) bool
209-
after func(Node)
210-
211-
commentStack []commentFrame
212-
current commentFrame
213-
}
214-
215-
type commentFrame struct {
216-
cg []*CommentGroup
217-
pos int8
218-
}
219-
220-
func (f *inspector) Before(node Node) bool {
221-
if f.before == nil || f.before(node) {
222-
f.commentStack = append(f.commentStack, f.current)
223-
f.current = commentFrame{cg: Comments(node)}
224-
f.visitComments(f.current.pos)
225-
return true
226-
}
227-
return false
228-
}
229-
230-
func (f *inspector) After(node Node) {
231-
f.visitComments(127)
232-
p := len(f.commentStack) - 1
233-
f.current = f.commentStack[p]
234-
f.commentStack = f.commentStack[:p]
235-
f.current.pos++
236-
if f.after != nil {
237-
f.after(node)
238-
}
239-
}
240-
241-
func (f *inspector) Token(t token.Token) {
242-
f.current.pos++
243-
}
244-
245-
func (f *inspector) visitComments(pos int8) {
246-
c := &f.current
247-
for ; len(c.cg) > 0; c.cg = c.cg[1:] {
248-
cg := c.cg[0]
249-
if cg.Position == pos {
250-
continue
251-
}
252-
if f.before == nil || f.before(cg) {
253-
for _, c := range cg.List {
254-
if f.before == nil || f.before(c) {
255-
if f.after != nil {
256-
f.after(c)
257-
}
258-
}
259-
}
260-
if f.after != nil {
261-
f.after(cg)
262-
}
263-
}
197+
if after != nil {
198+
after(node)
264199
}
265200
}

0 commit comments

Comments
 (0)