Skip to content

Commit bdfa6cd

Browse files
[SwiftSyntax] Add SyntaxRewriter.visitAny(_:) (#15212)
* [SwiftSyntax] Add SyntaxRewriter.visitAny(_:) This function, when overridden, allows Syntax rewriters to perform custom dynamic visitation behavior. If a user wanted to, say, store a series of transformations accessible by metatype, they can override visitAny and do their own runtime dispatch. If a non-nil result is returned from visitAny, the original specialized visitors are skipped.
1 parent 3eecb49 commit bdfa6cd

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
n

test/SwiftSyntax/VisitorTest.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,28 @@ VisitorTests.test("RewritingNodeWithEmptyChild") {
5353
})
5454
}
5555

56+
VisitorTests.test("SyntaxRewriter.visitAny") {
57+
class VisitAnyRewriter: SyntaxRewriter {
58+
let transform: (TokenSyntax) -> TokenSyntax
59+
init(transform: @escaping (TokenSyntax) -> TokenSyntax) {
60+
self.transform = transform
61+
}
62+
override func visitAny(_ node: Syntax) -> Syntax? {
63+
if let tok = node as? TokenSyntax {
64+
return transform(tok)
65+
}
66+
return nil
67+
}
68+
}
69+
expectDoesNotThrow({
70+
let parsed = try SourceFileSyntax.decodeSourceFileSyntax(try
71+
SwiftLang.parse(getInput("near-empty.swift")))
72+
let rewriter = VisitAnyRewriter(transform: { _ in
73+
return SyntaxFactory.makeIdentifier("")
74+
})
75+
let rewritten = rewriter.visit(parsed)
76+
expectEqual(rewritten.description, "")
77+
})
78+
}
79+
5680
runAllTests()

tools/SwiftSyntax/SyntaxRewriter.swift.gyb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,28 @@ open class SyntaxRewriter {
4545
/// - node: the node we are about to visit.
4646
open func visitPre(_ node: Syntax) {}
4747

48+
/// Override point to choose custom visitation dispatch instead of the
49+
/// specialized `visit(_:)` methods. Use this instead of those methods if
50+
/// you intend to dynamically dispatch rewriting behavior.
51+
/// - note: If this method returns a non-nil result, the specialized
52+
/// `visit(_:)` methods will not be called for this node.
53+
open func visitAny(_ node: Syntax) -> Syntax? {
54+
return nil
55+
}
56+
4857
/// The function called after visting the node and its descendents.
4958
/// - node: the node we just finished visiting.
5059
open func visitPost(_ node: Syntax) {}
5160

5261
public func visit(_ node: Syntax) -> Syntax {
5362
visitPre(node)
5463
defer { visitPost(node) }
64+
65+
// If the global visitor returned non-nil, skip specialized dispatch.
66+
if let newNode = visitAny(node) {
67+
return newNode
68+
}
69+
5570
switch node.raw.kind {
5671
case .token: return visit(node as! TokenSyntax)
5772
% for node in SYNTAX_NODES:

0 commit comments

Comments
 (0)