Skip to content

Commit 2a3d4cb

Browse files
Initial infrastructure for documenting SwiftSyntax API (swiftlang#14701)
1 parent fc74d52 commit 2a3d4cb

File tree

7 files changed

+70
-7
lines changed

7 files changed

+70
-7
lines changed

include/swift/Syntax/SyntaxNodes.h.gyb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ using ${node.name} =
4949
% for node in SYNTAX_NODES:
5050
% if not node.is_syntax_collection():
5151
% qualifier = "" if node.is_base() else "final"
52+
% for line in dedented_lines(node.description):
53+
/// ${line}
54+
% end
5255
class ${node.name} ${qualifier} : public ${node.base_type} {
5356
% if node.is_buildable():
5457
friend class ${node.name}Builder;
@@ -74,6 +77,9 @@ public:
7477
}
7578

7679
% for child in node.children:
80+
% for line in dedented_lines(child.description):
81+
/// ${line}
82+
% end
7783
% if child.is_optional:
7884
llvm::Optional<${child.type_name}> get${child.name}();
7985
% else:
@@ -84,8 +90,18 @@ public:
8490
% if child_node and child_node.is_syntax_collection():
8591
% child_elt = child_node.collection_element_name
8692
% child_elt_type = child_node.collection_element_type
93+
/// Adds the provided `${child_elt}` to the node's `${child.name}`
94+
/// collection.
95+
/// - param element: The new `${child_elt}` to add to the node's
96+
/// `${child.name}` collection.
97+
/// - returns: A copy of the receiver with the provided `${child_elt}`
98+
/// appended to its `${child.name}` collection.
8799
${node.name} add${child_elt}(${child_elt_type} ${child_elt});
88100
% end
101+
102+
/// Returns a copy of the receiver with its `${child.name}` replaced.
103+
/// - param newChild: The new `${child.name}` to replace the node's
104+
/// current `${child.name}`, if present.
89105
${node.name}
90106
with${child.name}(llvm::Optional<${child.type_name}> New${child.type_name});
91107

tools/SwiftSyntax/SyntaxNodes.swift.gyb

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,18 @@ public struct UnknownSyntax: _SyntaxBase {
5757
% for node in SYNTAX_NODES:
5858
% base_type = node.base_type
5959
% if node.is_base():
60+
% for line in dedented_lines(node.description):
61+
/// ${line}
62+
% end
6063
public protocol ${node.name}: Syntax {}
6164

6265
% elif node.collection_element:
6366
% pass
6467
% else:
68+
69+
% for line in dedented_lines(node.description):
70+
/// ${line}
71+
% end
6572
public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable {
6673
% if node.children:
6774
enum Cursor: Int {
@@ -127,6 +134,9 @@ public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable {
127134
% end
128135
% cast = '' if child.type_name == 'Syntax' \
129136
% else '%s %s' % (cast_symbol, child.type_name)
137+
% for line in dedented_lines(child.description):
138+
/// ${line}
139+
% end
130140
public var ${child.swift_name}: ${ret_type} {
131141
let child = data.cachedChild(at: Cursor.${child.swift_name})
132142
% if child.is_optional:
@@ -139,20 +149,29 @@ public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable {
139149
% child_elt = child_node.collection_element_name
140150
% child_elt_type = child_node.collection_element_type
141151

142-
public func add${child_elt}(_ elt: ${child_elt_type}) -> ${node.name} {
152+
/// Adds the provided `${child_elt}` to the node's `${child.swift_name}`
153+
/// collection.
154+
/// - param element: The new `${child_elt}` to add to the node's
155+
/// `${child.swift_name}` collection.
156+
/// - returns: A copy of the receiver with the provided `${child_elt}`
157+
/// appended to its `${child.swift_name}` collection.
158+
public func add${child_elt}(_ element: ${child_elt_type}) -> ${node.name} {
143159
var collection: RawSyntax
144160
if let col = raw[Cursor.${child.swift_name}] {
145-
collection = col.appending(elt.raw)
161+
collection = col.appending(element.raw)
146162
} else {
147163
collection = RawSyntax.node(SyntaxKind.${child_node.swift_syntax_kind},
148-
[elt.raw], .present)
164+
[element.raw], .present)
149165
}
150166
let (root, newData) = data.replacingChild(collection,
151167
at: Cursor.${child.swift_name})
152168
return ${node.name}(root: root, data: newData)
153169
}
154170
% end
155171

172+
/// Returns a copy of the receiver with its `${child.swift_name}` replaced.
173+
/// - param newChild: The new `${child.swift_name}` to replace the node's
174+
/// current `${child.swift_name}`, if present.
156175
public func with${child.name}(
157176
_ newChild: ${child.type_name}?) -> ${node.name} {
158177
let raw = newChild?.raw ?? ${make_missing_swift_child(child)}
@@ -162,10 +181,12 @@ public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable {
162181
}
163182
% end
164183

184+
/// Determines if two `${node.name}` nodes are equal to each other.
165185
public static func ==(lhs: ${node.name}, rhs: ${node.name}) -> Bool {
166186
return lhs._data === rhs._data
167187
}
168188

189+
/// A unique hash value for this node.
169190
public var hashValue: Int {
170191
return ObjectIdentifier(_data).hashValue
171192
}
@@ -202,6 +223,10 @@ extension ${node.name}: ${traits_list} {}
202223
/// MARK: Convenience methods
203224

204225
extension StructDeclSyntax {
226+
/// Creates a new StructDeclSyntax with the provided name as its identifier.
227+
/// - param name: The new struct's name.
228+
/// - returns: A new StructDeclSyntax with the same fields as the receiver,
229+
/// but with the provided identifier.
205230
func withIdentifier(_ name: String) -> StructDeclSyntax {
206231
let newToken = SyntaxFactory.makeIdentifier(name,
207232
leadingTrivia: identifier.leadingTrivia,

utils/gyb_syntax_support/Child.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ class Child(object):
88
A child of a node, that may be declared optional or a token with a
99
restricted subset of acceptable kinds or texts.
1010
"""
11-
def __init__(self, name, kind, is_optional=False,
11+
def __init__(self, name, kind, description=None, is_optional=False,
1212
token_choices=None, text_choices=None, node_choices=None):
1313
self.name = name
1414
self.swift_name = lowercase_first_word(name)
1515
self.syntax_kind = kind
16+
self.description = description
1617
self.swift_syntax_kind = lowercase_first_word(self.syntax_kind)
1718
self.type_name = kind_to_type(self.syntax_kind)
1819

utils/gyb_syntax_support/CommonNodes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@
1515

1616
# code-block-item = (decl | stmt | expr) ';'?
1717
Node('CodeBlockItem', kind='Syntax',
18+
description="""
19+
A CodeBlockItem is any Syntax node that appears on its own line inside
20+
a CodeBlock.
21+
""",
1822
children=[
1923
Child('Item', kind='Syntax',
24+
description="The underlying node inside the code block.",
2025
node_choices=[
2126
Child('Decl', kind='Decl'),
2227
Child('Stmt', kind='Stmt'),
2328
Child('Expr', kind='Expr'),
2429
]),
2530
Child('Semicolon', kind='SemicolonToken',
31+
description="""
32+
If present, the trailing semicolon at the end of the item.
33+
""",
2634
is_optional=True),
2735
]),
2836

utils/gyb_syntax_support/Node.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ class Node(object):
1616
subclass.
1717
"""
1818

19-
def __init__(self, name, kind=None, traits=None, children=None,
20-
element=None, element_name=None, element_choices=None):
19+
def __init__(self, name, description=None, kind=None, traits=None,
20+
children=None, element=None, element_name=None,
21+
element_choices=None):
2122
self.syntax_kind = name
2223
self.swift_syntax_kind = lowercase_first_word(name)
2324
self.name = kind_to_type(self.syntax_kind)
25+
self.description = description
2426

2527
self.traits = traits or []
2628
self.children = children or []

utils/gyb_syntax_support/Traits.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33

44
class Trait(object):
5-
def __init__(self, trait_name, children):
5+
def __init__(self, trait_name, description=None, children=None):
66
self.trait_name = trait_name
77
self.children = children
8+
self.description = description
89

910

1011
TRAITS = [

utils/gyb_syntax_support/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import textwrap
12
from AttributeNodes import ATTRIBUTE_NODES
23
from CommonNodes import COMMON_NODES # noqa: I201
34
from DeclNodes import DECL_NODES # noqa: I201
@@ -90,3 +91,12 @@ def create_node_map():
9091

9192
def is_visitable(node):
9293
return not node.is_base() and not node.collection_element
94+
95+
96+
def dedented_lines(description):
97+
"""
98+
Each line of the provided string with leading whitespace stripped.
99+
"""
100+
if not description:
101+
return []
102+
return textwrap.dedent(description).split('\n')

0 commit comments

Comments
 (0)