Skip to content

Commit 05640c2

Browse files
committed
cue/ast: move WalkVisitor and Visitor to astutil and unexport them
https://cuelang.org/cl/1194006 added ast.WalkVisitor and ast.Visitor so that the cue/ast and cue/ast/astutil packages could share the code rather than duplicating it. Roger correctly pointed out that ast.Walk is equally as powerful, one just needs to keep enough state somewhere like a method receiver. The new ast.stackVisitor type just added does exactly that. We can now move WalkVisitor and stackVisitor into cue/ast/astutil and unexport them, as they are the only users across the repository. The APIs were just exposed in master and not included in any release. Later on I would like to remove the needed for his walkVisitor layer, instead having the Sanitize and Resolve APIs keep their own state on top of the ast.Walk API. However, that work is not urgent, and would very easily be non-trivial, so leave a TODO for now. Signed-off-by: Daniel Martí <[email protected]> Change-Id: Ic35b997645da193aae42bd0489d5f5b1a0cdd071 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194084 Reviewed-by: Roger Peppe <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent fd64550 commit 05640c2

File tree

4 files changed

+71
-51
lines changed

4 files changed

+71
-51
lines changed

cue/ast/astutil/resolve.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ type ErrFunc func(pos token.Pos, msg string, args ...interface{})
7575
// Resolve resolves all identifiers in a file. Unresolved identifiers are
7676
// recorded in Unresolved. It will not overwrite already resolved values.
7777
func Resolve(f *ast.File, errFn ErrFunc) {
78-
ast.WalkVisitor(f, &scope{errFn: errFn, identFn: resolveIdent})
78+
walkVisitor(f, &scope{errFn: errFn, identFn: resolveIdent})
7979
}
8080

8181
// Resolve resolves all identifiers in an expression.
8282
// It will not overwrite already resolved values.
8383
func ResolveExpr(e ast.Expr, errFn ErrFunc) {
8484
f := &ast.File{}
85-
ast.WalkVisitor(e, &scope{file: f, errFn: errFn, identFn: resolveIdent})
85+
walkVisitor(e, &scope{file: f, errFn: errFn, identFn: resolveIdent})
8686
}
8787

8888
// A Scope maintains the set of named language entities declared
@@ -250,13 +250,13 @@ func (s *scope) lookup(name string) (p *scope, obj ast.Node, node entry) {
250250
}
251251

252252
func (s *scope) After(n ast.Node) {}
253-
func (s *scope) Before(n ast.Node) (w ast.Visitor) {
253+
func (s *scope) Before(n ast.Node) (w visitor) {
254254
switch x := n.(type) {
255255
case *ast.File:
256256
s := newScope(x, s, x, x.Decls)
257257
// Support imports.
258258
for _, d := range x.Decls {
259-
ast.WalkVisitor(d, s)
259+
walkVisitor(d, s)
260260
}
261261
return nil
262262

@@ -265,7 +265,7 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
265265

266266
case *ast.Comprehension:
267267
s = scopeClauses(s, x.Clauses)
268-
ast.WalkVisitor(x.Value, s)
268+
walkVisitor(x.Value, s)
269269
return nil
270270

271271
case *ast.Field:
@@ -277,10 +277,10 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
277277

278278
switch label := n.(type) {
279279
case *ast.ParenExpr:
280-
ast.WalkVisitor(label, s)
280+
walkVisitor(label, s)
281281

282282
case *ast.Interpolation:
283-
ast.WalkVisitor(label, s)
283+
walkVisitor(label, s)
284284

285285
case *ast.ListLit:
286286
if len(label.Elts) != 1 {
@@ -317,7 +317,7 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
317317
}
318318
}
319319
})
320-
ast.WalkVisitor(expr, s)
320+
walkVisitor(expr, s)
321321
}
322322

323323
if n := x.Value; n != nil {
@@ -329,7 +329,7 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
329329
n = alias.Expr
330330
}
331331
s.inField = true
332-
ast.WalkVisitor(n, s)
332+
walkVisitor(n, s)
333333
s.inField = false
334334
}
335335

@@ -342,7 +342,7 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
342342
delete(s.index, name) // The same name may still appear in another scope
343343

344344
if x.Expr != nil {
345-
ast.WalkVisitor(x.Expr, s)
345+
walkVisitor(x.Expr, s)
346346
}
347347
s.index[name] = saved
348348
return nil
@@ -354,7 +354,7 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
354354
delete(s.index, name) // The same name may still appear in another scope
355355

356356
if x.Expr != nil {
357-
ast.WalkVisitor(x.Expr, s)
357+
walkVisitor(x.Expr, s)
358358
}
359359
s.index[name] = saved
360360
return nil
@@ -367,7 +367,7 @@ func (s *scope) Before(n ast.Node) (w ast.Visitor) {
367367
// that resolve in a list.
368368

369369
case *ast.SelectorExpr:
370-
ast.WalkVisitor(x.X, s)
370+
walkVisitor(x.X, s)
371371
return nil
372372

373373
case *ast.Ident:
@@ -410,20 +410,20 @@ func scopeClauses(s *scope, clauses []ast.Clause) *scope {
410410
for _, c := range clauses {
411411
switch x := c.(type) {
412412
case *ast.ForClause:
413-
ast.WalkVisitor(x.Source, s)
413+
walkVisitor(x.Source, s)
414414
s = newScope(s.file, s, x, nil)
415415
if x.Key != nil {
416416
s.insert(x.Key.Name, x.Key, x)
417417
}
418418
s.insert(x.Value.Name, x.Value, x)
419419

420420
case *ast.LetClause:
421-
ast.WalkVisitor(x.Expr, s)
421+
walkVisitor(x.Expr, s)
422422
s = newScope(s.file, s, x, nil)
423423
s.insert(x.Ident.Name, x.Ident, x)
424424

425425
default:
426-
ast.WalkVisitor(c, s)
426+
walkVisitor(c, s)
427427
}
428428
}
429429
return s

cue/ast/astutil/sanitize.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func Sanitize(f *ast.File) error {
5050
}
5151

5252
// Gather all names.
53-
ast.WalkVisitor(f, &scope{
53+
walkVisitor(f, &scope{
5454
errFn: z.errf,
5555
nameFn: z.addName,
5656
identFn: z.markUsed,
@@ -67,7 +67,7 @@ func Sanitize(f *ast.File) error {
6767
index: make(map[string]entry),
6868
}
6969
z.fileScope = s
70-
ast.WalkVisitor(f, s)
70+
walkVisitor(f, s)
7171
if z.errs != nil {
7272
return z.errs
7373
}

cue/ast/astutil/walk.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2018 The CUE Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package astutil
16+
17+
import "cuelang.org/go/cue/ast"
18+
19+
// walkVisitor traverses an AST in depth-first order with a [visitor].
20+
//
21+
// TODO(mvdan): refactor away the need for walkVisitor;
22+
// Resolve and Sanitize should be able to use ast.Walk directly.
23+
func walkVisitor(node ast.Node, v visitor) {
24+
sv := &stackVisitor{stack: []visitor{v}}
25+
ast.Walk(node, sv.Before, sv.After)
26+
}
27+
28+
// stackVisitor helps implement visitor support on top of ast.Walk.
29+
type stackVisitor struct {
30+
stack []visitor
31+
}
32+
33+
func (v *stackVisitor) Before(node ast.Node) bool {
34+
current := v.stack[len(v.stack)-1]
35+
next := current.Before(node)
36+
if next == nil {
37+
return false
38+
}
39+
v.stack = append(v.stack, next)
40+
return true
41+
}
42+
43+
func (v *stackVisitor) After(node ast.Node) {
44+
v.stack[len(v.stack)-1] = nil // set visitor to nil so it can be garbage collected
45+
v.stack = v.stack[:len(v.stack)-1]
46+
}
47+
48+
// A visitor's before method is invoked for each node encountered by Walk.
49+
// If the result visitor w is true, Walk visits each of the children
50+
// of node with the visitor w, followed by a call of w.After.
51+
type visitor interface {
52+
Before(node ast.Node) (w visitor)
53+
After(node ast.Node)
54+
}

cue/ast/walk.go

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,6 @@ import (
1818
"fmt"
1919
)
2020

21-
// WalkVisitor traverses an AST in depth-first order with a [Visitor].
22-
func WalkVisitor(node Node, visitor Visitor) {
23-
v := &stackVisitor{stack: []Visitor{visitor}}
24-
Walk(node, v.Before, v.After)
25-
}
26-
27-
// stackVisitor helps implement Visitor support on top of Walk.
28-
type stackVisitor struct {
29-
stack []Visitor
30-
}
31-
32-
func (v *stackVisitor) Before(node Node) bool {
33-
current := v.stack[len(v.stack)-1]
34-
next := current.Before(node)
35-
if next == nil {
36-
return false
37-
}
38-
v.stack = append(v.stack, next)
39-
return true
40-
}
41-
42-
func (v *stackVisitor) After(node Node) {
43-
v.stack[len(v.stack)-1] = nil // set visitor to nil so it can be garbage collected
44-
v.stack = v.stack[:len(v.stack)-1]
45-
}
46-
47-
// A Visitor's before method is invoked for each node encountered by Walk.
48-
// If the result Visitor w is true, Walk visits each of the children
49-
// of node with the Visitor w, followed by a call of w.After.
50-
type Visitor interface {
51-
Before(node Node) (w Visitor)
52-
After(node Node)
53-
}
54-
5521
func walkList[N Node](list []N, before func(Node) bool, after func(Node)) {
5622
for _, node := range list {
5723
Walk(node, before, after)

0 commit comments

Comments
 (0)