Skip to content

Commit 0958eb3

Browse files
committed
Allow \" in single-quoted interpolated string literals
`\"` no longer closes single-quoted interpolated string literals. The escape sequence is not processed by the scanner.
1 parent 77b0ae0 commit 0958eb3

File tree

8 files changed

+71
-3
lines changed

8 files changed

+71
-3
lines changed

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ object Scanners {
10531053
getRawStringLit()
10541054
}
10551055

1056+
// for interpolated strings
10561057
@annotation.tailrec private def getStringPart(multiLine: Boolean): Unit =
10571058
if (ch == '"')
10581059
if (multiLine) {
@@ -1069,6 +1070,14 @@ object Scanners {
10691070
setStrVal()
10701071
token = STRINGLIT
10711072
}
1073+
else if (ch == '\\' && !multiLine) {
1074+
putChar(ch)
1075+
nextRawChar()
1076+
if (ch == '"' || ch == '\\')
1077+
putChar(ch)
1078+
nextRawChar()
1079+
getStringPart(multiLine)
1080+
}
10721081
else if (ch == '$') {
10731082
nextRawChar()
10741083
if (ch == '$' || ch == '"') {

docs/docs/internals/syntax-3.1.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ stringElement ::= printableChar \ (‘"’ | ‘\’)
7070
| charEscapeSeq
7171
multiLineChars ::= {[‘"’] [‘"’] char \ ‘"’} {‘"’}
7272
processedStringLiteral
73-
::= alphaid ‘"’ {printableChar \ (‘"’ | ‘$’) | escape} ‘"’
73+
::= alphaid ‘"’ {[‘\’] interpolatedStringPart | ‘\\’ | ‘\"’} ‘"’
7474
| alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’
75+
interpolatedStringPart
76+
::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape
7577
escape ::= ‘$$’
7678
| ‘$’ letter { letter | digit }
7779
| ‘{’ Block [‘;’ whiteSpace stringFormat whiteSpace] ‘}’

docs/docs/internals/syntax.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ stringElement ::= printableChar \ (‘"’ | ‘\’)
6969
| charEscapeSeq
7070
multiLineChars ::= {[‘"’] [‘"’] char \ ‘"’} {‘"’}
7171
processedStringLiteral
72-
::= alphaid ‘"’ {printableChar \ (‘"’ | ‘$’) | escape} ‘"’
72+
::= alphaid ‘"’ {[‘\’] interpolatedStringPart | ‘\\’ | ‘\"’} ‘"’
7373
| alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’
74+
interpolatedStringPart
75+
::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape
7476
escape ::= ‘$$’
7577
| ‘$’ letter { letter | digit }
7678
| ‘{’ Block [‘;’ whiteSpace stringFormat whiteSpace] ‘}’

docs/docs/reference/syntax.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ stringElement ::= printableChar \ (‘"’ | ‘\’)
6969
| charEscapeSeq
7070
multiLineChars ::= {[‘"’] [‘"’] char \ ‘"’} {‘"’}
7171
processedStringLiteral
72-
::= alphaid ‘"’ {printableChar \ (‘"’ | ‘$’) | escape} ‘"’
72+
::= alphaid ‘"’ {[‘\’] interpolatedStringPart | ‘\\’ | ‘\"’} ‘"’
7373
| alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’
74+
interpolatedStringPart
75+
::= printableChar \ (‘"’ | ‘$’ | ‘\’) | escape
7476
escape ::= ‘$$’
7577
| ‘$’ letter { letter | digit }
7678
| ‘{’ Block [‘;’ whiteSpace stringFormat whiteSpace] ‘}’

tests/neg/t6476.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// only the last one doesn't parse
2+
class C {
3+
s"""\ """
4+
s"""\\"""
5+
s"""\"""
6+
s"\ "
7+
s"\\"
8+
s"\" // error
9+
} // error (should not be one)

tests/neg/t6476b.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class C {
2+
val sa = s"""\""" // error: invalid escape
3+
val sb = s"""\\"""
4+
val sc = s"""\ """ // error: invalid escape
5+
val ra = raw"""\"""
6+
val rb = raw"""\\"""
7+
val rc = raw"""\ """
8+
}

tests/run/t6476.check

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"Hello", Alice
2+
"Hello", Alice
3+
\"Hello\", Alice
4+
\"Hello\", Alice
5+
\"Hello\", Alice
6+
\"Hello\", Alice
7+
\TILT\
8+
\\TILT\\
9+
\\TILT\\
10+
\TILT\
11+
\\TILT\\
12+
\\TILT\\
13+
\TILT\

tests/run/t6476.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
val person = "Alice"
4+
println(s"\"Hello\", $person")
5+
println(s"""\"Hello\", $person""")
6+
7+
println(f"\"Hello\", $person")
8+
println(f"""\"Hello\", $person""")
9+
10+
println(raw"\"Hello\", $person")
11+
println(raw"""\"Hello\", $person""")
12+
13+
println(s"\\TILT\\")
14+
println(f"\\TILT\\")
15+
println(raw"\\TILT\\")
16+
17+
println(s"""\\TILT\\""")
18+
println(f"""\\TILT\\""")
19+
println(raw"""\\TILT\\""")
20+
21+
println(raw"""\TILT\""")
22+
}
23+
}

0 commit comments

Comments
 (0)