10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
+ import SwiftSyntax
14
+ import SwiftSyntaxBuilder
15
+
13
16
/// Wrapper around the syntax kind strings to provide functionality specific to
14
17
/// SwiftSyntaxBuilder. In particular, this includes the functionality to create
15
18
/// the `*Buildable`, `ExpressibleAs*` and `*Syntax` Swift types from the syntax
@@ -19,11 +22,6 @@ struct SyntaxBuildableType: Hashable {
19
22
let tokenKind : String ?
20
23
let isOptional : Bool
21
24
22
- /// If optional `?`, otherwise the empty string.
23
- var optionalQuestionMark : String {
24
- isOptional ? " ? " : " "
25
- }
26
-
27
25
/// Whether this is a token.
28
26
var isToken : Bool {
29
27
syntaxKind == " Token "
@@ -43,17 +41,17 @@ struct SyntaxBuildableType: Hashable {
43
41
/// with fixed test), return an expression of the form ` = defaultValue`
44
42
/// that can be used as the default value for a function parameter.
45
43
/// Otherwise, return the empty string.
46
- var defaultInitialization : String {
44
+ var defaultInitialization : ExpressibleAsExprBuildable ? {
47
45
if isOptional {
48
- return " = nil "
46
+ return NilLiteralExpr ( )
49
47
} else if isToken {
50
48
if let token = token, token. text != nil {
51
- return " = TokenSyntax.` \( lowercaseFirstWord ( name: token. name) ) ` "
49
+ return MemberAccessExpr ( base : " TokenSyntax " , name : lowercaseFirstWord ( name: token. name) )
52
50
} else if tokenKind == " EOFToken " {
53
- return " = TokenSyntax. eof"
51
+ return MemberAccessExpr ( base : " TokenSyntax " , name : " eof " )
54
52
}
55
53
}
56
- return " "
54
+ return nil
57
55
}
58
56
59
57
/// Whether the type is a syntax collection.
@@ -68,81 +66,98 @@ struct SyntaxBuildableType: Hashable {
68
66
syntaxKind
69
67
}
70
68
71
- /// Return the name of the `Buildable` type that is the main entry point for building
69
+ /// Return the `Buildable` type that is the main entry point for building
72
70
/// SwiftSyntax trees using `SwiftSyntaxBuilder`.
73
71
///
74
72
/// These names look as follows:
75
73
/// - For nodes: The node name, e.g. `IdentifierExpr` (these are implemented as structs)
76
74
/// - For base kinds: `<BaseKind>Buildable`, e.g. `ExprBuildable` (these are implemented as protocols)
77
75
/// - For token: `TokenSyntax` (tokens don't have a dedicated type in SwiftSyntaxBuilder)
78
- /// If the type is optional, this terminates with a '?'.
79
- var buildable : String {
80
- if isToken {
81
- // Tokens don't have a dedicated buildable type.
82
- return " TokenSyntax \( optionalQuestionMark) "
83
- } else if SYNTAX_BASE_KINDS . contains ( syntaxKind) {
84
- return " \( syntaxKind) Buildable \( optionalQuestionMark) "
85
- } else {
86
- return " \( syntaxKind) \( optionalQuestionMark) "
87
- }
76
+ /// If the type is optional, the type is wrapped in an `OptionalType`.
77
+ var buildable : ExpressibleAsTypeBuildable {
78
+ optionalWrapped ( type: buildableBaseName)
88
79
}
89
80
90
81
/// Whether parameters of this type should be initializable by a result builder.
91
82
/// Used for certain syntax collections and block-like structures (e.g. `CodeBlock`,
92
83
/// `MemberDeclList`).
93
84
var isBuilderInitializable : Bool {
94
- BUILDER_INITIALIZABLE_TYPES . keys. contains ( nonOptional . buildable )
85
+ BUILDER_INITIALIZABLE_TYPES . keys. contains ( buildableBaseName )
95
86
}
96
87
97
88
/// A type suitable for initializing this type through a result builder (e.g.
98
89
/// returns `CodeBlockItemList` for `CodeBlock`) and otherwise itself.
99
90
var builderInitializableType : Self {
100
- let buildable = nonOptional. buildable
101
- return Self (
102
- syntaxKind: BUILDER_INITIALIZABLE_TYPES [ buildable] . flatMap { $0 } ?? buildable,
91
+ Self (
92
+ syntaxKind: BUILDER_INITIALIZABLE_TYPES [ buildableBaseName] . flatMap { $0 } ?? buildableBaseName,
103
93
isOptional: isOptional
104
94
)
105
95
}
106
96
107
97
/// The type from `buildable()` without any question marks attached.
108
98
/// This is used for the `create*` methods defined in the `ExpressibleAs*` protocols.
109
99
var buildableBaseName : String {
110
- nonOptional. buildable
100
+ if isToken {
101
+ // Tokens don't have a dedicated buildable type.
102
+ return " TokenSyntax "
103
+ } else if SYNTAX_BASE_KINDS . contains ( syntaxKind) {
104
+ return " \( syntaxKind) Buildable "
105
+ } else {
106
+ return syntaxKind
107
+ }
111
108
}
112
109
113
- /// The `ExpressibleAs*` Swift type for this syntax kind. Tokens don't
114
- /// have an `ExpressibleAs*` type, so for those this method just returns
115
- /// `TokenSyntax`. If the type is optional, this terminates with a `?`.
116
- var expressibleAs : String {
110
+ /// The `ExpressibleAs*` Swift type for this syntax kind without any
111
+ /// question marks attached.
112
+ var expressibleAsBaseName : String {
117
113
if isToken {
118
114
// Tokens don't have a dedicated ExpressibleAs type.
119
- return buildable
115
+ return buildableBaseName
120
116
} else {
121
- return " ExpressibleAs \( buildable ) "
117
+ return " ExpressibleAs \( buildableBaseName ) "
122
118
}
123
119
}
124
120
121
+ /// The `ExpressibleAs*` Swift type for this syntax kind. Tokens don't
122
+ /// have an `ExpressibleAs*` type, so for those this method just returns
123
+ /// `TokenSyntax`. If the type is optional, this terminates with a `?`.
124
+ var expressibleAs : ExpressibleAsTypeBuildable {
125
+ optionalWrapped ( type: expressibleAsBaseName)
126
+ }
127
+
125
128
/// The corresponding `*Syntax` type defined in the `SwiftSyntax` module,
126
- /// which will eventually get built from `SwiftSyntaxBuilder`. If the type
127
- /// is optional, this terminates with a `?`.
128
- var syntax : String {
129
+ /// without any question marks attached.
130
+ var syntaxBaseName : String {
129
131
if syntaxKind == " Syntax " {
130
- return " Syntax \( optionalQuestionMark ) "
132
+ return " Syntax "
131
133
} else {
132
- return " \( syntaxKind) Syntax \( optionalQuestionMark ) "
134
+ return " \( syntaxKind) Syntax "
133
135
}
134
136
}
135
137
136
- /// Assuming that this is a base kind, return the corresponding `*ListBuildable` type.
137
- var listBuildable : String {
138
+ /// The corresponding `*Syntax` type defined in the `SwiftSyntax` module,
139
+ /// which will eventually get built from `SwiftSyntaxBuilder`. If the type
140
+ /// is optional, this terminates with a `?`.
141
+ var syntax : ExpressibleAsTypeBuildable {
142
+ optionalWrapped ( type: syntaxBaseName)
143
+ }
144
+
145
+ /// Assuming that this is a base kind, return the corresponding `*ListBuildable` type
146
+ /// without any question marks attached.
147
+ var listBuildableBaseName : String {
138
148
assert ( SYNTAX_BASE_KINDS . contains ( syntaxKind) , " ListBuildable types only exist for syntax base kinds " )
139
- return " \( syntaxKind) ListBuildable \( optionalQuestionMark) "
149
+ return " \( syntaxKind) ListBuildable "
150
+ }
151
+
152
+ /// Assuming that this is a base kind, return the corresponding `*ListBuildable` type.
153
+ var listBuildable : ExpressibleAsTypeBuildable {
154
+ optionalWrapped ( type: listBuildableBaseName)
140
155
}
141
156
142
157
/// Assuming that this is a collection type, the type of the result builder
143
158
/// that can be used to build the collection.
144
- var resultBuilder : String {
145
- " \( syntaxKind) Builder \( optionalQuestionMark ) "
159
+ var resultBuilder : ExpressibleAsTypeBuildable {
160
+ optionalWrapped ( type : " \( syntaxKind) Builder " )
146
161
}
147
162
148
163
/// The collection types in which this type occurs as an element.
@@ -164,7 +179,7 @@ struct SyntaxBuildableType: Hashable {
164
179
/// make the `ExpressibleAs*` of this type conform to the `ExpressibleAs*`
165
180
/// protocol of the convertible types.
166
181
var convertibleToTypes : [ Self ] {
167
- ( SYNTAX_BUILDABLE_EXPRESSIBLE_AS_CONFORMANCES [ buildable ] ?? [ ] )
182
+ ( SYNTAX_BUILDABLE_EXPRESSIBLE_AS_CONFORMANCES [ buildableBaseName ] ?? [ ] )
168
183
. map { Self ( syntaxKind: $0) }
169
184
}
170
185
@@ -217,13 +232,31 @@ struct SyntaxBuildableType: Hashable {
217
232
}
218
233
}
219
234
235
+ /// Wraps a type in an optional depending on whether `isOptional` is true.
236
+ func optionalWrapped( type: ExpressibleAsTypeBuildable ) -> ExpressibleAsTypeBuildable {
237
+ if isOptional {
238
+ return OptionalType ( wrappedType: type)
239
+ } else {
240
+ return type
241
+ }
242
+ }
243
+
244
+ /// Wraps a type in an optional chaining depending on whether `isOptional` is true.
245
+ func optionalChained( expr: ExpressibleAsExprBuildable ) -> ExpressibleAsExprBuildable {
246
+ if isOptional {
247
+ return OptionalChainingExpr ( expression: expr)
248
+ } else {
249
+ return expr
250
+ }
251
+ }
252
+
220
253
/// Generate an expression that converts a variable named `varName`
221
254
/// which is of `expressibleAs` type to an object of type `buildable`.
222
- func generateExprConvertParamTypeToStorageType( varName: String ) -> String {
255
+ func generateExprConvertParamTypeToStorageType( varName: String ) -> ExpressibleAsExprBuildable {
223
256
if isToken {
224
257
return varName
225
258
} else {
226
- return " \( varName) \( optionalQuestionMark ) . create\( buildableBaseName) () "
259
+ return FunctionCallExpr ( MemberAccessExpr ( base : optionalChained ( expr : varName) , name : " create \( buildableBaseName) " ) )
227
260
}
228
261
}
229
262
}
0 commit comments