Skip to content

Commit 5a02df8

Browse files
authored
Merge pull request #670 from ahoppen/ahoppen/four-quotes-recovery
Improve diagnostic generated for string literal consisting of four quotes
2 parents 114e16a + 862e33d commit 5a02df8

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

Sources/SwiftParser/Expressions.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,9 @@ extension Parser {
904904

905905
/// Parse open quote.
906906
let openQuote = self.parseStringLiteralQuote(
907-
at: openDelimiter != nil ? .leadingRaw : .leading, text: text)
907+
at: openDelimiter != nil ? .leadingRaw : .leading,
908+
text: text
909+
) ?? RawTokenSyntax(missing: .stringQuote, arena: arena)
908910
text = text.dropFirst(openQuote.tokenText.count)
909911

910912
/// Parse segments.
@@ -915,7 +917,8 @@ extension Parser {
915917
/// Parse close quote.
916918
let closeQuote = self.parseStringLiteralQuote(
917919
at: openDelimiter != nil ? .trailingRaw : .trailing,
918-
text: text[closeStart...])
920+
text: text[closeStart...]
921+
) ?? RawTokenSyntax(missing: openQuote.tokenKind, arena: arena)
919922
text = text.dropFirst(closeQuote.byteLength)
920923

921924
/// Parse closing raw string delimiter if exist.
@@ -1026,7 +1029,7 @@ extension Parser {
10261029
mutating func parseStringLiteralQuote(
10271030
at position: QuotePosition,
10281031
text: Slice<SyntaxText>
1029-
) -> RawTokenSyntax {
1032+
) -> RawTokenSyntax? {
10301033
// Single quote. We only support single line literal.
10311034
if let first = text.first, first == UInt8(ascii: "'") {
10321035
let index = text.index(after: text.startIndex)
@@ -1061,6 +1064,9 @@ extension Parser {
10611064
if position == .leadingRaw {
10621065
quoteCount = 1
10631066
index = text.index(text.startIndex, offsetBy: quoteCount)
1067+
} else if position == .leading {
1068+
quoteCount = 3
1069+
index = text.index(text.startIndex, offsetBy: quoteCount)
10641070
}
10651071
}
10661072

@@ -1075,7 +1081,7 @@ extension Parser {
10751081
.multilineStringQuote, text: text[..<index], at: position)
10761082
}
10771083
// Otherwise, this is not a literal quote.
1078-
return RawTokenSyntax(missing: .stringQuote, arena: arena)
1084+
return nil
10791085
}
10801086

10811087
/// Foo.

Tests/SwiftParserTest/Expressions.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -288,14 +288,31 @@ final class ExpressionTests: XCTestCase {
288288

289289
AssertParse(
290290
##"""
291-
#^D0^#""""#^D1^#
291+
""""#^DIAG^#
292292
"""##,
293293
diagnostics: [
294-
// FIXME: Weird diagnostics doesn't recover code even if follow it
295-
DiagnosticSpec(locationMarker: "D0", message: "Expected '\"' in expression"),
296-
DiagnosticSpec(locationMarker: "D1", message: "Expected '\"' in expression")
294+
// FIXME: This should say: Expected '"""' in string literal
295+
DiagnosticSpec(message: #"Expected '"""' in expression"#)
297296
]
298297
)
298+
299+
AssertParse(
300+
##"""
301+
"""""#^DIAG^#
302+
"""##,
303+
diagnostics: [
304+
// FIXME: This should say: Expected '"""' in string literal
305+
DiagnosticSpec(message: #"Expected '"""' in expression"#)
306+
]
307+
)
308+
309+
// FIXME: We currently don't enforce that multiline string literal
310+
// contents must start on a new line
311+
AssertParse(
312+
##"""
313+
""""""#^DIAG^#
314+
"""##
315+
)
299316
}
300317

301318
func testSingleQuoteStringLiteral() {

0 commit comments

Comments
 (0)