@@ -80,7 +80,7 @@ public enum ChildKind {
80
80
81
81
/// A child of a node, that may be declared optional or a token with a
82
82
/// restricted subset of acceptable kinds or texts.
83
- public class Child : NodeChoiceConvertible {
83
+ public class Child : SyntaxNodeConvertible , NodeChoiceConvertible , ParameterConvertible {
84
84
/// The name of the child.
85
85
///
86
86
/// The first character of the name is always uppercase.
@@ -227,9 +227,9 @@ public class Child: NodeChoiceConvertible {
227
227
case . nodeChoices( let choices) :
228
228
return choices. isEmpty
229
229
case . node( let kind) :
230
- return kind. isBase
230
+ return kind. isBaseType
231
231
case . collection( kind: let kind, _, _, _) :
232
- return kind. isBase
232
+ return kind. isBaseType
233
233
case . token:
234
234
return false
235
235
}
@@ -244,6 +244,11 @@ public class Child: NodeChoiceConvertible {
244
244
return AttributeListSyntax ( " @_spi(ExperimentalLanguageFeatures) " ) . with ( \. trailingTrivia, . newline)
245
245
}
246
246
247
+ /// The ``Node`` representation of this child, if any.
248
+ public var node : Node ? {
249
+ self . syntaxNodeKind. node
250
+ }
251
+
247
252
/// If a classification is passed, it specifies the color identifiers in
248
253
/// that subtree should inherit for syntax coloring. Must be a member of
249
254
/// ``SyntaxClassification``.
@@ -273,3 +278,80 @@ public class Child: NodeChoiceConvertible {
273
278
self . isOptional = isOptional
274
279
}
275
280
}
281
+
282
+ // MARK: SyntaxNodeConvertible
283
+ public extension Child {
284
+ var isNode : Bool {
285
+ switch self . kind {
286
+ case . node, . collection:
287
+ return true
288
+ default :
289
+ return false
290
+ }
291
+ }
292
+
293
+ var syntaxType : TypeSyntax {
294
+ switch self . kind {
295
+ case . node( let kind) , . collection( let kind, _, _, _) :
296
+ return kind. syntaxType
297
+ case . nodeChoices:
298
+ return self . syntaxChoicesType
299
+ case . token:
300
+ return " TokenSyntax "
301
+ }
302
+ }
303
+ }
304
+
305
+ // MARK: ParameterConvertible
306
+ extension Child {
307
+ public var parameterAnyType : TypeSyntax {
308
+ self . parameterType ( specifier: " any " )
309
+ }
310
+
311
+ public var parameterSomeType : TypeSyntax {
312
+ self . parameterType ( specifier: " some " )
313
+ }
314
+
315
+ func parameterType(
316
+ specifier: TokenSyntax ,
317
+ protocolType: TypeSyntax ? = nil ,
318
+ syntaxType: TypeSyntax ? = nil
319
+ ) -> TypeSyntax {
320
+ let type : TypeSyntax
321
+ if self . isBaseNode {
322
+ type = " \( specifier) \( protocolType ?? self . protocolType) "
323
+ } else {
324
+ type = syntaxType ?? self . syntaxType
325
+ }
326
+ return self . isOptional ? type. optionalWrapped : type
327
+ }
328
+
329
+ func defaultValue( syntaxType: TypeSyntax ) -> ExprSyntax ? {
330
+ guard !self . isOptional else {
331
+ if self . isBaseNode {
332
+ return " \( syntaxType. optionalWrapped) .none "
333
+ } else {
334
+ return " nil "
335
+ }
336
+ }
337
+ if case . collection( _, _, defaultsToEmpty: true , _) = self . kind {
338
+ return " [] "
339
+ }
340
+ guard let token else {
341
+ return self . isOptional ? " nil " : nil
342
+ }
343
+ guard token. text == nil else {
344
+ return " . \( token. identifier) Token() "
345
+ }
346
+ guard case . token( let choices, _, _) = self . kind,
347
+ case . keyword( let keyword) = choices. only
348
+ else {
349
+ return nil
350
+ }
351
+ return " . \( token. memberCallName) (. \( keyword. spec. memberCallName) ) "
352
+ }
353
+
354
+ public var defaultValue : ExprSyntax ? {
355
+ self . defaultValue ( syntaxType: self . syntaxType)
356
+ }
357
+ }
0 commit comments