Skip to content

Commit c3cebd0

Browse files
committed
[Syntax] Fix TriviaPiece.isNewline
In Swift, only 'CR', 'LF', and 'CR+LF' are considered newline characters. `TriviaPiece.isNewline` should not return true for 'VT' and 'FF'. Instead of using 'Swift.Character.isNewline', introduce 'TriviaTraits' in CodeGeneration, and manually set them for each trivia piece kind.
1 parent fd232f9 commit c3cebd0

File tree

3 files changed

+127
-76
lines changed

3 files changed

+127
-76
lines changed

CodeGeneration/Sources/SyntaxSupport/Trivia.swift

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@
1212

1313
import SwiftSyntax
1414

15+
public struct TriviaTraits: OptionSet {
16+
public var rawValue: UInt8
17+
18+
public init(rawValue: UInt8) {
19+
self.rawValue = rawValue
20+
}
21+
22+
// Indicates this is a whitespace.
23+
public static var whitespace: Self { .init(rawValue: 1 << 0) }
24+
25+
// Indicates a newline in Swift source code.
26+
public static var newline: Self { .init(rawValue: 1 << 1) }
27+
28+
// Horizontal space.
29+
public static var spaceOrTab: Self { .init(rawValue: 1 << 2) }
30+
31+
// Comment in Swift source code.
32+
public static var comment: Self { .init(rawValue: 1 << 3) }
33+
}
34+
1535
public class Trivia {
1636
/// The name of the trivia.
1737
public let name: TokenSyntax
@@ -29,10 +49,8 @@ public class Trivia {
2949
/// This might differ from `characters` due to Swift's character escape requirements.
3050
public let swiftCharacters: [Character]
3151

32-
/// Indicates if the trivia represents a comment.
33-
///
34-
/// If `true`, the trivia is some form of a comment in the Swift code.
35-
public let isComment: Bool
52+
/// The traits.
53+
public let traits: TriviaTraits
3654

3755
/// The name of the trivia in lowercase.
3856
public var lowerName: TokenSyntax { .identifier(lowercaseFirstWord(name: name.text)) }
@@ -60,16 +78,6 @@ public class Trivia {
6078
/// If `true`, the trivia is made up of multiple characters.
6179
public var isCollection: Bool { charactersLen > 0 }
6280

63-
/// Indicates if the trivia contains only whitespace characters.
64-
public var isBlank: Bool {
65-
characters.contains { $0.isWhitespace }
66-
}
67-
68-
/// Indicates if the trivia contains newline characters.
69-
public var isNewLine: Bool {
70-
characters.contains { $0.isNewline }
71-
}
72-
7381
/// Initializes a new `Trivia` instance.
7482
///
7583
/// - Parameters:
@@ -83,12 +91,12 @@ public class Trivia {
8391
comment: SwiftSyntax.Trivia,
8492
characters: [Character] = [],
8593
swiftCharacters: [Character] = [],
86-
isComment: Bool = false
94+
traits: TriviaTraits = []
8795
) {
8896
self.name = name
8997
self.comment = comment
90-
self.isComment = isComment
9198
self.characters = characters
99+
self.traits = traits
92100

93101
// Swift sometimes doesn't support escaped characters like \f or \v;
94102
// we should allow specifying alternatives explicitly.
@@ -115,7 +123,7 @@ public let TRIVIAS: [Trivia] = [
115123
Trivia(
116124
name: "BlockComment",
117125
comment: #"A developer block comment, starting with '/*' and ending with '*/'."#,
118-
isComment: true
126+
traits: [.comment]
119127
),
120128

121129
Trivia(
@@ -126,7 +134,8 @@ public let TRIVIAS: [Trivia] = [
126134
],
127135
swiftCharacters: [
128136
Character("\r")
129-
]
137+
],
138+
traits: [.whitespace, .newline]
130139
),
131140

132141
Trivia(
@@ -139,19 +148,20 @@ public let TRIVIAS: [Trivia] = [
139148
swiftCharacters: [
140149
Character("\r"),
141150
Character("\n"),
142-
]
151+
],
152+
traits: [.whitespace, .newline]
143153
),
144154

145155
Trivia(
146156
name: "DocBlockComment",
147157
comment: #"A documentation block comment, starting with '/**' and ending with '*/'."#,
148-
isComment: true
158+
traits: [.comment]
149159
),
150160

151161
Trivia(
152162
name: "DocLineComment",
153163
comment: #"A documentation line comment, starting with '///' and excluding the trailing newline."#,
154-
isComment: true
164+
traits: [.comment]
155165
),
156166

157167
// Swift don't support form feed '\f' so we use the raw unicode
@@ -163,13 +173,14 @@ public let TRIVIAS: [Trivia] = [
163173
],
164174
swiftCharacters: [
165175
Character("\u{240C}")
166-
]
176+
],
177+
traits: [.whitespace]
167178
),
168179

169180
Trivia(
170181
name: "LineComment",
171182
comment: #"A developer line comment, starting with '//' and excluding the trailing newline."#,
172-
isComment: true
183+
traits: [.comment]
173184
),
174185

175186
Trivia(
@@ -180,7 +191,8 @@ public let TRIVIAS: [Trivia] = [
180191
],
181192
swiftCharacters: [
182193
Character("\n")
183-
]
194+
],
195+
traits: [.whitespace, .newline]
184196
),
185197

186198
Trivia(
@@ -202,7 +214,8 @@ public let TRIVIAS: [Trivia] = [
202214
],
203215
swiftCharacters: [
204216
Character(" ")
205-
]
217+
],
218+
traits: [.whitespace, .spaceOrTab]
206219
),
207220

208221
Trivia(
@@ -213,7 +226,8 @@ public let TRIVIAS: [Trivia] = [
213226
],
214227
swiftCharacters: [
215228
Character("\t")
216-
]
229+
],
230+
traits: [.whitespace, .spaceOrTab]
217231
),
218232

219233
Trivia(
@@ -230,6 +244,7 @@ public let TRIVIAS: [Trivia] = [
230244
],
231245
swiftCharacters: [
232246
Character("\u{2B7F}")
233-
]
247+
],
248+
traits: [.whitespace]
234249
),
235250
]

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/TriviaPiecesFile.swift

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -271,58 +271,52 @@ let triviaPiecesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
271271
}
272272

273273
fileprivate func generateIsHelpers(for pieceName: TokenSyntax) throws -> ExtensionDeclSyntax {
274-
return try ExtensionDeclSyntax("extension \(pieceName)") {
275-
DeclSyntax(
276-
"""
277-
/// Returns `true` if this piece is a newline, space or tab.
278-
public var isWhitespace: Bool {
279-
return isSpaceOrTab || isNewline
280-
}
281-
"""
282-
)
283-
284-
try VariableDeclSyntax("public var isNewline: Bool") {
274+
func generateHelper(_ header: SyntaxNodeString, trait: TriviaTraits) throws -> VariableDeclSyntax {
275+
try VariableDeclSyntax(header) {
285276
try SwitchExprSyntax("switch self") {
286-
for trivia in TRIVIAS {
287-
if trivia.isNewLine {
288-
SwitchCaseSyntax("case .\(trivia.enumCaseName):") {
289-
StmtSyntax("return true")
290-
}
277+
for trivia in TRIVIAS where trivia.traits.contains(trait) {
278+
SwitchCaseSyntax("case .\(trivia.enumCaseName):") {
279+
StmtSyntax("return true")
291280
}
292281
}
293282
SwitchCaseSyntax("default:") {
294283
StmtSyntax("return false")
295284
}
296285
}
297286
}
287+
}
288+
289+
return try ExtensionDeclSyntax("extension \(pieceName)") {
290+
try generateHelper(
291+
"""
292+
/// Returns `true` if this piece is a whitespace.
293+
public var isWhitespace: Bool
294+
""",
295+
trait: .whitespace
296+
)
298297

299-
DeclSyntax(
298+
try generateHelper(
300299
"""
301-
public var isSpaceOrTab: Bool {
302-
switch self {
303-
case .spaces:
304-
return true
305-
case .tabs:
306-
return true
307-
default:
308-
return false
309-
}
310-
}
300+
/// Returns `true` if this piece is a newline.
301+
public var isNewline: Bool
302+
""",
303+
trait: .newline
304+
)
305+
306+
try generateHelper(
311307
"""
308+
/// Returns `true` if this piece is a space or tab.
309+
public var isSpaceOrTab: Bool
310+
""",
311+
trait: .spaceOrTab
312312
)
313313

314-
DeclSyntax(
314+
try generateHelper(
315315
"""
316316
/// Returns `true` if this piece is a comment.
317-
public var isComment: Bool {
318-
switch self {
319-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
320-
return true
321-
default:
322-
return false
323-
}
324-
}
325-
"""
317+
public var isComment: Bool
318+
""",
319+
trait: .comment
326320
)
327321
}
328322
}

Sources/SwiftSyntax/generated/TriviaPieces.swift

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -443,12 +443,8 @@ extension RawTriviaPiece {
443443
}
444444

445445
extension TriviaPiece {
446-
/// Returns `true` if this piece is a newline, space or tab.
446+
/// Returns `true` if this piece is a whitespace.
447447
public var isWhitespace: Bool {
448-
return isSpaceOrTab || isNewline
449-
}
450-
451-
public var isNewline: Bool {
452448
switch self {
453449
case .carriageReturns:
454450
return true
@@ -458,13 +454,32 @@ extension TriviaPiece {
458454
return true
459455
case .newlines:
460456
return true
457+
case .spaces:
458+
return true
459+
case .tabs:
460+
return true
461461
case .verticalTabs:
462462
return true
463463
default:
464464
return false
465465
}
466466
}
467467

468+
/// Returns `true` if this piece is a newline.
469+
public var isNewline: Bool {
470+
switch self {
471+
case .carriageReturns:
472+
return true
473+
case .carriageReturnLineFeeds:
474+
return true
475+
case .newlines:
476+
return true
477+
default:
478+
return false
479+
}
480+
}
481+
482+
/// Returns `true` if this piece is a space or tab.
468483
public var isSpaceOrTab: Bool {
469484
switch self {
470485
case .spaces:
@@ -479,7 +494,13 @@ extension TriviaPiece {
479494
/// Returns `true` if this piece is a comment.
480495
public var isComment: Bool {
481496
switch self {
482-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
497+
case .blockComment:
498+
return true
499+
case .docBlockComment:
500+
return true
501+
case .docLineComment:
502+
return true
503+
case .lineComment:
483504
return true
484505
default:
485506
return false
@@ -488,12 +509,8 @@ extension TriviaPiece {
488509
}
489510

490511
extension RawTriviaPiece {
491-
/// Returns `true` if this piece is a newline, space or tab.
512+
/// Returns `true` if this piece is a whitespace.
492513
public var isWhitespace: Bool {
493-
return isSpaceOrTab || isNewline
494-
}
495-
496-
public var isNewline: Bool {
497514
switch self {
498515
case .carriageReturns:
499516
return true
@@ -503,13 +520,32 @@ extension RawTriviaPiece {
503520
return true
504521
case .newlines:
505522
return true
523+
case .spaces:
524+
return true
525+
case .tabs:
526+
return true
506527
case .verticalTabs:
507528
return true
508529
default:
509530
return false
510531
}
511532
}
512533

534+
/// Returns `true` if this piece is a newline.
535+
public var isNewline: Bool {
536+
switch self {
537+
case .carriageReturns:
538+
return true
539+
case .carriageReturnLineFeeds:
540+
return true
541+
case .newlines:
542+
return true
543+
default:
544+
return false
545+
}
546+
}
547+
548+
/// Returns `true` if this piece is a space or tab.
513549
public var isSpaceOrTab: Bool {
514550
switch self {
515551
case .spaces:
@@ -524,7 +560,13 @@ extension RawTriviaPiece {
524560
/// Returns `true` if this piece is a comment.
525561
public var isComment: Bool {
526562
switch self {
527-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
563+
case .blockComment:
564+
return true
565+
case .docBlockComment:
566+
return true
567+
case .docLineComment:
568+
return true
569+
case .lineComment:
528570
return true
529571
default:
530572
return false

0 commit comments

Comments
 (0)