@@ -140,24 +140,57 @@ open class SyntaxVisitor {
140
140
}
141
141
}
142
142
143
+
144
+ /// A wrapper over Syntax. A syntax node is only realized when explicitly asked;
145
+ /// otherwise the node is represented as a child index list from a realized
146
+ /// ancestor.
147
+ class PendingSyntaxNode {
148
+ let parent : PendingSyntaxNode ?
149
+ private var kind : PendingSyntaxNodeKind
150
+
151
+ private enum PendingSyntaxNodeKind {
152
+ /// We already have a `Syntax` node realised for this node
153
+ case realized( node: Syntax )
154
+ /// This node does not have a `Syntax` node instantiated yet. If needed, we
155
+ /// need to compute it from its parent RawSyntax node
156
+ case virtual( index: Int )
157
+ }
158
+
159
+ var node : Syntax {
160
+ switch kind {
161
+ case . realized( let node) :
162
+ return node
163
+ case . virtual( let index) :
164
+ let _node = parent!. node. child ( at: index) !
165
+ kind = . realized( node: _node)
166
+ return _node
167
+ }
168
+ }
169
+
170
+ init ( _ root: Syntax ) {
171
+ self . parent = nil
172
+ self . kind = . realized( node: root)
173
+ }
174
+
175
+ init ( _ parent: PendingSyntaxNode , _ idx: Int ) {
176
+ self . parent = parent
177
+ self . kind = . virtual( index: idx)
178
+ }
179
+ }
180
+
181
+
143
182
/// The raw syntax walker traverses the raw syntax tree to find
144
183
/// node kinds the SyntaxVisitor is interested and feed these syntax nodes to
145
184
/// SyntaxVisitor.
146
185
/// By traversing the raw syntax tree, we avoid realizing syntax nodes that're
147
186
/// not interesting to users' SyntaxVisitor.
148
187
class RawSyntaxVisitor {
149
188
private let visitor : SyntaxVisitor
150
- private var childIdxChain : [ Int ]
151
- private var nodeChain : [ Syntax ]
189
+ private var currentNode : PendingSyntaxNode ?
152
190
153
191
required init ( _ visitor: SyntaxVisitor , _ root: Syntax ) {
154
192
self . visitor = visitor
155
- self . nodeChain = [ root]
156
- self . childIdxChain = [ ]
157
- }
158
-
159
- convenience init ( _ another: RawSyntaxVisitor , _ root: Syntax ) {
160
- self . init ( another. visitor, root)
193
+ self . currentNode = PendingSyntaxNode ( root)
161
194
}
162
195
163
196
func shouldVisit( _ kind: SyntaxKind ) -> Bool {
@@ -169,31 +202,25 @@ class RawSyntaxVisitor {
169
202
}
170
203
171
204
func addChildIdx( _ idx: Int ) {
172
- childIdxChain . append ( idx)
205
+ currentNode = PendingSyntaxNode ( currentNode! , idx)
173
206
}
174
207
175
208
func moveUp( ) {
176
- if childIdxChain . isEmpty {
177
- nodeChain . removeLast ( )
178
- } else {
179
- childIdxChain . removeLast ( )
180
- }
209
+ currentNode = currentNode! . parent
210
+ }
211
+
212
+ func visitPre ( ) {
213
+ visitor . visitPre ( currentNode! . node )
181
214
}
182
215
183
216
func visitPost( ) {
184
- visitor. visitPost ( nodeChain . last! )
217
+ visitor. visitPost ( currentNode! . node )
185
218
}
186
219
187
220
// The current raw syntax node is interesting for the user, so realize a
188
221
// correponding syntax node and feed it into the visitor.
189
- func visitCurrent( ) -> Bool {
190
- for id in childIdxChain {
191
- nodeChain. append ( nodeChain. last!. child ( at: id) !)
192
- }
193
- childIdxChain. removeAll ( keepingCapacity: true )
194
- let node = nodeChain. last!
195
- visitor. visitPre ( node)
196
- return visitor. visit ( node)
222
+ func visit( ) -> Bool {
223
+ return visitor. visit ( currentNode!. node)
197
224
}
198
225
}
199
226
0 commit comments