@@ -98,12 +98,23 @@ open class SyntaxVisitor {
9898 public init ( ) { }
9999% for node in SYNTAX_NODES:
100100% if is_visitable ( node) :
101- open func visit( _ node: ${ node. name} ) {
102- visitChildren ( node )
101+ open func visit( _ node: ${ node. name} ) -> Bool {
102+ return true
103103 }
104104% end
105105% end
106106
107+ open func visit( _ node: UnknownSyntax ) -> Bool {
108+ return true
109+ }
110+
111+ open func shouldVisit( _ kind: SyntaxKind ) -> Bool {
112+ return true
113+ }
114+ open func shouldVisit( _ kind: TokenKind ) -> Bool {
115+ return true
116+ }
117+
107118 open func visit( _ token: TokenSyntax ) { }
108119
109120 /// The function called before visiting the node and its descendents.
@@ -114,21 +125,109 @@ open class SyntaxVisitor {
114125 /// - node: the node we just finished visiting.
115126 open func visitPost( _ node: Syntax ) { }
116127
117- public func visit( _ node: Syntax ) {
118- visitPre ( node)
119- defer { visitPost ( node) }
128+ public func visit( _ node: Syntax ) -> Bool {
120129 switch node. raw. kind {
121130 case . token: visit ( node as! TokenSyntax )
122131% for node in SYNTAX_NODES:
123132% if is_visitable ( node) :
124- case . ${ node. swift_syntax_kind} : visit ( node as! ${ node. name} )
133+ case . ${ node. swift_syntax_kind} : return visit ( node as! ${ node. name} )
125134% end
126135% end
127- default : visitChildren ( node)
136+ case . unknown: return visit ( node as! UnknownSyntax )
137+ default : break
128138 }
139+ return false
129140 }
141+ }
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+
182+ /// The raw syntax walker traverses the raw syntax tree to find
183+ /// node kinds the SyntaxVisitor is interested and feed these syntax nodes to
184+ /// SyntaxVisitor.
185+ /// By traversing the raw syntax tree, we avoid realizing syntax nodes that're
186+ /// not interesting to users' SyntaxVisitor.
187+ class RawSyntaxVisitor {
188+ private let visitor : SyntaxVisitor
189+ private var currentNode : PendingSyntaxNode ?
190+
191+ required init ( _ visitor: SyntaxVisitor , _ root: Syntax ) {
192+ self . visitor = visitor
193+ self . currentNode = PendingSyntaxNode ( root)
194+ }
195+
196+ func shouldVisit( _ kind: SyntaxKind ) -> Bool {
197+ return visitor. shouldVisit ( kind)
198+ }
199+
200+ func shouldVisit( _ kind: TokenKind ) -> Bool {
201+ return visitor. shouldVisit ( kind)
202+ }
203+
204+ func addChildIdx( _ idx: Int ) {
205+ currentNode = PendingSyntaxNode ( currentNode!, idx)
206+ }
207+
208+ func moveUp( ) {
209+ currentNode = currentNode!. parent
210+ }
211+
212+ func visitPre( ) {
213+ visitor. visitPre ( currentNode!. node)
214+ }
215+
216+ func visitPost( ) {
217+ visitor. visitPost ( currentNode!. node)
218+ }
219+
220+ // The current raw syntax node is interesting for the user, so realize a
221+ // correponding syntax node and feed it into the visitor.
222+ func visit( ) -> Bool {
223+ return visitor. visit ( currentNode!. node)
224+ }
225+ }
226+
227+ extension Syntax {
228+ public func walk( _ visitor: SyntaxVisitor ) {
130229
131- func visitChildren ( _ node: Syntax ) {
132- node . children . forEach { visit ( $0 ) }
230+ // Traverse the raw syntax tree by using the current syntax node as root.
231+ data . raw . accept ( RawSyntaxVisitor ( visitor , self ) )
133232 }
134233}
0 commit comments