Skip to content

Commit 1e78668

Browse files
committed
Use parser integration of SwiftSyntaxBuilder in Code Generation
1 parent 108a098 commit 1e78668

File tree

15 files changed

+2122
-3027
lines changed

15 files changed

+2122
-3027
lines changed

CodeGeneration/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ let package = Package(
1212
.executable(name: "generate-swiftsyntaxbuilder", targets: ["generate-swiftsyntaxbuilder"]),
1313
],
1414
dependencies: [
15-
.package(url: "https://github.com/apple/swift-syntax.git", revision: "dcd692d759e09730098e45ba7276d0d96d004bac"),
15+
.package(url: "https://github.com/apple/swift-syntax.git", revision: "108a09851eb34b855bd0f9ff3e52ea396b531b58"),
1616
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.1.4")),
1717
],
1818
targets: [

CodeGeneration/Sources/Utils/GenerateTemplates.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import Foundation
1414
import SwiftSyntaxBuilder
15+
import SwiftBasicFormat
1516

1617
public func generateTemplates(templates: [(SourceFile, String)], destination: URL, verbose: Bool) throws {
1718
let format = Format(indentWidth: 2)

CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public extension Child {
3737
/// represents this child node.
3838
func generateExprBuildSyntaxNode(varName: ExpressibleAsExprBuildable, formatName: String) -> ExpressibleAsExprBuildable {
3939
if type.isToken {
40-
return FunctionCallExpr(MemberAccessExpr(base: type.optionalChained(expr: varName), name: "buildToken")) {
40+
return FunctionCallExpr(calledExpression: MemberAccessExpr(base: type.optionalChained(expr: varName), name: "buildToken")) {
4141
TupleExprElement(label: "format", expression: "format")
4242
}
4343
} else {
@@ -46,7 +46,7 @@ public extension Child {
4646
format = MemberAccessExpr(base: format, name: "_indented")
4747
}
4848
let expr = type.optionalChained(expr: varName)
49-
return FunctionCallExpr(MemberAccessExpr(base: expr, name: "build\(type.baseName)")) {
49+
return FunctionCallExpr(calledExpression: MemberAccessExpr(base: expr, name: "build\(type.baseName)")) {
5050
TupleExprElement(label: "format", expression: format)
5151
}
5252
}
@@ -88,7 +88,7 @@ public extension Child {
8888
})
8989
}
9090
let disjunction = ExprList(assertChoices.flatMap { [$0, BinaryOperatorExpr("||")] }.dropLast())
91-
return FunctionCallExpr("assert") {
91+
return FunctionCallExpr(calledExpression: "assert") {
9292
SequenceExpr(elements: disjunction)
9393
}
9494
}

CodeGeneration/Sources/Utils/SyntaxBuildableType.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ public struct SyntaxBuildableType: Hashable {
7575
/// - For base kinds: `<BaseKind>Buildable`, e.g. `ExprBuildable` (these are implemented as protocols)
7676
/// - For token: `TokenSyntax` (tokens don't have a dedicated type in SwiftSyntaxBuilder)
7777
/// If the type is optional, the type is wrapped in an `OptionalType`.
78-
public var buildable: ExpressibleAsTypeBuildable {
79-
optionalWrapped(type: buildableBaseName)
78+
public var buildable: TypeBuildable {
79+
optionalWrapped(type: buildableBaseName).createTypeBuildable()
8080
}
8181

8282
/// Whether parameters of this type should be initializable by a result builder.
@@ -119,7 +119,7 @@ public struct SyntaxBuildableType: Hashable {
119119
/// The `ExpressibleAs*` Swift type for this syntax kind. Tokens don't
120120
/// have an `ExpressibleAs*` type, so for those this method just returns
121121
/// `TokenSyntax`. If the type is optional, this terminates with a `?`.
122-
public var expressibleAs: ExpressibleAsTypeBuildable {
122+
public var expressibleAs: TypeBuildable {
123123
optionalWrapped(type: expressibleAsBaseName)
124124
}
125125

@@ -136,7 +136,7 @@ public struct SyntaxBuildableType: Hashable {
136136
/// The corresponding `*Syntax` type defined in the `SwiftSyntax` module,
137137
/// which will eventually get built from `SwiftSyntaxBuilder`. If the type
138138
/// is optional, this terminates with a `?`.
139-
public var syntax: ExpressibleAsTypeBuildable {
139+
public var syntax: TypeBuildable {
140140
optionalWrapped(type: syntaxBaseName)
141141
}
142142

@@ -148,7 +148,7 @@ public struct SyntaxBuildableType: Hashable {
148148
}
149149

150150
/// Assuming that this is a base kind, return the corresponding `*ListBuildable` type.
151-
public var listBuildable: ExpressibleAsTypeBuildable {
151+
public var listBuildable: TypeBuildable {
152152
optionalWrapped(type: listBuildableBaseName)
153153
}
154154

@@ -237,11 +237,11 @@ public struct SyntaxBuildableType: Hashable {
237237
}
238238

239239
/// Wraps a type in an optional depending on whether `isOptional` is true.
240-
public func optionalWrapped(type: ExpressibleAsTypeBuildable) -> ExpressibleAsTypeBuildable {
240+
public func optionalWrapped(type: ExpressibleAsTypeBuildable) -> TypeBuildable {
241241
if isOptional {
242242
return OptionalType(wrappedType: type)
243243
} else {
244-
return type
244+
return type.createTypeBuildable()
245245
}
246246
}
247247

@@ -269,7 +269,7 @@ public struct SyntaxBuildableType: Hashable {
269269
if isToken {
270270
return varName
271271
} else {
272-
return FunctionCallExpr(MemberAccessExpr(base: optionalChained(expr: varName), name: "create\(buildableBaseName)"))
272+
return FunctionCallExpr(calledExpression: MemberAccessExpr(base: optionalChained(expr: varName), name: "create\(buildableBaseName)"))
273273
}
274274
}
275275
}

CodeGeneration/Sources/generate-swiftbasicformat/FormatFile.swift

Lines changed: 48 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -23,90 +23,45 @@ let formatFile = SourceFile {
2323
)
2424

2525
StructDecl(modifiers: [Token.public], identifier: "Format") {
26-
VariableDecl(
27-
modifiers: [Token.public],
28-
.let,
29-
name: "indentWidth",
30-
type: "Int"
31-
)
26+
VariableDecl("public let indentWidth: Int")
3227

33-
VariableDecl(
34-
modifiers: [Token.private],
35-
.var,
36-
name: "indents",
37-
type: "Int",
38-
initializer: IntegerLiteralExpr(0)
39-
)
28+
VariableDecl("private var indents: Int = 0")
4029

4130
InitializerDecl(
42-
modifiers: [Token.public],
43-
signature: FunctionSignature(
44-
input: ParameterClause {
45-
FunctionParameter(
46-
firstName: .identifier("indentWidth"),
47-
colon: .colon,
48-
type: "Int",
49-
defaultArgument: IntegerLiteralExpr(4)
50-
)
51-
}
52-
)
53-
) {
54-
SequenceExpr {
55-
MemberAccessExpr(base: "self", name: "indentWidth")
56-
AssignmentExpr()
57-
"indentWidth"
31+
"""
32+
public init(indentWidth: Int = 4) {
33+
self.indentWidth = indentWidth
5834
}
59-
}
35+
"""
36+
)
6037
}
6138

6239
ExtensionDecl(extendedType: "Format") {
6340
VariableDecl(
64-
modifiers: [Token.public],
65-
name: "_indented",
66-
type: "Self"
67-
) {
68-
VariableDecl(.var, name: "copy", initializer: "self")
69-
SequenceExpr {
70-
MemberAccessExpr(base: "copy", name: "indents")
71-
BinaryOperatorExpr("+=")
72-
IntegerLiteralExpr(1)
41+
"""
42+
public var _indented: Self {
43+
var copy = self
44+
copy.indents += 1
45+
return copy
7346
}
74-
ReturnStmt(expression: "copy")
75-
}
47+
"""
48+
)
7649

7750
VariableDecl(
78-
modifiers: [Token.public],
79-
name: "indentTrivia",
80-
type: "Trivia"
81-
) {
82-
TernaryExpr(
83-
if: SequenceExpr {
84-
"indents"
85-
BinaryOperatorExpr("==")
86-
IntegerLiteralExpr(0)
87-
},
88-
then: MemberAccessExpr(name: "zero"),
89-
else: FunctionCallExpr(MemberAccessExpr(name: "spaces")) {
90-
TupleExprElement(expression: SequenceExpr {
91-
"indents"
92-
BinaryOperatorExpr("*")
93-
"indentWidth"
94-
})
95-
}
96-
)
97-
}
51+
"""
52+
public var indentTrivia: Trivia {
53+
indents == 0 ? .zero : .spaces(indents * indentWidth)
54+
}
55+
"""
56+
)
9857

9958
VariableDecl(
100-
modifiers: [Token.private],
101-
name: "indentedNewline",
102-
type: "Trivia"
103-
) {
104-
SequenceExpr {
105-
MemberAccessExpr(name: "newline")
106-
BinaryOperatorExpr("+")
107-
"indentTrivia"
59+
"""
60+
private var indentedNewline: Trivia {
61+
.newline + indentTrivia
10862
}
109-
}
63+
"""
64+
)
11065
}
11166

11267
ExtensionDecl(extendedType: "Format") {
@@ -136,57 +91,22 @@ private func createFormatFunctionSignature(type: SyntaxBuildableType) -> Functio
13691

13792
/// Generate the format implementation for a buildable node.
13893
private func createBuildableNodeFormatFunction(node: Node) -> FunctionDecl {
139-
FunctionDecl(
140-
modifiers: Token.public,
141-
identifier: .identifier("format"),
142-
signature: createFormatFunctionSignature(type: node.type)
143-
) {
144-
VariableDecl(
145-
.var,
146-
name: "result",
147-
initializer: node.children
148-
.filter(\.requiresLeadingNewline)
149-
.reduce("syntax") { base, child in
150-
FunctionCallExpr(MemberAccessExpr(base: base, name: "with\(child.name)")) {
151-
let childExpr = MemberAccessExpr(base: "syntax", name: child.swiftName)
152-
TupleExprElement(expression: FunctionCallExpr(MemberAccessExpr(base: childExpr, name: "withLeadingTrivia")) {
153-
TupleExprElement(expression: SequenceExpr {
154-
"indentedNewline"
155-
BinaryOperatorExpr("+")
156-
TupleExpr {
157-
SequenceExpr {
158-
MemberAccessExpr(base: childExpr, name: "leadingTrivia")
159-
BinaryOperatorExpr("??")
160-
ArrayExpr()
161-
}
162-
}
163-
})
164-
})
165-
}
166-
}
167-
)
168-
VariableDecl(
169-
.let,
170-
name: "leadingTrivia",
171-
initializer: SequenceExpr {
172-
MemberAccessExpr(base: "result", name: "leadingTrivia")
173-
BinaryOperatorExpr("??")
174-
ArrayExpr()
175-
}
176-
)
177-
IfStmt(conditions: ExprList {
178-
PrefixOperatorExpr("!", MemberAccessExpr(base: "leadingTrivia", name: "isEmpty"))
179-
}) {
180-
SequenceExpr {
181-
"result"
182-
AssignmentExpr()
183-
FunctionCallExpr(MemberAccessExpr(base: "result", name: "withLeadingTrivia")) {
184-
TupleExprElement(expression: "leadingTrivia")
185-
}
94+
var initializerExpr: ExprBuildable = IdentifierExpr("syntax")
95+
for child in node.children where child.requiresLeadingNewline {
96+
initializerExpr = FunctionCallExpr("\(initializerExpr).with\(child.name)(syntax.\(child.swiftName).withLeadingTrivia(indentedNewline + (syntax.\(child.swiftName).leadingTrivia ?? [])))")
97+
}
98+
return FunctionDecl(
99+
"""
100+
public func format(syntax: \(node.type.syntaxBaseName)) -> \(node.type.syntaxBaseName) {
101+
var result = \(initializerExpr)
102+
let leadingTrivia = result.leadingTrivia ?? []
103+
if !leadingTrivia.isEmpty {
104+
result = result.withLeadingTrivia(leadingTrivia)
186105
}
106+
return result
187107
}
188-
ReturnStmt(expression: "result")
189-
}
108+
"""
109+
)
190110
}
191111

192112
/// Generate the format implementation for a collection node.
@@ -198,29 +118,13 @@ private func createBuildableCollectionNodeFormatFunction(node: Node) -> Function
198118
signature: createFormatFunctionSignature(type: node.type)
199119
) {
200120
if node.elementsSeparatedByNewline {
201-
FunctionCallExpr(node.type.syntaxBaseName) {
202-
TupleExprElement(expression: FunctionCallExpr(
203-
MemberAccessExpr(base: "syntax", name: "map"),
204-
trailingClosure: ClosureExpr {
205-
FunctionCallExpr(MemberAccessExpr(base: "$0", name: "withLeadingTrivia")) {
206-
TupleExprElement(expression: TupleExpr {
207-
SequenceExpr {
208-
"indentedNewline"
209-
BinaryOperatorExpr("+")
210-
TupleExpr {
211-
SequenceExpr {
212-
MemberAccessExpr(base: "$0", name: "leadingTrivia")
213-
BinaryOperatorExpr("??")
214-
ArrayExpr()
215-
}
216-
}
217-
}
218-
}
219-
)
220-
}
221-
}
222-
))
223-
}
121+
FunctionCallExpr(
122+
"""
123+
\(node.type.syntaxBaseName)(syntax.map {
124+
$0.withLeadingTrivia((indentedNewline + ($0.leadingTrivia ?? [])))
125+
})
126+
"""
127+
)
224128
} else {
225129
"syntax"
226130
}
@@ -250,14 +154,10 @@ private func createTokenFormatFunction() -> FunctionDecl {
250154
private func createWithLeadingWithTrailingTriviaCall(token: TokenSpec) -> CodeBlockItem {
251155
var res: ExprBuildable = IdentifierExpr("syntax")
252156
if token.requiresLeadingSpace {
253-
res = FunctionCallExpr(MemberAccessExpr(base: res, name: "withLeadingTrivia")) {
254-
TupleExprElement(expression: MemberAccessExpr(name: "space"))
255-
}
157+
res = FunctionCallExpr("\(res).withLeadingTrivia(.space)")
256158
}
257159
if token.requiresTrailingSpace {
258-
res = FunctionCallExpr(MemberAccessExpr(base: res, name: "withTrailingTrivia")) {
259-
TupleExprElement(expression: MemberAccessExpr(name: "space"))
260-
}
160+
res = FunctionCallExpr("\(res).withTrailingTrivia(.space)")
261161
}
262162
return CodeBlockItem(item: ReturnStmt(expression: res))
263163
}

0 commit comments

Comments
 (0)