Skip to content

Add appendInterpolation with optional syntax nodes #2085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,9 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
let list = ExprListSyntax {
ExprSyntax("layout.initialize(repeating: nil)")
for (index, child) in node.children.enumerated() {
let optionalMark = child.isOptional ? "?" : ""
ExprSyntax("layout[\(raw: index)] = \(child.varOrCaseName.backtickedIfNeeded)\(raw: optionalMark).raw")
let optionalMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil

ExprSyntax("layout[\(raw: index)] = \(child.varOrCaseName.backtickedIfNeeded)\(optionalMark).raw")
.with(\.leadingTrivia, .newline)
}
}
Expand All @@ -239,12 +240,12 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {

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

if child.syntaxNodeKind == .syntax {
ExprSyntax("layoutView.children[\(raw: index)]\(raw: iuoMark)")
ExprSyntax("layoutView.children[\(raw: index)]\(exclamationMark)")
} else {
ExprSyntax("layoutView.children[\(raw: index)].map(\(child.syntaxNodeKind.rawType).init(raw:))\(raw: iuoMark)")
ExprSyntax("layoutView.children[\(raw: index)].map(\(child.syntaxNodeKind.rawType).init(raw:))\(exclamationMark)")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,12 @@ func syntaxNode(emitKind: SyntaxNodeKind) -> SourceFileSyntax {
}
}

let questionMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil

AccessorDeclSyntax(
"""
set(value) {
self = \(node.kind.syntaxType)(data.replacingChild(at: \(raw: index), with: value\(raw: child.isOptional ? "?" : "").data, arena: SyntaxArena()))
self = \(node.kind.syntaxType)(data.replacingChild(at: \(raw: index), with: value\(questionMark).data, arena: SyntaxArena()))
}
"""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ let syntaxTraitsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
"""
) {
for child in trait.children {
let questionMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil

DeclSyntax(
"""
\(child.documentation)
var \(child.varOrCaseName): \(child.syntaxNodeKind.syntaxType)\(raw: child.isOptional ? "?" : "") { get set }
var \(child.varOrCaseName): \(child.syntaxNodeKind.syntaxType)\(questionMark) { get set }
"""
)
}
Expand Down
20 changes: 20 additions & 0 deletions Sources/SwiftSyntaxBuilder/Syntax+StringInterpolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ extension SyntaxStringInterpolation: StringInterpolationProtocol {
}

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

/// Append an optional syntax node to the interpolation.
///
/// This method accepts an optional syntax node and appends it to the interpolation
/// if it exists. If the syntax node is nil, this method does nothing.
///
/// - Parameter node: An optional syntax node that conforms to `SyntaxProtocol`.
public mutating func appendInterpolation<Node: SyntaxProtocol>(
_ node: Node?
) {
if let node {
appendInterpolation(node)
}
}

public mutating func appendInterpolation<T>(raw value: T) {
sourceText.append(contentsOf: String(describing: value).utf8)
self.lastIndentation = nil
Expand Down
16 changes: 16 additions & 0 deletions Tests/SwiftSyntaxBuilderTest/StringInterpolationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ final class StringInterpolationTests: XCTestCase {
)
}

func testOptionalInterpolationWithNil() {
let tokenSyntax: TokenSyntax? = nil

let funcSyntax: DeclSyntax = "func foo\(tokenSyntax)()"
XCTAssertTrue(funcSyntax.is(FunctionDeclSyntax.self))
XCTAssertEqual(funcSyntax.description, "func foo()")
}

func testOptionalInterpolationWithValue() {
let tokenSyntax: TokenSyntax? = .identifier("Bar")

let funcSyntax: DeclSyntax = "func foo\(tokenSyntax)()"
XCTAssertTrue(funcSyntax.is(FunctionDeclSyntax.self))
XCTAssertEqual(funcSyntax.description, "func fooBar()")
}

func testPatternInterpolation() {
let letPattern: PatternSyntax = "let x"
XCTAssertTrue(letPattern.is(ValueBindingPatternSyntax.self))
Expand Down