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