@@ -25,40 +25,62 @@ 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 merging in the given trivia. Only includes one
57
+ /// copy of a common prefix of `self` and `trivia`.
58
+ public func merging( _ trivia: Trivia ) -> Trivia {
59
+ let lhs = self . decomposed
60
+ let rhs = trivia. decomposed
61
+ for infixLength in ( 0 ... Swift . min ( lhs. count, rhs. count) ) . reversed ( ) {
62
+ if lhs. suffix ( infixLength) == rhs. suffix ( infixLength) {
63
+ return lhs. appending ( Trivia ( pieces: Array ( rhs. dropFirst ( infixLength) ) ) )
64
+ }
65
+ }
66
+ return lhs. appending ( rhs)
67
+ }
68
+
69
+ /// Creates a new `Trivia` by merging the leading and trailing `Trivia`
70
+ /// of `triviaOf` into the end of `self`. Only includes one copy of any
71
+ /// common prefixes.
72
+ public func merging< T: SyntaxProtocol > ( triviaOf node: T ) -> Trivia {
73
+ return merging ( node. leadingTrivia) . merging ( node. trailingTrivia)
52
74
}
53
75
54
76
/// 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 )
77
+ public static func + ( lhs: Trivia , rhs: Trivia ) -> Trivia {
78
+ return lhs. appending ( rhs)
57
79
}
58
80
59
81
/// Concatenates two collections of `Trivia` into the left-hand side.
60
- public static func += ( lhs: inout Trivia , rhs: Trivia ) {
61
- lhs = lhs + rhs
82
+ public static func += ( lhs: inout Trivia , rhs: Trivia ) {
83
+ lhs = lhs. appending ( rhs)
62
84
}
63
85
}
64
86
@@ -118,13 +140,45 @@ extension Trivia: CustomDebugStringConvertible {
118
140
}
119
141
}
120
142
143
+ extension Trivia {
144
+ /// Decomposes the trivia into pieces that all have count 1
145
+ @_spi ( RawSyntax)
146
+ public var decomposed : Trivia {
147
+ let pieces = self . flatMap ( { ( piece: TriviaPiece ) -> [ TriviaPiece ] in
148
+ switch piece {
149
+ case . spaces( let count) :
150
+ return Array ( repeating: TriviaPiece . spaces ( 1 ) , count: count)
151
+ case . tabs( let count) :
152
+ return Array ( repeating: TriviaPiece . tabs ( 1 ) , count: count)
153
+ case . verticalTabs( let count) :
154
+ return Array ( repeating: TriviaPiece . verticalTabs ( 1 ) , count: count)
155
+ case . formfeeds( let count) :
156
+ return Array ( repeating: TriviaPiece . formfeeds ( 1 ) , count: count)
157
+ case . newlines( let count) :
158
+ return Array ( repeating: TriviaPiece . newlines ( 1 ) , count: count)
159
+ case . backslashes( let count) :
160
+ return Array ( repeating: TriviaPiece . backslashes ( 1 ) , count: count)
161
+ case . pounds( let count) :
162
+ return Array ( repeating: TriviaPiece . pounds ( 1 ) , count: count)
163
+ case . carriageReturns( let count) :
164
+ return Array ( repeating: TriviaPiece . carriageReturns ( 1 ) , count: count)
165
+ case . carriageReturnLineFeeds( let count) :
166
+ return Array ( repeating: TriviaPiece . carriageReturnLineFeeds ( 1 ) , count: count)
167
+ case . lineComment, . blockComment, . docLineComment, . docBlockComment, . unexpectedText, . shebang:
168
+ return [ piece]
169
+ }
170
+ } )
171
+ return Trivia ( pieces: pieces)
172
+ }
173
+ }
174
+
121
175
extension TriviaPiece {
122
176
/// Returns true if the trivia is `.newlines`, `.carriageReturns` or `.carriageReturnLineFeeds`
123
177
public var isNewline : Bool {
124
178
switch self {
125
179
case . newlines,
126
- . carriageReturns,
127
- . carriageReturnLineFeeds:
180
+ . carriageReturns,
181
+ . carriageReturnLineFeeds:
128
182
return true
129
183
default :
130
184
return false
@@ -137,8 +191,8 @@ extension RawTriviaPiece {
137
191
public var isNewline : Bool {
138
192
switch self {
139
193
case . newlines,
140
- . carriageReturns,
141
- . carriageReturnLineFeeds:
194
+ . carriageReturns,
195
+ . carriageReturnLineFeeds:
142
196
return true
143
197
default :
144
198
return false
0 commit comments