Skip to content

Commit 8d88b29

Browse files
committed
WIP enumerate node_choices and element_choices
1 parent 6ba87a8 commit 8d88b29

12 files changed

+1670
-736
lines changed

Sources/SwiftSyntax/Syntax.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
5959
}
6060

6161
// Casting functions to specialized syntax nodes.
62-
extension Syntax {
62+
extension SyntaxProtocol {
6363
public func `is`<S: SyntaxProtocol>(_ syntaxType: S.Type) -> Bool {
6464
return self.as(syntaxType) != nil
6565
}
6666

6767
public func `as`<S: SyntaxProtocol>(_ syntaxType: S.Type) -> S? {
68-
return S.init(self)
68+
return S.init(self._syntaxNode)
6969
}
7070
}
7171

Sources/SwiftSyntax/SyntaxCollections.swift.gyb

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,48 @@ public protocol SyntaxCollection: SyntaxProtocol, Sequence {
3838
/// versions of the collection with different children.
3939
% end
4040
public struct ${node.name}: SyntaxCollection, SyntaxHashable {
41+
% if node.collection_element_choices:
42+
public enum Element: SyntaxProtocol {
43+
% for choice_name in node.collection_element_choices:
44+
% choice = NODE_MAP[choice_name]
45+
case `${choice.swift_syntax_kind}`(${choice.name})
46+
% end
47+
public var _syntaxNode: Syntax {
48+
switch self {
49+
% for choice_name in node.collection_element_choices:
50+
% choice = NODE_MAP[choice_name]
51+
case .${choice.swift_syntax_kind}(let node): return node._syntaxNode
52+
% end
53+
}
54+
}
55+
init(_ data: SyntaxData) { self.init(Syntax(data))! }
56+
% for choice_name in node.collection_element_choices:
57+
% choice_node = NODE_MAP.get(choice_name)
58+
% if choice_node and choice_node.is_base():
59+
public init<Node: ${choice_node.name}Protocol>(_ node: Node) {
60+
self = .${choice_node.swift_syntax_kind}(${choice_node.name}(node))
61+
}
62+
% else:
63+
public init(_ node: ${choice_node.name}) {
64+
self = .${choice_node.swift_syntax_kind}(node)
65+
}
66+
% end
67+
% end
68+
public init?<Node: SyntaxProtocol>(_ syntaxNode: Node) {
69+
% for choice_name in node.collection_element_choices:
70+
% choice = NODE_MAP[choice_name]
71+
if let node = syntaxNode.as(${choice.name}.self) {
72+
self = .${choice.swift_syntax_kind}(node)
73+
return
74+
}
75+
% end
76+
return nil
77+
}
78+
}
79+
% else:
80+
public typealias Element = ${node.collection_element_type}
81+
% end
82+
4183
public let _syntaxNode: Syntax
4284

4385
var layoutView: RawSyntaxLayoutView {
@@ -59,7 +101,7 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
59101
self._syntaxNode = Syntax(data)
60102
}
61103

62-
public init(_ children: [${node.collection_element_type}]) {
104+
public init(_ children: [Element]) {
63105
let raw = RawSyntax.makeLayout(kind: SyntaxKind.${node.swift_syntax_kind},
64106
from: children.map { $0.raw }, arena: .default)
65107
let data = SyntaxData.forRoot(raw)
@@ -87,8 +129,7 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
87129
///
88130
/// - Parameter syntax: The element to append.
89131
/// - Returns: A new `${node.name}` with that element appended to the end.
90-
public func appending(
91-
_ syntax: ${node.collection_element_type}) -> ${node.name} {
132+
public func appending(_ syntax: Element) -> ${node.name} {
92133
var newLayout = layoutView.formLayoutArray()
93134
newLayout.append(syntax.raw)
94135
return replacingLayout(newLayout)
@@ -100,8 +141,7 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
100141
/// - Parameter syntax: The element to prepend.
101142
/// - Returns: A new `${node.name}` with that element prepended to the
102143
/// beginning.
103-
public func prepending(
104-
_ syntax: ${node.collection_element_type}) -> ${node.name} {
144+
public func prepending(_ syntax: Element) -> ${node.name} {
105145
return inserting(syntax, at: 0)
106146
}
107147

@@ -113,8 +153,7 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
113153
/// - index: The index at which to insert the element in the collection.
114154
///
115155
/// - Returns: A new `${node.name}` with that element appended to the end.
116-
public func inserting(_ syntax: ${node.collection_element_type},
117-
at index: Int) -> ${node.name} {
156+
public func inserting(_ syntax: Element, at index: Int) -> ${node.name} {
118157
var newLayout = layoutView.formLayoutArray()
119158
/// Make sure the index is a valid insertion index (0 to 1 past the end)
120159
precondition((newLayout.startIndex...newLayout.endIndex).contains(index),
@@ -131,8 +170,7 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
131170
/// - syntax: The element to replace with.
132171
///
133172
/// - Returns: A new `${node.name}` with the new element at the provided index.
134-
public func replacing(childAt index: Int,
135-
with syntax: ${node.collection_element_type}) -> ${node.name} {
173+
public func replacing(childAt index: Int, with syntax: Element) -> ${node.name} {
136174
var newLayout = layoutView.formLayoutArray()
137175
/// Make sure the index is a valid index for replacing
138176
precondition((newLayout.startIndex..<newLayout.endIndex).contains(index),
@@ -221,7 +259,6 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
221259

222260
/// Conformance for `${node.name}` to the `BidirectionalCollection` protocol.
223261
extension ${node.name}: BidirectionalCollection {
224-
public typealias Element = ${node.collection_element_type}
225262
public typealias Index = SyntaxChildrenIndex
226263

227264
public struct Iterator: IteratorProtocol {
@@ -233,13 +270,13 @@ extension ${node.name}: BidirectionalCollection {
233270
self.iterator = rawChildren.makeIterator()
234271
}
235272

236-
public mutating func next() -> ${node.collection_element_type}? {
273+
public mutating func next() -> Element? {
237274
guard let (raw, info) = self.iterator.next() else {
238275
return nil
239276
}
240277
let absoluteRaw = AbsoluteRawSyntax(raw: raw!, info: info)
241278
let data = SyntaxData(absoluteRaw, parent: parent)
242-
return ${node.collection_element_type}(data)
279+
return Element(data)
243280
}
244281
}
245282

@@ -274,11 +311,11 @@ extension ${node.name}: BidirectionalCollection {
274311
return rawChildren.distance(from: start, to: end)
275312
}
276313

277-
public subscript(position: SyntaxChildrenIndex) -> ${node.collection_element_type} {
314+
public subscript(position: SyntaxChildrenIndex) -> Element {
278315
let (raw, info) = rawChildren[position]
279316
let absoluteRaw = AbsoluteRawSyntax(raw: raw!, info: info)
280317
let data = SyntaxData(absoluteRaw, parent: Syntax(self))
281-
return ${node.collection_element_type}(data)
318+
return Element(data)
282319
}
283320
}
284321
% end

Sources/SwiftSyntax/SyntaxNodes.swift.gyb.template

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,70 @@ nodes whose base kind are that specified kind.
4747
/// ${line}
4848
% end
4949
public struct ${node.name}: ${base_type}Protocol, SyntaxHashable {
50+
% for child in node.children:
51+
% if child.node_choices:
52+
public enum ${child.name}: SyntaxProtocol {
53+
% for choice in child.node_choices:
54+
case `${choice.swift_name}`(${choice.type_name})
55+
% end
56+
public var _syntaxNode: Syntax {
57+
switch self {
58+
% for choice in child.node_choices:
59+
case .${choice.swift_name}(let node): return node._syntaxNode
60+
% end
61+
}
62+
}
63+
init(_ data: SyntaxData) { self.init(Syntax(data))! }
64+
% for choice in child.node_choices:
65+
% choice_node = NODE_MAP.get(choice.syntax_kind)
66+
% # We don't add 'init(_: TokenSyntax)' because we need to check the
67+
% # token kind.
68+
% if choice.is_token():
69+
% pass
70+
% elif choice_node and choice_node.is_base():
71+
public init<Node: ${choice_node.name}Protocol>(_ node: Node) {
72+
self = .${choice.swift_name}(${choice_node.name}(node))
73+
}
74+
% else:
75+
public init(_ node: ${choice.type_name}) {
76+
self = .${choice.swift_name}(node)
77+
}
78+
% end
79+
% end
80+
public init?<Node: SyntaxProtocol>(_ syntaxNode: Node) {
81+
% token_choices = []
82+
% other_choices = []
83+
% for choice in child.node_choices:
84+
% if choice.is_token():
85+
% token_choices += [choice]
86+
% else:
87+
% other_choices += [choice]
88+
% end
89+
% end
90+
%
91+
% if token_choices:
92+
if let tok = syntaxNode.as(TokenSyntax.self) {
93+
switch tok.rawTokenKind {
94+
% for choice in token_choices:
95+
case .${choice.token.swift_kind()}: self = .${choice.swift_name}(tok)
96+
% end
97+
default: return nil
98+
}
99+
return
100+
}
101+
% end
102+
% for choice in other_choices:
103+
if let node = syntaxNode.as(${choice.type_name}.self) {
104+
self = .${choice.swift_name}(node)
105+
return
106+
}
107+
% end
108+
return nil
109+
}
110+
}
111+
112+
% end
113+
% end
50114
% # ==============
51115
% # Initialization
52116
% # ==============
@@ -71,7 +135,7 @@ public struct ${node.name}: ${base_type}Protocol, SyntaxHashable {
71135
public init(
72136
% for (index, child) in enumerate(node.children):
73137
% comma = ',' if index != len(node.children) - 1 else ''
74-
% param_type = child.type_name
138+
% param_type = child.name if child.node_choices else child.type_name
75139
% if child.is_optional:
76140
% param_type = param_type + "?"
77141
% if child.is_unexpected_nodes():
@@ -102,21 +166,21 @@ public struct ${node.name}: ${base_type}Protocol, SyntaxHashable {
102166
% # Children properties
103167
% # ===================
104168
%
105-
% ret_type = child.type_name
106-
% if child.is_optional:
107-
% ret_type += '?'
108-
% end
169+
% child_type = child.type_name
170+
% if child.node_choices:
171+
% child_type = child.name
172+
% optional_mark = "?" if child.is_optional else ""
109173
110174
% for line in dedented_lines(child.description):
111175
/// ${line}
112176
% end
113-
public var ${child.swift_name}: ${ret_type} {
177+
public var ${child.swift_name}: ${child_type}${optional_mark} {
114178
get {
115179
let childData = data.child(at: ${idx}, parent: Syntax(self))
116180
% if child.is_optional:
117181
if childData == nil { return nil }
118182
% end
119-
return ${child.type_name}(childData!)
183+
return ${child_type}(childData!)
120184
}
121185
set(value) {
122186
self = with${child.name}(value)
@@ -161,7 +225,7 @@ public struct ${node.name}: ${base_type}Protocol, SyntaxHashable {
161225
/// - param newChild: The new `${child.swift_name}` to replace the node's
162226
/// current `${child.swift_name}`, if present.
163227
public func with${child.name}(
164-
_ newChild: ${child.type_name}?) -> ${node.name} {
228+
_ newChild: ${child_type}?) -> ${node.name} {
165229
% if child.is_optional:
166230
let raw = newChild?.raw
167231
% else:

Sources/SwiftSyntax/SyntaxOtherNodes.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ public struct TokenSyntax: SyntaxProtocol, SyntaxHashable {
9898
return tokenKind.text
9999
}
100100

101+
@_spi(RawSyntax)
102+
public var rawTokenKind: RawTokenKind {
103+
return tokenView.rawKind
104+
}
105+
101106
/// Returns a new TokenSyntax with its kind replaced
102107
/// by the provided token kind.
103108
public func withKind(_ tokenKind: TokenKind) -> TokenSyntax {

0 commit comments

Comments
 (0)