Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow $ escaping double quotes in interpolations #9536

Merged
merged 2 commits into from Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 6 additions & 4 deletions spec/01-lexical-syntax.md
Expand Up @@ -503,9 +503,10 @@ not processed, except for Unicode escapes.
#### Interpolated string

```ebnf
interpolatedString ::= alphaid ‘"’ {printableChar \ (‘"’ | ‘$’) | escape} ‘"’
interpolatedString ::= alphaid ‘"’ {printableChar \ (‘"’ | ‘$’) | escape} ‘"’
| alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘$’) | escape} {‘"’} ‘"""’
escape ::= ‘$$’
escape ::= ‘$$’
| ‘$"’
| ‘$’ id
| ‘$’ BlockExpr
alphaid ::= upper idrest
Expand All @@ -522,13 +523,14 @@ or multi-line (triple quote).
Inside a interpolated string none of the usual escape characters are interpreted
(except for unicode escapes) no matter whether the string literal is normal
(enclosed in single quotes) or multi-line (enclosed in triple quotes).
Instead, there are two new forms of dollar sign escape.
Instead, there are three new forms of dollar sign escape.
The most general form encloses an expression in `${` and `}`, i.e. `${expr}`.
The expression enclosed in the braces that follow the leading `$` character is of
syntactical category BlockExpr. Hence, it can contain multiple statements,
and newlines are significant. Single ‘$’-signs are not permitted in isolation
in a interpolated string. A single ‘$’-sign can still be obtained by doubling the ‘$’
character: ‘$$’.
character: ‘$$’. A single ‘"’-sign in a single quoted interpolation would end the
interpolation. A single ‘"’-sign can be obtained by the sequence ‘\$"’.

The simpler form consists of a ‘$’-sign followed by an identifier starting with
a letter and followed only by letters, digits, and underscore characters,
Expand Down
5 changes: 3 additions & 2 deletions spec/13-syntax-summary.md
Expand Up @@ -63,8 +63,9 @@ multiLineChars ::= {[‘"’] [‘"’] charNoDoubleQuote} {‘"’}
interpolatedString
::= alphaid ‘"’ {printableChar \ (‘"’ | ‘\$’) | escape} ‘"’
| alphaid ‘"""’ {[‘"’] [‘"’] char \ (‘"’ | ‘\$’) | escape} {‘"’} ‘"""’
escape ::= ‘\$\$’
| ‘\$’ id
escape ::= ‘\$\$’
| ‘\$"’
| ‘\$’ id
| ‘\$’ BlockExpr
alphaid ::= upper idrest
| varid
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
Expand Up @@ -912,7 +912,7 @@ trait Scanners extends ScannersCommon {
}
} else if (ch == '$') {
nextRawChar()
if (ch == '$') {
if (ch == '$' || ch == '"') {
putChar(ch)
nextRawChar()
getStringPart(multiLine)
Expand All @@ -938,7 +938,8 @@ trait Scanners extends ScannersCommon {
next.token = kwArray(idx)
}
} else {
syntaxError(s"invalid string interpolation $$$ch, expected: $$$$, $$identifier or $${expression}")
val expectations = "$$, $\", $identifier or ${expression}"
syntaxError(s"invalid string interpolation $$$ch, expected: $expectations")
}
} else {
val isUnclosedLiteral = (ch == SU || (!multiLine && (ch == CR || ch == LF)))
Expand Down
7 changes: 2 additions & 5 deletions test/files/neg/t5856.check
@@ -1,9 +1,6 @@
t5856.scala:10: error: invalid string interpolation $", expected: $$, $identifier or ${expression}
val s9 = s"$"
^
t5856.scala:10: error: unclosed string literal
val s9 = s"$"
^
^
t5856.scala:2: error: error in interpolated string: identifier or block expected
val s1 = s"$null"
^
Expand All @@ -28,4 +25,4 @@ t5856.scala:8: error: error in interpolated string: identifier or block expected
t5856.scala:9: error: error in interpolated string: identifier or block expected
val s8 = s"$super"
^
10 errors
9 errors
6 changes: 6 additions & 0 deletions test/files/run/interpolation.check
Expand Up @@ -30,3 +30,9 @@ Best price: 13.35

0
00
"everybody loves escaped quotes" is a common sentiment.
hi"$"
hi"$"
hi"$"
hi"$"
hi"$"
8 changes: 8 additions & 0 deletions test/files/run/interpolation.scala
Expand Up @@ -29,4 +29,12 @@ object Test extends App {
println(f"")
println(f"${0}")
println(f"${0}${0}")

println(s"$"everybody loves escaped quotes$" is a common sentiment.")
println(f"hi$"$$$"")
println(raw"hi$"$$$"")

println(s"""hi$"$$$"""")
println(f"""hi$"$$$"""")
println(raw"""hi$"$$$"""")
}