Skip to content

Commit

Permalink
handle trailing escapes
Browse files Browse the repository at this point in the history
  • Loading branch information
Martijn Hoekstra committed Aug 6, 2019
1 parent c403dca commit dbb8483
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 22 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Expand Up @@ -94,7 +94,7 @@ val mimaFilterSettings = Seq(
ProblemFilters.exclude[MissingClassProblem]("scala.reflect.runtime.JavaMirrors$JavaMirror$typeTagCache$"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.TypeTags.TypeTagImpl"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.api.Universe.TypeTagImpl"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.StringContext.processUnicode")
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.StringContext.processUnicode"),
ProblemFilters.exclude[MissingClassProblem]("scala.StringContext$InvalidUnicodeEscapeException")
),
)
Expand Down
40 changes: 24 additions & 16 deletions src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
Expand Up @@ -907,41 +907,49 @@ trait Scanners extends ScannersCommon {
syntaxError(start, s"octal escape literals are unsupported: use $alt instead")
putChar(oct.toChar)
} else {
ch match {
case 'b' => putChar('\b')
case 't' => putChar('\t')
case 'n' => putChar('\n')
case 'f' => putChar('\f')
case 'r' => putChar('\r')
case '\"' => putChar('\"')
case '\'' => putChar('\'')
case '\\' => putChar('\\')
case 'u' => getUEscape()
case _ => invalidEscape()
if (ch == 'u') {
if (getUEscape()) nextChar()
}
else {
ch match {
case 'b' => putChar('\b')
case 't' => putChar('\t')
case 'n' => putChar('\n')
case 'f' => putChar('\f')
case 'r' => putChar('\r')
case '\"' => putChar('\"')
case '\'' => putChar('\'')
case '\\' => putChar('\\')
case _ => invalidEscape()
}
nextChar()
}
nextChar()
}
} else {
putChar(ch)
nextChar()
}

private def getUEscape(): Unit = {
private def getUEscape(): Boolean = {
while (ch == 'u') nextChar()
var codepoint = 0
var digitsRead = 0
while(digitsRead < 4){
while (digitsRead < 4) {
if (digitsRead > 0) nextChar()
val digit = digit2int(ch, 16)
digitsRead += 1
if (digit >= 0) {
codepoint = codepoint << 4
codepoint += digit
}
else invalidUnicodeEscape(digitsRead)
else {
invalidUnicodeEscape(digitsRead)
return false
}
}
val found = codepoint.asInstanceOf[Char]
putChar(found)
true
}


Expand All @@ -951,7 +959,7 @@ trait Scanners extends ScannersCommon {
}

protected def invalidUnicodeEscape(n: Int): Unit = {
syntaxError(charOffset -n, "invalid unicode escape")
syntaxError(charOffset - n, "invalid unicode escape")
putChar(ch)
}

Expand Down
2 changes: 2 additions & 0 deletions src/library/scala/StringContext.scala
Expand Up @@ -344,6 +344,8 @@ object StringContext {
val digitsRead = dindex
(codepoint.asInstanceOf[Char], usRead + digitsRead)
}
else if (dindex + uindex >= len)
throw new InvalidUnicodeEscapeException(src, startindex, dindex + uindex)
else {
val ch = src(dindex + uindex)
val e = ch.asDigit
Expand Down
20 changes: 19 additions & 1 deletion test/files/neg/t3220-1.check
Expand Up @@ -4,4 +4,22 @@ t3220-1.scala:2: error: invalid unicode escape
t3220-1.scala:3: error: invalid unicode escape at index 6 of foo \unope that's wrong
val badtriple = """foo \unope that's wrong"""
^
two errors found
t3220-1.scala:4: error: invalid unicode escape
val caretPos = "foo \u12x3 pos @ x"
^
t3220-1.scala:5: error: invalid unicode escape
val caretPos2 = "foo \uuuuuuu12x3 pos @ x"
^
t3220-1.scala:6: error: invalid unicode escape
val carPosTerm = "foo \u123"
^
t3220-1.scala:7: error: invalid unicode escape
val halfAnEscape = "foo \u12"
^
t3220-1.scala:8: error: invalid unicode escape
val halfAnEscapeChar = '\u45'
^
t3220-1.scala:9: error: invalid unicode escape
val `half An Identifier\u45` = "nope"
^
8 errors found
6 changes: 6 additions & 0 deletions test/files/neg/t3220-1.scala
@@ -1,4 +1,10 @@
object Example {
val badsingle = "foo \unope that's wrong"
val badtriple = """foo \unope that's wrong"""
val caretPos = "foo \u12x3 pos @ x"
val caretPos2 = "foo \uuuuuuu12x3 pos @ x"
val carPosTerm = "foo \u123"
val halfAnEscape = "foo \u12"
val halfAnEscapeChar = '\u45'
val `half An Identifier\u45` = "nope"
}
11 changes: 7 additions & 4 deletions test/files/neg/t3220-2.check
@@ -1,13 +1,16 @@
t3220-2.scala:2: error: invalid unicode escape at index 6 of foo \unope that's wrong
val badInters1 = s"foo \unope that's wrong"
^
t3220-2.scala:3: error: invalid unicode escape at index 6 of foo \unope that's wrong
t3220-2.scala:3: error: invalid unicode escape at index 8 of foo \u12
val badIntersEnd1 = s"foo \u12"
^
t3220-2.scala:4: error: invalid unicode escape at index 6 of foo \unope that's wrong
val badInterRaw1 = raw"foo \unope that's wrong"
^
t3220-2.scala:4: error: invalid unicode escape at index 6 of foo \unope that's wrong
t3220-2.scala:6: error: invalid unicode escape at index 6 of foo \unope that's wrong
val badInters3 = s"""foo \unope that's wrong"""
^
t3220-2.scala:5: error: invalid unicode escape at index 6 of foo \unope that's wrong
t3220-2.scala:7: error: invalid unicode escape at index 6 of foo \unope that's wrong
val badInterRaw3 = raw"""foo \unope that's wrong"""
^
four errors found
5 errors found
2 changes: 2 additions & 0 deletions test/files/neg/t3220-2.scala
@@ -1,6 +1,8 @@
object Example {
val badInters1 = s"foo \unope that's wrong"
val badIntersEnd1 = s"foo \u12"
val badInterRaw1 = raw"foo \unope that's wrong"
val badInterRawEnd1 = raw"foo \u12"
val badInters3 = s"""foo \unope that's wrong"""
val badInterRaw3 = raw"""foo \unope that's wrong"""
}

0 comments on commit dbb8483

Please sign in to comment.