Skip to content

Commit 33a5ad4

Browse files
committed
Normalize line ending to \n in StringLiteralExprSyntax.representedLiteralValue
This matches the specification of multi-line string literal handling: From https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#String-Literals: > Line breaks in a multiline string literal are normalized to use the line feed character. Even if your source file has a mix of carriage returns and line feeds, all of the line breaks in the string will be the same. From https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170417/035923.html: > The quoted string should normalize newlines to \n in the value of the literal, regardless of whether the source file uses \n (Unix), \r\n (Windows), or \r (classic Mac) line endings. Likewise, when the compiler strips the initial and final newline from the literal value, it will strip one of any of the \n, \r\n, or \r line-ending sequences from both ends of the literal.
1 parent e3ea968 commit 33a5ad4

File tree

2 files changed

+15
-3
lines changed

2 files changed

+15
-3
lines changed

Diff for: Sources/SwiftParser/Lexer/Cursor.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1594,7 +1594,7 @@ extension Lexer.Cursor {
15941594
// MARK: Lexing a character in a string literal
15951595

15961596
extension Lexer.Cursor {
1597-
enum CharacterLex {
1597+
enum CharacterLex: Equatable {
15981598
/// A normal character as it occurs in the source file
15991599
case success(Unicode.Scalar)
16001600

Diff for: Sources/SwiftParser/StringLiteralRepresentedLiteralValue.swift

+14-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ extension StringSegmentSyntax {
8383
precondition(!hasError, "appendUnescapedLiteralValue relies on properly parsed literals")
8484

8585
let rawText = content.rawText
86-
if !rawText.contains("\\") {
87-
// Fast path. No escape sequence.
86+
if !rawText.contains(where: { $0 == "\\" || $0 == "\r" }) {
87+
// Fast path. No escape sequence that need to be interpreted or line endings that need to be normalized to \n.
8888
output.append(String(syntaxText: rawText))
8989
return
9090
}
@@ -105,6 +105,18 @@ extension StringSegmentSyntax {
105105
)
106106

107107
switch lex {
108+
case .success(Unicode.Scalar("\r")):
109+
// Line endings in multi-line string literals are normalized to line feeds even if the source file has a
110+
// different encoding for new lines.
111+
output.append("\n")
112+
if cursor.peek() == "\n" {
113+
// If we have \r\n, eat the \n as well and leave
114+
let consumed = cursor.lexCharacterInStringLiteral(
115+
stringLiteralKind: stringLiteralKind,
116+
delimiterLength: delimiterLength
117+
)
118+
assert(consumed == .success(Unicode.Scalar("\n")))
119+
}
108120
case .success(let scalar),
109121
.validatedEscapeSequence(let scalar):
110122
output.append(Character(scalar))

0 commit comments

Comments
 (0)