Skip to content

Commit 167605e

Browse files
committed
Add documentation for initializers that build a node from a header and a result builder
rdar://108643660
1 parent 8ddbb9a commit 167605e

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

Sources/SwiftSyntaxBuilder/SyntaxNodeWithBody.swift

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ extension SyntaxStringInterpolation {
4040
public protocol HasTrailingCodeBlock {
4141
var body: CodeBlockSyntax { get set }
4242

43+
/// Constructs a syntax node where `header` builds the text of the node before the body in braces and `bodyBuilder` is used to build the node’s body.
44+
///
45+
/// For example the following function has header `while x < 5` and the body will contain an `ExprSyntax` with text `x += 1`.
46+
///
47+
/// ```swift
48+
/// while x < 5 {
49+
/// x += 1
50+
/// }
51+
/// ```
4352
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax) rethrows
4453
}
4554

@@ -71,6 +80,15 @@ extension WhileStmtSyntax: HasTrailingCodeBlock {}
7180
public protocol HasTrailingOptionalCodeBlock {
7281
var body: CodeBlockSyntax? { get set }
7382

83+
/// Constructs a syntax node where `header` builds the text of the node before the body in braces and `bodyBuilder` is used to build the node’s body.
84+
///
85+
/// For example the following function has header `func addOne(_ base: Int) -> Int` and the body will contain an `ExprSyntax` with text `return base + 1`.
86+
///
87+
/// ```swift
88+
/// func addOne(_ base: Int) -> Int {
89+
/// return base + 1
90+
/// }
91+
/// ```
7492
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax) throws
7593
}
7694

@@ -95,6 +113,16 @@ extension InitializerDeclSyntax: HasTrailingOptionalCodeBlock {}
95113
public protocol HasTrailingMemberDeclBlock {
96114
var memberBlock: MemberDeclBlockSyntax { get set }
97115

116+
/// Constructs a syntax node where `header` builds the text of the node before the members in braces and `membersBuilder` is used to list the node’s members.
117+
///
118+
/// For example the following function has header `struct Point` and the body will contain two `DeclSyntax` with text `var x: Int` and `var y: Int`, respecitively.
119+
///
120+
/// ```swift
121+
/// struct Point {
122+
/// var x: Int
123+
/// var y: Int
124+
/// }
125+
/// ```
98126
init(_ header: PartialSyntaxNodeString, @MemberDeclListBuilder membersBuilder: () throws -> MemberDeclListSyntax) throws
99127
}
100128

@@ -121,6 +149,19 @@ extension StructDeclSyntax: HasTrailingMemberDeclBlock {}
121149
// So we cannot conform to `HasTrailingCodeBlock`
122150

123151
public extension IfExprSyntax {
152+
/// Constructs an `if` expression with an optional `else` block.
153+
///
154+
/// `header` specifies the part of the `if` expression before the body’s first brace. For example the following `if` expression has the header `if sunny`
155+
///
156+
/// ```swift
157+
/// if sunny {
158+
/// sunbath()
159+
/// }
160+
/// ```
161+
///
162+
/// If `elseBuilder` is not `nil`, an `else` keyword will automatically be inserted.
163+
///
164+
/// This function takes care of inserting the braces as well.
124165
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax, @CodeBlockItemListBuilder `else` elseBuilder: () throws -> CodeBlockItemListSyntax? = { nil }) throws {
125166
let expr = ExprSyntax("\(header) {}")
126167
guard let ifExpr = expr.as(Self.self) else {
@@ -132,6 +173,30 @@ public extension IfExprSyntax {
132173
self.elseKeyword = elseBody != nil ? .keyword(.else) : nil
133174
}
134175

176+
/// Constructs an `if` expression with a following `else if` clause.
177+
/// This can be used to create longer chains of `if`, `else if` expressions. For example to construct
178+
///
179+
/// ```swift
180+
/// if x == 1 {
181+
/// return "one
182+
/// } else if x == 2 {
183+
/// return "two
184+
/// } else {
185+
/// return "many
186+
/// }
187+
/// ```
188+
///
189+
/// You can use
190+
///
191+
/// ```swift
192+
/// try IfExprSyntax("if x == 1", bodyBuilder: {
193+
/// StmtSyntax(#"return "one""#)
194+
/// }, elseIf: IfExprSyntax("if x == 2", bodyBuilder: {
195+
/// StmtSyntax(#"return "two""#)
196+
/// }, else: {
197+
/// StmtSyntax(#"return "many""#)
198+
/// }))
199+
/// ```
135200
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax, elseIf: IfExprSyntax) throws {
136201
let expr = ExprSyntax("\(header) {}")
137202
guard let ifExpr = expr.as(Self.self) else {
@@ -147,6 +212,9 @@ public extension IfExprSyntax {
147212
// MARK: - SwitchCase
148213

149214
extension SwitchCaseSyntax {
215+
/// Constructs a case item where `header` includes the text between the `case` keyword and the `:` (both inclusive) and `statementsBuilder` can be used to build the statements inside the case item.
216+
///
217+
/// For example, a `default` case has header `default:`.
150218
public init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder statementsBuilder: () throws -> CodeBlockItemListSyntax) rethrows {
151219
self = SwitchCaseSyntax("\(header)")
152220
self.statements = try statementsBuilder()
@@ -158,6 +226,18 @@ extension SwitchCaseSyntax {
158226
// So we cannot conform to `HasTrailingCodeBlock` or `HasTrailingMemberDeclBlock`
159227

160228
public extension SwitchExprSyntax {
229+
/// Constructs an `switch` expression where `header` builds the text before the opening `{` and `casesBuilder` can be used to build the case items.
230+
///
231+
/// For example, the following switch expression hase header `switch direction` and two case items for `up` and `down`
232+
///
233+
/// ```swift
234+
/// switch direction {
235+
/// case .up:
236+
/// goUp()
237+
/// case .down:
238+
/// goDown()
239+
/// }
240+
/// ```
161241
init(_ header: PartialSyntaxNodeString, @SwitchCaseListBuilder casesBuilder: () throws -> SwitchCaseListSyntax = { SwitchCaseListSyntax([]) }) throws {
162242
let expr = ExprSyntax("\(header) {}")
163243
guard let switchExpr = expr.as(Self.self) else {

Tests/SwiftSyntaxBuilderTest/IfStmtTests.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,32 @@ final class IfStmtTests: XCTestCase {
9797
}
9898
"""
9999
),
100+
#line: (
101+
try IfExprSyntax(
102+
"if x == 1",
103+
bodyBuilder: {
104+
StmtSyntax(#"return "one""#)
105+
},
106+
elseIf: IfExprSyntax(
107+
"if x == 2",
108+
bodyBuilder: {
109+
StmtSyntax(#"return "two""#)
110+
},
111+
else: {
112+
StmtSyntax(#"return "many""#)
113+
}
114+
)
115+
),
116+
"""
117+
if x == 1 {
118+
return "one"
119+
} else if x == 2 {
120+
return "two"
121+
} else {
122+
return "many"
123+
}
124+
"""
125+
),
100126
]
101127

102128
for (line, testCase) in testCases {

0 commit comments

Comments
 (0)