Skip to content

Commit 5c98b24

Browse files
authored
Merge pull request #1255 from ahoppen/ahoppen/multi-line-string-errors
Diagnose incorrect indentation in multi-line string literals
2 parents da8e48f + 0c2e50e commit 5c98b24

35 files changed

+2358
-314
lines changed

CodeGeneration/Sources/SyntaxSupport/Trivia.swift.gyb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ public class Trivia {
2626
public let isComment: Bool
2727

2828
public var lowerName: String { lowercaseFirstWord(name: name) }
29+
30+
public var enumCaseName: String {
31+
if self.isCollection {
32+
if lowerName == "backslash" {
33+
return "backslashes"
34+
} else {
35+
return "\(lowerName)s"
36+
}
37+
} else {
38+
return lowerName
39+
}
40+
}
2941

3042
public var charactersLen: Int { characters.count }
3143

CodeGeneration/Sources/SyntaxSupport/gyb_generated/Trivia.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ public class Trivia {
2121
public let isComment: Bool
2222

2323
public var lowerName: String { lowercaseFirstWord(name: name) }
24+
25+
public var enumCaseName: String {
26+
if self.isCollection {
27+
if lowerName == "backslash" {
28+
return "backslashes"
29+
} else {
30+
return "\(lowerName)s"
31+
}
32+
} else {
33+
return lowerName
34+
}
35+
}
2436

2537
public var charactersLen: Int { characters.count }
2638

@@ -122,6 +134,22 @@ public let TRIVIAS: [Trivia] = [
122134
Trivia(name: "DocBlockComment",
123135
comment: #"A documentation block comment, starting with '/**' and ending with '*/'."#,
124136
isComment: true),
137+
Trivia(name: "Backslash",
138+
comment: #"A backslash that is at the end of a line in a multi-line string literal to escape the newline."#,
139+
characters: [
140+
Character("\\")
141+
],
142+
swiftCharacters: [
143+
Character("\\")
144+
]),
145+
Trivia(name: "Pound",
146+
comment: #"A '#' that is at the end of a line in a multi-line string literal to escape the newline."#,
147+
characters: [
148+
Character("#")
149+
],
150+
swiftCharacters: [
151+
Character("#")
152+
]),
125153
Trivia(name: "UnexpectedText",
126154
comment: #"Any skipped unexpected text."#),
127155
Trivia(name: "Shebang",

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/TriviaFile.swift

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
3838
if trivia.isCollection {
3939
EnumCaseDeclSyntax("""
4040
/// \(raw: trivia.comment)
41-
case \(raw: trivia.lowerName)s(Int)
41+
case \(raw: trivia.enumCaseName)(Int)
4242
""")
4343

4444
} else {
4545
EnumCaseDeclSyntax("""
4646
/// \(raw: trivia.comment)
47-
case \(raw: trivia.lowerName)(String)
47+
case \(raw: trivia.enumCaseName)(String)
4848
""")
4949
}
5050
}
@@ -67,11 +67,11 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
6767
for trivia in TRIVIAS {
6868
if trivia.isCollection {
6969
let joined = trivia.characters.map { "\($0)" }.joined()
70-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)s(count):") {
70+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(count):") {
7171
FunctionCallExprSyntax("printRepeated(\(literal: joined), count: count)")
7272
}
7373
} else {
74-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)(text):") {
74+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(text):") {
7575
FunctionCallExprSyntax("target.write(text)")
7676
}
7777
}
@@ -89,12 +89,12 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
8989
SwitchStmtSyntax(expression: ExprSyntax("self")) {
9090
for trivia in TRIVIAS {
9191
if trivia.isCollection {
92-
SwitchCaseSyntax("case .\(raw: trivia.lowerName)s(let data):") {
93-
ReturnStmtSyntax(#"return "\#(raw: trivia.lowerName)s(\(data))""#)
92+
SwitchCaseSyntax("case .\(raw: trivia.enumCaseName)(let data):") {
93+
ReturnStmtSyntax(#"return "\#(raw: trivia.enumCaseName)(\(data))""#)
9494
}
9595
} else {
96-
SwitchCaseSyntax("case .\(raw: trivia.lowerName)(let name):") {
97-
ReturnStmtSyntax(#"return "\#(raw: trivia.lowerName)(\(name.debugDescription))""#)
96+
SwitchCaseSyntax("case .\(raw: trivia.enumCaseName)(let name):") {
97+
ReturnStmtSyntax(#"return "\#(raw: trivia.enumCaseName)(\(name.debugDescription))""#)
9898
}
9999
}
100100
}
@@ -127,8 +127,8 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
127127

128128
InitializerDeclSyntax("""
129129
/// Creates Trivia with the provided underlying pieces.
130-
public init(pieces: [TriviaPiece]) {
131-
self.pieces = pieces
130+
public init<S: Sequence>(pieces: S) where S.Element == TriviaPiece {
131+
self.pieces = Array(pieces)
132132
}
133133
""")
134134

@@ -173,24 +173,24 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
173173
let joined = trivia.characters.map { "\($0)" }.joined()
174174
FunctionDeclSyntax("""
175175
/// Returns a piece of trivia for some number of \(literal: joined) characters.
176-
public static func \(raw: trivia.lowerName)s(_ count: Int) -> Trivia {
177-
return [.\(raw: trivia.lowerName)s(count)]
176+
public static func \(raw: trivia.enumCaseName)(_ count: Int) -> Trivia {
177+
return [.\(raw: trivia.enumCaseName)(count)]
178178
}
179179
""")
180180

181181
VariableDeclSyntax("""
182182
/// Gets a piece of trivia for \(literal: joined) characters.
183183
public static var \(raw: trivia.lowerName): Trivia {
184-
return .\(raw: trivia.lowerName)s(1)
184+
return .\(raw: trivia.enumCaseName)(1)
185185
}
186186
""")
187187

188188

189189
} else {
190190
FunctionDeclSyntax("""
191191
/// Returns a piece of trivia for \(raw: trivia.name).
192-
public static func \(raw: trivia.lowerName)(_ text: String) -> Trivia {
193-
return [.\(raw: trivia.lowerName)(text)]
192+
public static func \(raw: trivia.enumCaseName)(_ text: String) -> Trivia {
193+
return [.\(raw: trivia.enumCaseName)(text)]
194194
}
195195
""")
196196
}
@@ -288,15 +288,15 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
288288
SwitchStmtSyntax(expression: ExprSyntax("self")) {
289289
for trivia in TRIVIAS {
290290
if trivia.isCollection {
291-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)s(count):") {
291+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(count):") {
292292
if trivia.charactersLen != 1 {
293293
ReturnStmtSyntax("return SourceLength(utf8Length: count * \(raw: trivia.charactersLen))")
294294
} else {
295295
ReturnStmtSyntax("return SourceLength(utf8Length: count)")
296296
}
297297
}
298298
} else {
299-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)(text):") {
299+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(text):") {
300300
ReturnStmtSyntax("return SourceLength(of: text)")
301301
}
302302
}
@@ -315,10 +315,10 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
315315
""") {
316316
for trivia in TRIVIAS {
317317
if trivia.isCollection {
318-
EnumCaseDeclSyntax(" case \(raw: trivia.lowerName)s(Int)")
318+
EnumCaseDeclSyntax(" case \(raw: trivia.enumCaseName)(Int)")
319319

320320
} else {
321-
EnumCaseDeclSyntax("case \(raw: trivia.lowerName)(SyntaxText)")
321+
EnumCaseDeclSyntax("case \(raw: trivia.enumCaseName)(SyntaxText)")
322322
}
323323
}
324324

@@ -328,12 +328,12 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
328328
SwitchStmtSyntax(expression: ExprSyntax("piece")) {
329329
for trivia in TRIVIAS {
330330
if trivia.isCollection {
331-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)s(count):") {
332-
ReturnStmtSyntax("return .\(raw: trivia.lowerName)s(count)")
331+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(count):") {
332+
ReturnStmtSyntax("return .\(raw: trivia.enumCaseName)(count)")
333333
}
334334
} else {
335-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)(text):") {
336-
ReturnStmtSyntax("return .\(raw: trivia.lowerName)(arena.intern(text))")
335+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(text):") {
336+
ReturnStmtSyntax("return .\(raw: trivia.enumCaseName)(arena.intern(text))")
337337
}
338338
}
339339
}
@@ -362,12 +362,12 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
362362
SwitchStmtSyntax(expression: ExprSyntax("raw")) {
363363
for trivia in TRIVIAS {
364364
if trivia.isCollection {
365-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)s(count):") {
366-
ExprSyntax("self = .\(raw: trivia.lowerName)s(count)")
365+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(count):") {
366+
ExprSyntax("self = .\(raw: trivia.enumCaseName)(count)")
367367
}
368368
} else {
369-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)(text):") {
370-
ExprSyntax("self = .\(raw: trivia.lowerName)(String(syntaxText: text))")
369+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(text):") {
370+
ExprSyntax("self = .\(raw: trivia.enumCaseName)(String(syntaxText: text))")
371371
}
372372
}
373373
}
@@ -383,15 +383,15 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
383383
SwitchStmtSyntax(expression: ExprSyntax("self")) {
384384
for trivia in TRIVIAS {
385385
if trivia.isCollection {
386-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)s(count):") {
386+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(count):") {
387387
if trivia.charactersLen != 1 {
388388
ReturnStmtSyntax("return count * \(raw: trivia.charactersLen)")
389389
} else {
390390
ReturnStmtSyntax("return count")
391391
}
392392
}
393393
} else {
394-
SwitchCaseSyntax("case let .\(raw: trivia.lowerName)(text):") {
394+
SwitchCaseSyntax("case let .\(raw: trivia.enumCaseName)(text):") {
395395
ReturnStmtSyntax("return text.count")
396396
}
397397
}
@@ -405,11 +405,11 @@ let triviaFile = SourceFileSyntax(leadingTrivia: .docLineComment(generateCopyrig
405405
SwitchStmtSyntax(expression: ExprSyntax("self")) {
406406
for trivia in TRIVIAS {
407407
if trivia.isCollection {
408-
SwitchCaseSyntax("case .\(raw: trivia.lowerName)s(_):") {
408+
SwitchCaseSyntax("case .\(raw: trivia.enumCaseName)(_):") {
409409
ReturnStmtSyntax("return nil")
410410
}
411411
} else {
412-
SwitchCaseSyntax("case .\(raw: trivia.lowerName)(let text):") {
412+
SwitchCaseSyntax("case .\(raw: trivia.enumCaseName)(let text):") {
413413
ReturnStmtSyntax("return text")
414414
}
415415
}

0 commit comments

Comments
 (0)