Skip to content

Commit 57d5eab

Browse files
committed
Allow empty lines without indenation in multi-line string literals
1 parent 84c1a2b commit 57d5eab

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

Sources/SwiftParser/StringLiterals.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ extension Parser {
210210
segment.unexpectedAfterContent,
211211
arena: self.arena
212212
)
213+
} else if segment.content.tokenText == "" || segment.content.tokenText.triviaPieceIfNewline != nil {
214+
// Empty lines don't need to be indented and there's no indentation we need to strip away.
213215
} else {
214216
let actualIndentation = segment.content.tokenText.prefix(while: { $0 == UInt8(ascii: " ") || $0 == UInt8(ascii: "\t") })
215217
let actualIndentationTrivia = TriviaParser.parseTrivia(SyntaxText(rebasing: actualIndentation), position: .leading)

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,76 @@ final class ExpressionTests: XCTestCase {
10041004
"""#
10051005
)
10061006
}
1007+
1008+
func testEmptyLineInMultilineStringLiteral() {
1009+
AssertParse(
1010+
#"""
1011+
"""
1012+
line 1
1013+
1014+
line 2
1015+
"""
1016+
"""#,
1017+
substructure: Syntax(
1018+
StringLiteralExprSyntax(
1019+
openDelimiter: nil,
1020+
openQuote: .multilineStringQuoteToken(leadingTrivia: [.spaces(2)], trailingTrivia: .newline),
1021+
segments: StringLiteralSegmentsSyntax([
1022+
.stringSegment(StringSegmentSyntax(content: .stringSegment("line 1\n", leadingTrivia: [.spaces(2)]))),
1023+
.stringSegment(StringSegmentSyntax(content: .stringSegment("\n"))),
1024+
.stringSegment(StringSegmentSyntax(content: .stringSegment("line 2", leadingTrivia: [.spaces(2)], trailingTrivia: .newline))),
1025+
]),
1026+
closeQuote: .multilineStringQuoteToken(leadingTrivia: [.spaces(2)]),
1027+
closeDelimiter: nil
1028+
)
1029+
),
1030+
options: [.substructureCheckTrivia]
1031+
)
1032+
1033+
AssertParse(
1034+
#"""
1035+
"""
1036+
line 1
1037+
1038+
"""
1039+
"""#,
1040+
substructure: Syntax(
1041+
StringLiteralExprSyntax(
1042+
openDelimiter: nil,
1043+
openQuote: .multilineStringQuoteToken(leadingTrivia: [.spaces(2)], trailingTrivia: .newline),
1044+
segments: StringLiteralSegmentsSyntax([
1045+
.stringSegment(StringSegmentSyntax(content: .stringSegment("line 1\n", leadingTrivia: [.spaces(2)]))),
1046+
.stringSegment(StringSegmentSyntax(content: .stringSegment("", trailingTrivia: .newline))),
1047+
]),
1048+
closeQuote: .multilineStringQuoteToken(leadingTrivia: [.spaces(2)]),
1049+
closeDelimiter: nil
1050+
)
1051+
),
1052+
options: [.substructureCheckTrivia]
1053+
)
1054+
}
1055+
1056+
func testUnderIndentedWhitespaceonlyLineInMultilineStringLiteral() {
1057+
AssertParse(
1058+
#"""
1059+
"""
1060+
line 1
1061+
1️⃣
1062+
line 2
1063+
"""
1064+
"""#,
1065+
diagnostics: [
1066+
DiagnosticSpec(message: "insufficient indentation of line in multi-line string literal")
1067+
],
1068+
fixedSource: #"""
1069+
"""
1070+
line 1
1071+
\#(" ")
1072+
line 2
1073+
"""
1074+
"""#
1075+
)
1076+
}
10071077
}
10081078

10091079
final class MemberExprTests: XCTestCase {

0 commit comments

Comments
 (0)