@@ -98,12 +98,17 @@ open class SyntaxVisitor {
98
98
public init ( ) { }
99
99
% for node in SYNTAX_NODES:
100
100
% if is_visitable ( node) :
101
- open func visit( _ node: ${ node. name} ) {
102
- visitChildren ( node)
103
- }
101
+ open func visit( _ node: ${ node. name} ) { }
104
102
% end
105
103
% end
106
104
105
+ open func shouldVisit( _ kind: SyntaxKind ) -> Bool {
106
+ return true
107
+ }
108
+ open func shouldVisit( _ kind: TokenKind ) -> Bool {
109
+ return true
110
+ }
111
+
107
112
open func visit( _ token: TokenSyntax ) { }
108
113
109
114
/// The function called before visiting the node and its descendents.
@@ -115,20 +120,79 @@ open class SyntaxVisitor {
115
120
open func visitPost( _ node: Syntax ) { }
116
121
117
122
public func visit( _ node: Syntax ) {
118
- visitPre ( node)
119
- defer { visitPost ( node) }
120
123
switch node. raw. kind {
121
124
case . token: visit ( node as! TokenSyntax )
122
125
% for node in SYNTAX_NODES:
123
126
% if is_visitable ( node) :
124
127
case . ${ node. swift_syntax_kind} : visit ( node as! ${ node. name} )
125
128
% end
126
129
% end
127
- default : visitChildren ( node )
130
+ default : return
128
131
}
129
132
}
133
+ }
134
+
135
+ /// The raw syntax walker traverses the raw syntax tree to find
136
+ /// node kinds the SyntaxVisitor is interested and feed these syntax nodes to
137
+ /// SyntaxVisitor.
138
+ /// By traversing the raw syntax tree, we avoid realizing syntax nodes that're
139
+ /// not interesting to users' SyntaxVisitor.
140
+ class RawSyntaxVisitor {
141
+ private let visitor : SyntaxVisitor
142
+ private var childIdxChain : [ Int ]
143
+ private var nodeChain : [ Syntax ]
144
+
145
+ required init ( _ visitor: SyntaxVisitor , _ root: Syntax ) {
146
+ self . visitor = visitor
147
+ self . nodeChain = [ root]
148
+ self . childIdxChain = [ ]
149
+ }
150
+
151
+ convenience init ( _ another: RawSyntaxVisitor , _ root: Syntax ) {
152
+ self . init ( another. visitor, root)
153
+ }
154
+
155
+ func shouldVisit( _ kind: SyntaxKind ) -> Bool {
156
+ return visitor. shouldVisit ( kind)
157
+ }
158
+
159
+ func shouldVisit( _ kind: TokenKind ) -> Bool {
160
+ return visitor. shouldVisit ( kind)
161
+ }
162
+
163
+ func addChildIdx( _ idx: Int ) {
164
+ childIdxChain. append ( idx)
165
+ }
166
+
167
+ func moveUp( ) {
168
+ if childIdxChain. isEmpty {
169
+ nodeChain. removeLast ( )
170
+ } else {
171
+ childIdxChain. removeLast ( )
172
+ }
173
+ }
174
+
175
+ func visitPost( ) {
176
+ visitor. visitPost ( nodeChain. last!)
177
+ }
178
+
179
+ // The current raw syntax node is interesting for the user, so realize a
180
+ // correponding syntax node and feed it into the visitor.
181
+ func visitCurrent( ) {
182
+ for id in childIdxChain {
183
+ nodeChain. append ( nodeChain. last!. child ( at: id) !)
184
+ }
185
+ childIdxChain. removeAll ( keepingCapacity: true )
186
+ let node = nodeChain. last!
187
+ visitor. visitPre ( node)
188
+ visitor. visit ( node)
189
+ }
190
+ }
191
+
192
+ extension Syntax {
193
+ public func walk( _ visitor: SyntaxVisitor ) {
130
194
131
- func visitChildren ( _ node: Syntax ) {
132
- node . children . forEach { visit ( $0 ) }
195
+ // Traverse the raw syntax tree by using the current syntax node as root.
196
+ data . raw . accept ( RawSyntaxVisitor ( visitor , self ) )
133
197
}
134
198
}
0 commit comments