Skip to content

Commit bbab764

Browse files
committed
Introduce SyntaxTreeStructure
1 parent 41dafda commit bbab764

15 files changed

+3602
-2
lines changed

Sources/SwiftSyntax/Misc.swift.gyb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ extension Syntax {
4343
}
4444
}
4545

46+
public static var structure: SyntaxNodeStructure {
47+
return .choices([
48+
.node(UnknownSyntax.self),
49+
.node(TokenSyntax.self),
50+
% for node in NON_BASE_SYNTAX_NODES:
51+
% if node.is_base():
52+
.node(Unknown${node.name}.self),
53+
% else:
54+
.node(${node.name}.self),
55+
% end
56+
% end
57+
])
58+
}
59+
4660
public func childNameForDiagnostics(_ index: SyntaxChildrenIndex) -> String? {
4761
switch self.as(SyntaxEnum.self) {
4862
case .token(let node):

Sources/SwiftSyntax/Syntax.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,44 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
/// Describes the statically allowed structure of a syntax tree node.
14+
public enum SyntaxNodeStructure {
15+
public enum SyntaxChoice {
16+
case node(SyntaxProtocol.Type)
17+
case token(TokenKind)
18+
}
19+
20+
/// The node contains a fixed number of children which can be accessed by these key paths.
21+
case layout([AnyKeyPath])
22+
23+
/// The node is a `SyntaxCollection` of the given type.
24+
case collection(SyntaxProtocol.Type)
25+
26+
/// The node can contain a single node with one of the listed types.
27+
case choices([SyntaxChoice])
28+
29+
public var isLayout: Bool {
30+
switch self {
31+
case .layout: return true
32+
default: return false
33+
}
34+
}
35+
36+
public var isCollection: Bool {
37+
switch self {
38+
case .collection: return true
39+
default: return false
40+
}
41+
}
42+
43+
public var isChoices: Bool {
44+
switch self {
45+
case .choices: return true
46+
default: return false
47+
}
48+
}
49+
}
50+
1351
/// A Syntax node represents a tree of nodes with tokens at the leaves.
1452
/// Each node has accessors for its known children, and allows efficient
1553
/// iteration over the children through its `children` property.
@@ -136,6 +174,9 @@ public protocol SyntaxProtocol: CustomStringConvertible,
136174
/// conversion is not possible.
137175
init?(_ syntaxNode: Syntax)
138176

177+
/// The statically allowed structure of the syntax node.
178+
static var structure: SyntaxNodeStructure { get }
179+
139180
/// Return a name with which the child at the given `index` can be referred to
140181
/// in diagnostics.
141182
/// Typically, you want to use `childNameInParent` on the child instead of

Sources/SwiftSyntax/SyntaxBaseNodes.swift.gyb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ public struct ${node.name}: ${node.name}Protocol, SyntaxHashable {
138138
return Syntax(self).asProtocol(${node.name}Protocol.self)!
139139
}
140140

141+
public static var structure: SyntaxNodeStructure {
142+
return .choices([
143+
% for child_node in [child_node for child_node in SYNTAX_NODES if child_node.base_kind == node.syntax_kind]:
144+
.node(${child_node.name}.self),
145+
% end
146+
])
147+
}
148+
141149
public func childNameForDiagnostics(_ index: SyntaxChildrenIndex) -> String? {
142150
return Syntax(self).childNameForDiagnostics(index)
143151
}

Sources/SwiftSyntax/SyntaxCollections.swift.gyb

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,17 @@
1818
//
1919
//===----------------------------------------------------------------------===//
2020

21-
public protocol SyntaxCollection: SyntaxProtocol, Sequence {
21+
public protocol SyntaxCollection: SyntaxProtocol, Sequence where Element: SyntaxProtocol {
2222
/// The number of elements, `present` or `missing`, in this collection.
2323
var count: Int { get }
2424
}
2525

26+
public extension SyntaxCollection {
27+
static var structure: SyntaxNodeStructure {
28+
return .collection(Element.self)
29+
}
30+
}
31+
2632
% for node in SYNTAX_NODES:
2733
% if node.collection_element:
2834
% element_node = NODE_MAP.get(node.collection_element)
@@ -75,6 +81,15 @@ public struct ${node.name}: SyntaxCollection, SyntaxHashable {
7581
% end
7682
return nil
7783
}
84+
85+
public static var structure: SyntaxNodeStructure {
86+
return .choices([
87+
% for choice_name in node.collection_element_choices:
88+
% choice = NODE_MAP[choice_name]
89+
.node(${choice.name}.self),
90+
% end
91+
])
92+
}
7893
}
7994
% else:
8095
public typealias Element = ${node.collection_element_type}

Sources/SwiftSyntax/SyntaxNodes.swift.gyb.template

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ public struct ${node.name}: ${base_type}Protocol, SyntaxHashable {
107107
% end
108108
return nil
109109
}
110+
111+
public static var structure: SyntaxNodeStructure {
112+
return .choices([
113+
% for choice in child.node_choices:
114+
% if choice.is_token() and choice.token.text:
115+
.token(.${choice.token.swift_kind()}),
116+
% elif choice.is_token() and not choice.token.text:
117+
.token(.${choice.token.swift_kind()}("")),
118+
% else:
119+
.node(${choice.type_name}.self),
120+
% end
121+
% end
122+
])
123+
}
110124
}
111125

112126
% end
@@ -236,6 +250,14 @@ public struct ${node.name}: ${base_type}Protocol, SyntaxHashable {
236250
}
237251
% end
238252
253+
public static var structure: SyntaxNodeStructure {
254+
return .layout([
255+
% for (index, child) in enumerate(node.children):
256+
\Self.${child.swift_name},
257+
% end
258+
])
259+
}
260+
239261
public func childNameForDiagnostics(_ index: SyntaxChildrenIndex) -> String? {
240262
switch index.data?.indexInParent {
241263
% for (index, child) in enumerate(node.children):

Sources/SwiftSyntax/SyntaxOtherNodes.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public struct UnknownSyntax: SyntaxProtocol, SyntaxHashable {
3838
self.init(data)
3939
}
4040

41+
public static var structure: SyntaxNodeStructure {
42+
return .layout([])
43+
}
44+
4145
public func childNameForDiagnostics(_ index: SyntaxChildrenIndex) -> String? {
4246
return nil
4347
}
@@ -200,6 +204,10 @@ public struct TokenSyntax: SyntaxProtocol, SyntaxHashable {
200204
return raw.totalLength
201205
}
202206

207+
public static var structure: SyntaxNodeStructure {
208+
return .layout([])
209+
}
210+
203211
public func childNameForDiagnostics(_ index: SyntaxChildrenIndex) -> String? {
204212
return nil
205213
}

0 commit comments

Comments
 (0)