Skip to content

Commit 4c59d05

Browse files
authored
Merge pull request #2038 from ahoppen/ahoppen/simplify-rewriter
Simplify `SyntaxRewriter` and `SyntaxVisitor`
2 parents 75e68f3 + 74e9a89 commit 4c59d05

File tree

4 files changed

+2810
-7742
lines changed

4 files changed

+2810
-7742
lines changed

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -161,31 +161,24 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
161161
)
162162
}
163163

164-
for node in NON_BASE_SYNTAX_NODES {
165-
DeclSyntax(
166-
"""
167-
/// Implementation detail of visit(_:). Do not call directly.
168-
private func visitImpl\(node.kind.syntaxType)(_ data: SyntaxData) -> Syntax {
169-
let node = \(node.kind.syntaxType)(data)
170-
// Accessing _syntaxNode directly is faster than calling Syntax(node)
171-
visitPre(node._syntaxNode)
172-
defer { visitPost(node._syntaxNode) }
173-
if let newNode = visitAny(node._syntaxNode) { return newNode }
174-
return Syntax(visit(node))
175-
}
176-
"""
177-
)
178-
}
179-
180164
DeclSyntax(
181165
"""
182-
/// Implementation detail of visit(_:). Do not call directly.
183-
private func visitImplTokenSyntax(_ data: SyntaxData) -> Syntax {
184-
let node = TokenSyntax(data)
166+
/// Interpret `data` as a node of type `nodeType`, visit it, calling
167+
/// the `visit` to transform the node.
168+
private func visitImpl<NodeType: SyntaxProtocol>(
169+
_ data: SyntaxData,
170+
_ nodeType: NodeType.Type,
171+
_ visit: (NodeType) -> some SyntaxProtocol
172+
) -> Syntax {
173+
let node = Syntax(data).cast(NodeType.self)
185174
// Accessing _syntaxNode directly is faster than calling Syntax(node)
186175
visitPre(node._syntaxNode)
187-
defer { visitPost(node._syntaxNode) }
188-
if let newNode = visitAny(node._syntaxNode) { return newNode }
176+
defer {
177+
visitPost(node._syntaxNode)
178+
}
179+
if let newNode = visitAny(node._syntaxNode) {
180+
return newNode
181+
}
189182
return Syntax(visit(node))
190183
}
191184
"""
@@ -232,12 +225,12 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
232225
) {
233226
try SwitchExprSyntax("switch data.raw.kind") {
234227
SwitchCaseSyntax("case .token:") {
235-
StmtSyntax("return visitImplTokenSyntax")
228+
StmtSyntax("return { self.visitImpl($0, TokenSyntax.self, self.visit) }")
236229
}
237230

238231
for node in NON_BASE_SYNTAX_NODES {
239232
SwitchCaseSyntax("case .\(node.varOrCaseName):") {
240-
StmtSyntax("return visitImpl\(node.kind.syntaxType)")
233+
StmtSyntax("return { self.visitImpl($0, \(node.kind.syntaxType).self, self.visit) }")
241234
}
242235
}
243236
}
@@ -260,12 +253,12 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
260253
try! FunctionDeclSyntax("private func visit(_ data: SyntaxData) -> Syntax") {
261254
try SwitchExprSyntax("switch data.raw.kind") {
262255
SwitchCaseSyntax("case .token:") {
263-
StmtSyntax("return visitImplTokenSyntax(data)")
256+
StmtSyntax("return visitImpl(data, TokenSyntax.self, visit)")
264257
}
265258

266259
for node in NON_BASE_SYNTAX_NODES {
267260
SwitchCaseSyntax("case .\(node.varOrCaseName):") {
268-
StmtSyntax("return visitImpl\(node.kind.syntaxType)(data)")
261+
StmtSyntax("return visitImpl(data, \(node.kind.syntaxType).self, visit)")
269262
}
270263
}
271264
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxVisitorFile.swift

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,26 @@ let syntaxVisitorFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
9292
"""
9393
)
9494

95-
for node in NON_BASE_SYNTAX_NODES {
96-
DeclSyntax(
97-
"""
98-
/// Implementation detail of doVisit(_:_:). Do not call directly.
99-
private func visitImpl\(node.kind.syntaxType)(_ data: SyntaxData) {
100-
let node = \(node.kind.syntaxType)(data)
101-
let needsChildren = (visit(node) == .visitChildren)
102-
// Avoid calling into visitChildren if possible.
103-
if needsChildren && !node.raw.layoutView!.children.isEmpty {
104-
visitChildren(node)
105-
}
106-
visitPost(node)
95+
DeclSyntax(
96+
"""
97+
/// Interpret `data` as a node of type `nodeType`, visit it, calling
98+
/// the `visit` and `visitPost` functions during visitation.
99+
private func visitImpl<NodeType: SyntaxProtocol>(
100+
_ data: SyntaxData,
101+
_ nodeType: NodeType.Type,
102+
_ visit: (NodeType) -> SyntaxVisitorContinueKind,
103+
_ visitPost: (NodeType) -> Void
104+
) {
105+
let node = NodeType(Syntax(data))!
106+
let needsChildren = (visit(node) == .visitChildren)
107+
// Avoid calling into visitChildren if possible.
108+
if needsChildren && !node.raw.layoutView!.children.isEmpty {
109+
visitChildren(node)
107110
}
108-
"""
109-
)
110-
}
111+
visitPost(node)
112+
}
113+
"""
114+
)
111115

112116
try FunctionDeclSyntax("private func visit(_ data: SyntaxData)") {
113117
try SwitchExprSyntax("switch data.raw.kind") {
@@ -119,17 +123,13 @@ let syntaxVisitorFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
119123
"""
120124
// No children to visit.
121125
visitPost(node)
122-
// The implementation of every generated case goes into its own function. This
123-
// circumvents an issue where the compiler allocates stack space for every
124-
// case statement next to each other in debug builds, causing it to allocate
125-
// ~50KB per call to this function. rdar://55929175
126126
"""
127127
)
128128
}
129129

130130
for node in NON_BASE_SYNTAX_NODES {
131131
SwitchCaseSyntax("case .\(node.varOrCaseName):") {
132-
ExprSyntax("visitImpl\(node.kind.syntaxType)(data)")
132+
ExprSyntax("visitImpl(data, \(node.kind.syntaxType).self, visit, visitPost)")
133133
}
134134
}
135135
}

0 commit comments

Comments
 (0)