Skip to content

Commit 4e9d84c

Browse files
authored
Merge pull request swiftlang#78 from akyrtzi/reversed-collection
[SyntaxCollections] Add a reversed `Sequence` for `SyntaxCollection`s
2 parents 794949d + 680ded8 commit 4e9d84c

File tree

3 files changed

+81
-13
lines changed

3 files changed

+81
-13
lines changed

Sources/SwiftSyntax/SyntaxChildren.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,14 @@ struct RawSyntaxChildren: Sequence {
5454
}
5555
}
5656

57+
protocol AbsoluteRawSyntaxIteratorProtocol:
58+
IteratorProtocol where Element == AbsoluteRawSyntax {
59+
}
60+
5761
/// Sequence of `AbsoluteRawSyntax` formed from all the `present` layout
5862
/// children nodes of a raw node.
5963
struct PresentRawSyntaxChildren: Sequence {
60-
struct Iterator: IteratorProtocol {
64+
struct Iterator: AbsoluteRawSyntaxIteratorProtocol {
6165
var iterator: RawSyntaxChildren.Iterator
6266

6367
init(parent: AbsoluteRawSyntax) {
@@ -98,7 +102,7 @@ struct PresentRawSyntaxChildren: Sequence {
98102

99103
/// Reversed Sequence of `PresentRawSyntaxChildren`.
100104
struct ReversedPresentRawSyntaxChildren: Sequence {
101-
struct Iterator: IteratorProtocol {
105+
struct Iterator: AbsoluteRawSyntaxIteratorProtocol {
102106
let parent: RawSyntax
103107
var previousChildInfo: AbsoluteSyntaxInfo
104108

Sources/SwiftSyntax/SyntaxCollections.swift.gyb

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ public struct ${node.name}: _SyntaxBase, Hashable, SyntaxCollection {
157157

158158
/// Conformance for `${node.name}`` to the Sequence protocol.
159159
extension ${node.name}: Sequence {
160+
fileprivate static func nextElement<Iter>(
161+
_ iterator: inout Iter, parent: _SyntaxBase
162+
) -> ${node.collection_element_type}? where Iter: AbsoluteRawSyntaxIteratorProtocol {
163+
guard let absoluteRaw = iterator.next() else { return nil }
164+
let data = SyntaxData(absoluteRaw, parent: parent)
165+
% is_constructable = node.collection_element_type != 'Syntax' and \
166+
% not (element_node and element_node.is_base())
167+
% if is_constructable:
168+
return ${node.collection_element_type}(data)
169+
% else:
170+
% cast = '' if node.collection_element_type == 'Syntax' \
171+
% else 'as! ' + node.collection_element_type
172+
return (makeSyntax(data) ${cast})
173+
% end
174+
}
175+
160176
public struct Iterator: IteratorProtocol {
161177
private let parent: _SyntaxBase
162178
private var iterator: PresentRawSyntaxChildren.Iterator
@@ -167,24 +183,45 @@ extension ${node.name}: Sequence {
167183
}
168184

169185
public mutating func next() -> ${node.collection_element_type}? {
170-
guard let absoluteRaw = iterator.next() else { return nil }
171-
let data = SyntaxData(absoluteRaw, parent: self.parent)
172-
% is_constructable = node.collection_element_type != 'Syntax' and \
173-
% not (element_node and element_node.is_base())
174-
% if is_constructable:
175-
return ${node.collection_element_type}(data)
176-
% else:
177-
% cast = '' if node.collection_element_type == 'Syntax' \
178-
% else 'as! ' + node.collection_element_type
179-
return (makeSyntax(data) ${cast})
180-
% end
186+
return ${node.name}.nextElement(&iterator, parent: parent)
181187
}
182188
}
183189

184190
/// Returns an iterator over the elements of this syntax collection.
185191
public func makeIterator() -> Iterator {
186192
return Iterator(collection: self)
187193
}
194+
195+
public func reversed() -> Reversed {
196+
return Reversed(collection: self)
197+
}
198+
199+
public struct Reversed: Sequence {
200+
public struct Iterator: IteratorProtocol {
201+
private let parent: _SyntaxBase
202+
private var iterator: ReversedPresentRawSyntaxChildren.Iterator
203+
204+
public init(collection node: ${node.name}) {
205+
self.iterator = .init(parent: node.data.absoluteRaw)
206+
self.parent = node
207+
}
208+
209+
public mutating func next() -> ${node.collection_element_type}? {
210+
return ${node.name}.nextElement(&iterator, parent: parent)
211+
}
212+
}
213+
214+
let collection: ${node.name}
215+
216+
/// Returns an iterator over the elements of this syntax collection.
217+
public func makeIterator() -> Iterator {
218+
return Iterator(collection: collection)
219+
}
220+
221+
public func reversed() -> ${node.name} {
222+
return collection
223+
}
224+
}
188225
}
189226

190227
% end

Tests/SwiftSyntaxTest/SyntaxCollections.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class SyntaxCollectionsAPITestCase: XCTestCase {
1818
("testRemovingLastElement", testRemovingLastElement),
1919
("testRemovingElement", testRemovingElement),
2020
("testReplacingElement", testReplacingElement),
21+
("testIteration", testIteration),
2122
]
2223

2324
public func testAppendingElement() {
@@ -112,4 +113,30 @@ public class SyntaxCollectionsAPITestCase: XCTestCase {
112113
XCTAssertNotNil(newArrayElementList.child(at: 2))
113114
XCTAssertEqual("\(newArrayElementList.child(at: 2)!)", "3")
114115
}
116+
117+
public func testIteration() {
118+
let arrayElementList = SyntaxFactory.makeArrayElementList([
119+
integerLiteralElement(0),
120+
integerLiteralElement(1),
121+
integerLiteralElement(2)
122+
])
123+
124+
let elems = Array(arrayElementList)
125+
XCTAssertEqual(elems.count, 3)
126+
guard elems.count == 3 else {
127+
return
128+
}
129+
XCTAssertEqual("\(elems[0])", "0")
130+
XCTAssertEqual("\(elems[1])", "1")
131+
XCTAssertEqual("\(elems[2])", "2")
132+
133+
let relems = Array(arrayElementList.reversed())
134+
XCTAssertEqual(relems.count, 3)
135+
guard relems.count == 3 else {
136+
return
137+
}
138+
XCTAssertEqual("\(relems[2])", "0")
139+
XCTAssertEqual("\(relems[1])", "1")
140+
XCTAssertEqual("\(relems[0])", "2")
141+
}
115142
}

0 commit comments

Comments
 (0)