Skip to content

Commit a234047

Browse files
davidklassenantonmedv
authored andcommitted
Add Node method to Visitor interface to allow to patch ast tree
1 parent eea41bc commit a234047

File tree

5 files changed

+60
-28
lines changed

5 files changed

+60
-28
lines changed

ast/base_visitor.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ func (BaseVisitor) ArrayNode(node *ArrayNode) {}
4141
func (BaseVisitor) MapNode(node *MapNode) {}
4242

4343
func (BaseVisitor) PairNode(node *PairNode) {}
44+
45+
func (BaseVisitor) Node(node *Node) {}

ast/visitor.go

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,24 @@ type Visitor interface {
2323
ArrayNode(node *ArrayNode)
2424
MapNode(node *MapNode)
2525
PairNode(node *PairNode)
26+
Node(node *Node)
2627
}
2728

2829
type walker struct {
2930
visitor Visitor
3031
}
3132

32-
func Walk(node Node, visitor Visitor) {
33+
func Walk(node *Node, visitor Visitor) {
3334
w := walker{
3435
visitor: visitor,
3536
}
3637
w.walk(node)
3738
}
3839

39-
func (w *walker) walk(node Node) {
40-
switch n := node.(type) {
40+
func (w *walker) walk(node *Node) {
41+
w.visitor.Node(node)
42+
43+
switch n := (*node).(type) {
4144
case *NilNode:
4245
w.visitor.NilNode(n)
4346
case *IdentifierNode:
@@ -51,61 +54,62 @@ func (w *walker) walk(node Node) {
5154
case *StringNode:
5255
w.visitor.StringNode(n)
5356
case *UnaryNode:
54-
w.walk(n.Node)
57+
w.walk(&n.Node)
5558
w.visitor.UnaryNode(n)
5659
case *BinaryNode:
57-
w.walk(n.Left)
58-
w.walk(n.Right)
60+
w.walk(&n.Left)
61+
w.walk(&n.Right)
5962
w.visitor.BinaryNode(n)
6063
case *MatchesNode:
61-
w.walk(n.Left)
62-
w.walk(n.Right)
64+
w.walk(&n.Left)
65+
w.walk(&n.Right)
6366
w.visitor.MatchesNode(n)
6467
case *PropertyNode:
65-
w.walk(n.Node)
68+
w.walk(&n.Node)
6669
w.visitor.PropertyNode(n)
6770
case *IndexNode:
68-
w.walk(n.Node)
69-
w.walk(n.Index)
71+
w.walk(&n.Node)
72+
w.walk(&n.Index)
7073
w.visitor.IndexNode(n)
7174
case *MethodNode:
72-
w.walk(n.Node)
75+
w.walk(&n.Node)
7376
for _, arg := range n.Arguments {
74-
w.walk(arg)
77+
w.walk(&arg)
7578
}
7679
w.visitor.MethodNode(n)
7780
case *FunctionNode:
7881
for _, arg := range n.Arguments {
79-
w.walk(arg)
82+
w.walk(&arg)
8083
}
8184
w.visitor.FunctionNode(n)
8285
case *BuiltinNode:
8386
for _, arg := range n.Arguments {
84-
w.walk(arg)
87+
w.walk(&arg)
8588
}
8689
w.visitor.BuiltinNode(n)
8790
case *ClosureNode:
88-
w.walk(n.Node)
91+
w.walk(&n.Node)
8992
w.visitor.ClosureNode(n)
9093
case *PointerNode:
9194
w.visitor.PointerNode(n)
9295
case *ConditionalNode:
93-
w.walk(n.Cond)
94-
w.walk(n.Exp1)
95-
w.walk(n.Exp2)
96+
w.walk(&n.Cond)
97+
w.walk(&n.Exp1)
98+
w.walk(&n.Exp2)
9699
w.visitor.ConditionalNode(n)
97100
case *ArrayNode:
98101
for _, node := range n.Nodes {
99-
w.walk(node)
102+
w.walk(&node)
100103
}
101104
w.visitor.ArrayNode(n)
102105
case *MapNode:
103-
for _, pair := range n.Pairs {
104-
w.walk(pair)
106+
var pair Node
107+
for _, pair = range n.Pairs {
108+
w.walk(&pair)
105109
}
106110
w.visitor.MapNode(n)
107111
case *PairNode:
108-
w.walk(n.Value)
112+
w.walk(&n.Value)
109113
w.visitor.PairNode(n)
110114
default:
111115
panic(fmt.Sprintf("undefined node type (%T)", node))

ast/visitor_test.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,38 @@ func (v *visitor) IdentifierNode(node *ast.IdentifierNode) {
1616
}
1717

1818
func TestWalk(t *testing.T) {
19-
node := &ast.BinaryNode{
19+
var node ast.Node
20+
node = &ast.BinaryNode{
2021
Operator: "+",
2122
Left: &ast.IdentifierNode{Value: "foo"},
2223
Right: &ast.IdentifierNode{Value: "bar"},
2324
}
2425

2526
visitor := &visitor{}
26-
ast.Walk(node, visitor)
27+
ast.Walk(&node, visitor)
2728
assert.Equal(t, []string{"foo", "bar"}, visitor.identifiers)
2829
}
30+
31+
type patcher struct {
32+
ast.BaseVisitor
33+
}
34+
35+
func (p *patcher) Node(node *ast.Node) {
36+
if _, ok := (*node).(*ast.IdentifierNode); ok {
37+
*node = &ast.NilNode{}
38+
}
39+
}
40+
41+
func TestWalk_patch(t *testing.T) {
42+
var node ast.Node
43+
node = &ast.BinaryNode{
44+
Operator: "+",
45+
Left: &ast.IdentifierNode{Value: "foo"},
46+
Right: &ast.IdentifierNode{Value: "bar"},
47+
}
48+
49+
patcher := &patcher{}
50+
ast.Walk(&node, patcher)
51+
assert.IsType(t, &ast.NilNode{}, node.(*ast.BinaryNode).Left)
52+
assert.IsType(t, &ast.NilNode{}, node.(*ast.BinaryNode).Right)
53+
}

checker/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func (v setVisitor) IntegerNode(node *ast.IntegerNode) {
281281
}
282282

283283
func setUncertainType(node ast.Node, t reflect.Type) {
284-
ast.Walk(node, setVisitor{t: dereference(t)})
284+
ast.Walk(&node, setVisitor{t: dereference(t)})
285285
}
286286

287287
type hasVisitor struct {
@@ -295,6 +295,6 @@ func (v *hasVisitor) IntegerNode(node *ast.IntegerNode) {
295295

296296
func isCertain(node ast.Node) bool {
297297
v := &hasVisitor{certain: true}
298-
ast.Walk(node, v)
298+
ast.Walk(&node, v)
299299
return v.certain
300300
}

cmd/ecc/dot.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ const format = `digraph {
1818

1919
func dotAst(node Node) {
2020
v := &visitor{}
21-
Walk(node, v)
21+
Walk(&node, v)
2222
dot := fmt.Sprintf(format, v.nodes, v.links)
2323
_, _ = fmt.Fprintf(os.Stdout, dot)
2424
}
2525

2626
type visitor struct {
27+
BaseVisitor
2728
nodes string
2829
links string
2930
index int

0 commit comments

Comments
 (0)