Skip to content

Commit e6700a2

Browse files
authored
Merge pull request #2085 from Matejkob/option-syntax-nodes-interpolation
Add `appendInterpolation` with optional syntax nodes
2 parents 6a8fb47 + 2c8a8c9 commit e6700a2

File tree

5 files changed

+48
-7
lines changed

5 files changed

+48
-7
lines changed

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,9 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
217217
let list = ExprListSyntax {
218218
ExprSyntax("layout.initialize(repeating: nil)")
219219
for (index, child) in node.children.enumerated() {
220-
let optionalMark = child.isOptional ? "?" : ""
221-
ExprSyntax("layout[\(raw: index)] = \(child.varOrCaseName.backtickedIfNeeded)\(raw: optionalMark).raw")
220+
let optionalMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil
221+
222+
ExprSyntax("layout[\(raw: index)] = \(child.varOrCaseName.backtickedIfNeeded)\(optionalMark).raw")
222223
.with(\.leadingTrivia, .newline)
223224
}
224225
}
@@ -239,12 +240,12 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
239240

240241
for (index, child) in node.children.enumerated() {
241242
try VariableDeclSyntax("public var \(child.varOrCaseName.backtickedIfNeeded): Raw\(child.buildableType.buildable)") {
242-
let iuoMark = child.isOptional ? "" : "!"
243+
let exclamationMark = child.isOptional ? nil : TokenSyntax.exclamationMarkToken()
243244

244245
if child.syntaxNodeKind == .syntax {
245-
ExprSyntax("layoutView.children[\(raw: index)]\(raw: iuoMark)")
246+
ExprSyntax("layoutView.children[\(raw: index)]\(exclamationMark)")
246247
} else {
247-
ExprSyntax("layoutView.children[\(raw: index)].map(\(child.syntaxNodeKind.rawType).init(raw:))\(raw: iuoMark)")
248+
ExprSyntax("layoutView.children[\(raw: index)].map(\(child.syntaxNodeKind.rawType).init(raw:))\(exclamationMark)")
248249
}
249250
}
250251
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,12 @@ func syntaxNode(emitKind: SyntaxNodeKind) -> SourceFileSyntax {
177177
}
178178
}
179179

180+
let questionMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil
181+
180182
AccessorDeclSyntax(
181183
"""
182184
set(value) {
183-
self = \(node.kind.syntaxType)(data.replacingChild(at: \(raw: index), with: value\(raw: child.isOptional ? "?" : "").data, arena: SyntaxArena()))
185+
self = \(node.kind.syntaxType)(data.replacingChild(at: \(raw: index), with: value\(questionMark).data, arena: SyntaxArena()))
184186
}
185187
"""
186188
)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ let syntaxTraitsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
2626
"""
2727
) {
2828
for child in trait.children {
29+
let questionMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil
30+
2931
DeclSyntax(
3032
"""
3133
\(child.documentation)
32-
var \(child.varOrCaseName): \(child.syntaxNodeKind.syntaxType)\(raw: child.isOptional ? "?" : "") { get set }
34+
var \(child.varOrCaseName): \(child.syntaxNodeKind.syntaxType)\(questionMark) { get set }
3335
"""
3436
)
3537
}

Sources/SwiftSyntaxBuilder/Syntax+StringInterpolation.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ extension SyntaxStringInterpolation: StringInterpolationProtocol {
6363
}
6464

6565
/// Append a syntax node to the interpolation.
66+
///
67+
/// This method accepts a syntax node and appends it to the interpolation.
68+
/// If there was a previous indentation value, the method will indent the
69+
/// syntax node with that value. If not, it will use the syntax node as-is.
70+
///
71+
/// - Parameter node: A syntax node that conforms to `SyntaxProtocol`.
6672
public mutating func appendInterpolation<Node: SyntaxProtocol>(
6773
_ node: Node
6874
) {
@@ -84,6 +90,20 @@ extension SyntaxStringInterpolation: StringInterpolationProtocol {
8490
self.lastIndentation = nil
8591
}
8692

93+
/// Append an optional syntax node to the interpolation.
94+
///
95+
/// This method accepts an optional syntax node and appends it to the interpolation
96+
/// if it exists. If the syntax node is nil, this method does nothing.
97+
///
98+
/// - Parameter node: An optional syntax node that conforms to `SyntaxProtocol`.
99+
public mutating func appendInterpolation<Node: SyntaxProtocol>(
100+
_ node: Node?
101+
) {
102+
if let node {
103+
appendInterpolation(node)
104+
}
105+
}
106+
87107
public mutating func appendInterpolation<T>(raw value: T) {
88108
sourceText.append(contentsOf: String(describing: value).utf8)
89109
self.lastIndentation = nil

Tests/SwiftSyntaxBuilderTest/StringInterpolationTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ final class StringInterpolationTests: XCTestCase {
7272
)
7373
}
7474

75+
func testOptionalInterpolationWithNil() {
76+
let tokenSyntax: TokenSyntax? = nil
77+
78+
let funcSyntax: DeclSyntax = "func foo\(tokenSyntax)()"
79+
XCTAssertTrue(funcSyntax.is(FunctionDeclSyntax.self))
80+
XCTAssertEqual(funcSyntax.description, "func foo()")
81+
}
82+
83+
func testOptionalInterpolationWithValue() {
84+
let tokenSyntax: TokenSyntax? = .identifier("Bar")
85+
86+
let funcSyntax: DeclSyntax = "func foo\(tokenSyntax)()"
87+
XCTAssertTrue(funcSyntax.is(FunctionDeclSyntax.self))
88+
XCTAssertEqual(funcSyntax.description, "func fooBar()")
89+
}
90+
7591
func testPatternInterpolation() {
7692
let letPattern: PatternSyntax = "let x"
7793
XCTAssertTrue(letPattern.is(ValueBindingPatternSyntax.self))

0 commit comments

Comments
 (0)