@@ -25,40 +25,60 @@ public struct Trivia {
25
25
self . pieces = Array ( pieces)
26
26
}
27
27
28
- /// Creates Trivia with no pieces.
29
- public static var zero : Trivia {
30
- return Trivia ( pieces: [ ] )
31
- }
32
-
33
28
/// Whether the Trivia contains no pieces.
34
29
public var isEmpty : Bool {
35
30
pieces. isEmpty
36
31
}
37
32
33
+ public var sourceLength : SourceLength {
34
+ return pieces. map ( { $0. sourceLength } ) . reduce ( . zero, + )
35
+ }
36
+
37
+ /// Get the byteSize of this trivia
38
+ public var byteSize : Int {
39
+ return sourceLength. utf8Length
40
+ }
41
+
38
42
/// Creates a new `Trivia` by appending the provided `TriviaPiece` to the end.
39
43
public func appending( _ piece: TriviaPiece ) -> Trivia {
40
44
var copy = pieces
41
45
copy. append ( piece)
42
46
return Trivia ( pieces: copy)
43
47
}
44
48
45
- public var sourceLength : SourceLength {
46
- return pieces. map ( { $0. sourceLength } ) . reduce ( . zero, + )
49
+ /// Creates a new `Trivia` by appending the given trivia to the end.
50
+ public func appending( _ trivia: Trivia ) -> Trivia {
51
+ var copy = pieces
52
+ copy. append ( contentsOf: trivia. pieces)
53
+ return Trivia ( pieces: copy)
47
54
}
48
55
49
- /// Get the byteSize of this trivia
50
- public var byteSize : Int {
51
- return sourceLength. utf8Length
56
+ /// Creates a new `Trivia` by appending the given trivia to the end.
57
+ public func merging( _ trivia: Trivia ) -> Trivia {
58
+ let lhs = self . decomposed
59
+ let rhs = trivia. decomposed
60
+ for infixLength in ( 0 ... Swift . min ( lhs. count, rhs. count) ) . reversed ( ) {
61
+ if lhs. suffix ( infixLength) == rhs. suffix ( infixLength) {
62
+ return lhs. appending ( Trivia ( pieces: Array ( rhs. dropFirst ( infixLength) ) ) )
63
+ }
64
+ }
65
+ return lhs. appending ( rhs)
66
+ }
67
+
68
+ /// Creates a new `Trivia` by merging the leading and trailing `Trivia`
69
+ /// of `triviaOf` to the end, .
70
+ public func merging< T: SyntaxProtocol > ( triviaOf node: T ) -> Trivia {
71
+ return merging ( node. leadingTrivia) . merging ( node. trailingTrivia)
52
72
}
53
73
54
74
/// Concatenates two collections of `Trivia` into one collection.
55
- public static func + ( lhs: Trivia , rhs: Trivia ) -> Trivia {
56
- return Trivia ( pieces : lhs. pieces + rhs. pieces )
75
+ public static func + ( lhs: Trivia , rhs: Trivia ) -> Trivia {
76
+ return lhs. appending ( rhs)
57
77
}
58
78
59
79
/// Concatenates two collections of `Trivia` into the left-hand side.
60
- public static func += ( lhs: inout Trivia , rhs: Trivia ) {
61
- lhs = lhs + rhs
80
+ public static func += ( lhs: inout Trivia , rhs: Trivia ) {
81
+ lhs = lhs. appending ( rhs)
62
82
}
63
83
}
64
84
@@ -118,13 +138,45 @@ extension Trivia: CustomDebugStringConvertible {
118
138
}
119
139
}
120
140
141
+ extension Trivia {
142
+ /// Decomposes the trivia into pieces that all have count 1
143
+ @_spi ( RawSyntax)
144
+ public var decomposed : Trivia {
145
+ let pieces = self . flatMap ( { ( piece: TriviaPiece ) -> [ TriviaPiece ] in
146
+ switch piece {
147
+ case . spaces( let count) :
148
+ return Array ( repeating: TriviaPiece . spaces ( 1 ) , count: count)
149
+ case . tabs( let count) :
150
+ return Array ( repeating: TriviaPiece . tabs ( 1 ) , count: count)
151
+ case . verticalTabs( let count) :
152
+ return Array ( repeating: TriviaPiece . verticalTabs ( 1 ) , count: count)
153
+ case . formfeeds( let count) :
154
+ return Array ( repeating: TriviaPiece . formfeeds ( 1 ) , count: count)
155
+ case . newlines( let count) :
156
+ return Array ( repeating: TriviaPiece . newlines ( 1 ) , count: count)
157
+ case . backslashes( let count) :
158
+ return Array ( repeating: TriviaPiece . backslashes ( 1 ) , count: count)
159
+ case . pounds( let count) :
160
+ return Array ( repeating: TriviaPiece . pounds ( 1 ) , count: count)
161
+ case . carriageReturns( let count) :
162
+ return Array ( repeating: TriviaPiece . carriageReturns ( 1 ) , count: count)
163
+ case . carriageReturnLineFeeds( let count) :
164
+ return Array ( repeating: TriviaPiece . carriageReturnLineFeeds ( 1 ) , count: count)
165
+ case . lineComment, . blockComment, . docLineComment, . docBlockComment, . unexpectedText, . shebang:
166
+ return [ piece]
167
+ }
168
+ } )
169
+ return Trivia ( pieces: pieces)
170
+ }
171
+ }
172
+
121
173
extension TriviaPiece {
122
174
/// Returns true if the trivia is `.newlines`, `.carriageReturns` or `.carriageReturnLineFeeds`
123
175
public var isNewline : Bool {
124
176
switch self {
125
177
case . newlines,
126
- . carriageReturns,
127
- . carriageReturnLineFeeds:
178
+ . carriageReturns,
179
+ . carriageReturnLineFeeds:
128
180
return true
129
181
default :
130
182
return false
@@ -137,8 +189,8 @@ extension RawTriviaPiece {
137
189
public var isNewline : Bool {
138
190
switch self {
139
191
case . newlines,
140
- . carriageReturns,
141
- . carriageReturnLineFeeds:
192
+ . carriageReturns,
193
+ . carriageReturnLineFeeds:
142
194
return true
143
195
default :
144
196
return false
0 commit comments