10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
- public protocol SyntaxCollection : SyntaxProtocol , BidirectionalCollection , MutableCollection where Element: SyntaxProtocol {
13
+ public protocol SyntaxCollection : SyntaxProtocol , BidirectionalCollection where Element: SyntaxProtocol , Index == SyntaxChildrenIndex {
14
14
associatedtype Iterator = SyntaxCollectionIterator < Element >
15
15
16
16
/// The ``SyntaxKind`` of the syntax node that conforms to ``SyntaxCollection``.
@@ -33,6 +33,17 @@ extension SyntaxCollection {
33
33
self . init ( Syntax ( data) ) !
34
34
}
35
35
36
+ /// Initialize the collection from a collection of the same type.
37
+ ///
38
+ /// - Note: This initializer is needed to improve source compatibility after
39
+ /// the `+` operators have been added. Previously, they created an array
40
+ /// that was converted to a ``SyntaxCollection`` and now they create a
41
+ /// ``SyntaxCollection``, which makes the initializer a no-op.
42
+ @available ( * , deprecated, message: " Call to initializer is not necessary. " )
43
+ public init ( _ collection: Self ) {
44
+ self = collection
45
+ }
46
+
36
47
public init < Children: Sequence > ( _ children: Children ) where Children. Element == Element {
37
48
let arena = SyntaxArena ( )
38
49
// Extend the lifetime of children so their arenas don't get destroyed
@@ -208,6 +219,170 @@ public struct SyntaxCollectionIterator<E: SyntaxProtocol>: IteratorProtocol {
208
219
}
209
220
}
210
221
222
+ // MARK: Functions analogous to RangeReplaceableCollection
223
+
224
+ /// Defines functions that are similar to those in `RangeReplaceableCollection`.
225
+ ///
226
+ /// SyntaxCollection doesn’t conform to `RangeReplaceableCollection` because of
227
+ /// two reasons:
228
+ /// - `RangeReplaceableCollection` assumes that creating a new colleciton and
229
+ /// adding all elements from another collection to it results in the same
230
+ /// collection. This is not true for `SyntaxCollection` because the new
231
+ /// collection wouldn’t have a parent. This causes eg. the default
232
+ /// implementation of `filter` to misbehave.
233
+ /// - It can’t make the complexity guarantees that `RangeReplaceableCollection`
234
+ /// requires, e.g. `append` is `O(tree depth)` instead of `O(1)`.
235
+ extension SyntaxCollection {
236
+ /// Replace the nodes in `subrange` by `newElements`.
237
+ public mutating func replaceSubrange( _ subrange: Range < Self . Index > , with newElements: some Collection < Element > ) {
238
+ // We only access the raw nodes of `newElements` below.
239
+ // Keep `newElements` alive so their arena doesn't get deallocated.
240
+ withExtendedLifetime ( newElements) {
241
+ var newLayout = layoutView. formLayoutArray ( )
242
+ let layoutRangeLowerBound = ( subrange. lowerBound. data? . indexInParent) . map ( Int . init) ?? newLayout. endIndex
243
+ let layoutRangeUpperBound = ( subrange. upperBound. data? . indexInParent) . map ( Int . init) ?? newLayout. endIndex
244
+ newLayout. replaceSubrange ( layoutRangeLowerBound..< layoutRangeUpperBound, with: newElements. map { $0. raw } )
245
+ self = replacingLayout ( newLayout)
246
+ }
247
+ }
248
+
249
+ /// Adds an element to the end of the collection.
250
+ ///
251
+ /// - Parameter newElement: The element to append to the collection.
252
+ public mutating func append( _ newElement: Element ) {
253
+ insert ( newElement, at: endIndex)
254
+ }
255
+
256
+ /// Adds the elements of a sequence to the end of this collection.
257
+ ///
258
+ /// - Parameter newElements: The elements to append to the collection.
259
+ public mutating func append( contentsOf newElements: some Sequence < Element > ) {
260
+ insert ( contentsOf: Array ( newElements) , at: endIndex)
261
+ }
262
+
263
+ /// Inserts a new element into the collection at the specified position.
264
+ ///
265
+ /// - Parameter newElement: The new element to insert into the collection.
266
+ /// - Parameter i: The position at which to insert the new element.
267
+ /// `index` must be a valid index into the collection.
268
+ public mutating func insert( _ newElement: Element , at i: Index ) {
269
+ replaceSubrange ( i..< i, with: CollectionOfOne ( newElement) )
270
+ }
271
+
272
+ /// Inserts the elements of a sequence into the collection at the specified
273
+ /// position.
274
+ ///
275
+ /// - Parameter newElements: The new elements to insert into the collection.
276
+ /// - Parameter i: The position at which to insert the new elements. `index`
277
+ /// must be a valid index of the collection.
278
+ public mutating func insert( contentsOf newElements: some Collection < Element > , at i: Index ) {
279
+ replaceSubrange ( i..< i, with: newElements)
280
+ }
281
+
282
+ /// Removes and returns the element at the specified position.
283
+ ///
284
+ /// - Parameter position: The position of the element to remove. `position`
285
+ /// must be a valid index of the collection that is not equal to the
286
+ /// collection's end index.
287
+ /// - Returns: The removed element.
288
+ @discardableResult
289
+ public mutating func remove( at position: Index ) -> Element {
290
+ precondition ( !isEmpty, " Can't remove from an empty collection " )
291
+ let result : Element = self [ position]
292
+ replaceSubrange ( position..< index ( after: position) , with: EmptyCollection ( ) )
293
+ return result
294
+ }
295
+
296
+ /// Removes the elements in the specified subrange from the collection.
297
+ ///
298
+ /// - Parameter bounds: The range of the collection to be removed. The
299
+ /// bounds of the range must be valid indices of the collection.
300
+ public mutating func removeSubrange( _ bounds: Range < Index > ) {
301
+ replaceSubrange ( bounds, with: EmptyCollection ( ) )
302
+ }
303
+
304
+ /// Creates a new collection by concatenating the elements of a collection and
305
+ /// a sequence.
306
+ ///
307
+ /// - Parameters:
308
+ /// - lhs: A ``SyntaxCollection``
309
+ /// - rhs: A collection or finite sequence.
310
+ public static func + ( lhs: Self , rhs: some Sequence < Element > ) -> Self {
311
+ var result = lhs
312
+ result. append ( contentsOf: rhs)
313
+ return result
314
+ }
315
+
316
+ /// Creates a new collection by concatenating the elements of a collection and
317
+ /// a sequence.
318
+ ///
319
+ /// - Parameters:
320
+ /// - lhs: A ``SyntaxCollection``
321
+ /// - rhs: A collection or finite sequence.
322
+ ///
323
+ /// - Note: This overload exists to resolve when adding an array to a ``SyntaxCollection``.
324
+ public static func + ( lhs: Self , rhs: some RangeReplaceableCollection < Element > ) -> Self {
325
+ var result = lhs
326
+ result. append ( contentsOf: rhs)
327
+ return result
328
+ }
329
+
330
+ /// Creates a new collection by concatenating the elements of a sequence and a
331
+ /// collection.
332
+ ///
333
+ /// - Parameters:
334
+ /// - lhs: A collection or finite sequence.
335
+ /// - rhs: A range-replaceable collection.
336
+ public static func + ( lhs: some Sequence < Element > , rhs: Self ) -> Self {
337
+ var result = rhs
338
+ result. insert ( contentsOf: Array ( lhs) , at: result. startIndex)
339
+ return result
340
+ }
341
+
342
+ /// Creates a new collection by concatenating the elements of a sequence and a
343
+ /// collection.
344
+ ///
345
+ /// - Parameters:
346
+ /// - lhs: A collection or finite sequence.
347
+ /// - rhs: A range-replaceable collection.
348
+ ///
349
+ /// - Note: This overload exists to resolve when adding an array to a ``SyntaxCollection``.
350
+ public static func + ( lhs: some RangeReplaceableCollection < Element > , rhs: Self ) -> Self {
351
+ var result = rhs
352
+ result. insert ( contentsOf: Array ( lhs) , at: result. startIndex)
353
+ return result
354
+ }
355
+
356
+ /// Appends the elements of a sequence to a range-replaceable collection.
357
+ ///
358
+ /// - Parameters:
359
+ /// - lhs: The ``SyntaxCollection`` to append to.
360
+ /// - rhs: A collection or finite sequence.
361
+ ///
362
+ /// - Note: This will result in an allocation of a copy of this node.
363
+ public static func += ( lhs: inout Self , rhs: some Sequence < Element > ) {
364
+ lhs. append ( contentsOf: rhs)
365
+ }
366
+
367
+ /// Returns a new ``SyntaxCollection`` that just contains the elements
368
+ /// satisfying the given predicate.
369
+ ///
370
+ /// - Parameter isIncluded: A closure that takes an element of the
371
+ /// collection as its argument and returns a Boolean value indicating
372
+ /// whether the element should be included in the returned collection.
373
+ /// - Returns: A ``SyntaxCollection`` of the elements that `isIncluded` allowed.
374
+ ///
375
+ /// - Note: This creates a new ``SyntaxCollection`` node. If the resulting node
376
+ /// is not needed (e.g. because it’s only being iterated), convert the
377
+ /// ``SyntaxCollection`` to an array first or use the `where` clause in
378
+ /// a `for` statement.
379
+ public func filter( _ isIncluded: ( Element ) throws -> Bool ) rethrows -> Self {
380
+ var result = self
381
+ result. replaceSubrange ( self . startIndex..< self . endIndex, with: try Array ( self ) . filter ( isIncluded) )
382
+ return result
383
+ }
384
+ }
385
+
211
386
/// Conformance to `BidirectionalCollection`.
212
387
extension SyntaxCollection {
213
388
public func makeIterator( ) -> SyntaxCollectionIterator < Element > {
0 commit comments