summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2017-02-20 14:20:10 -0800
committerGitHub <noreply@github.com>2017-02-20 14:20:10 -0800
commit023a96afe30d04e6de771d0676b85b0889b89a37 (patch)
tree27a9342ae392a21bffad4c717f39d47bed5ac718 /src
parente21ab425880b7c3fa4cca3c9503045823d250025 (diff)
parent05cc3e2271d2c2226ded33bef5a03f0c70c6f66d (diff)
downloadscala-023a96afe30d04e6de771d0676b85b0889b89a37.tar.gz
scala-023a96afe30d04e6de771d0676b85b0889b89a37.tar.bz2
scala-023a96afe30d04e6de771d0676b85b0889b89a37.zip
Merge pull request #5629 from som-snytt/issue/10120-quote-err
SI-10133 Require escaped single quote char lit
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala24
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Formatting.scala35
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala7
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ReplReporter.scala33
4 files changed, 40 insertions, 59 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 3ed1570c1c..d72002f0a7 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -543,24 +543,36 @@ trait Scanners extends ScannersCommon {
}
fetchDoubleQuote()
case '\'' =>
+ def unclosedCharLit() = {
+ val msg = "unclosed character literal"
+ // previous token was Symbol contiguous with the orphan single quote at offset
+ if (token == SYMBOLLIT && offset == lastOffset) {
+ syntaxError(s"""$msg (or use " for string literal "$strVal")""")
+ } else {
+ syntaxError(msg)
+ }
+ }
def fetchSingleQuote() = {
nextChar()
if (isIdentifierStart(ch))
charLitOr(getIdentRest)
else if (isOperatorPart(ch) && (ch != '\\'))
charLitOr(getOperatorRest)
+ else if (ch == '\'') {
+ nextChar()
+ val advice = if (ch == '\'') { do nextChar() while (ch == '\''); " (use '\\'' for single quote)" } else ""
+ syntaxError(s"empty character literal${advice}")
+ }
else if (!isAtEnd && (ch != SU && ch != CR && ch != LF || isUnicodeEscape)) {
getLitChar()
- if (ch == '\'') {
+ if (ch != '\'') unclosedCharLit()
+ else {
nextChar()
token = CHARLIT
setStrVal()
- } else {
- syntaxError("unclosed character literal")
}
}
- else
- syntaxError("unclosed character literal")
+ else unclosedCharLit()
}
fetchSingleQuote()
case '.' =>
@@ -792,7 +804,7 @@ trait Scanners extends ScannersCommon {
next.token = kwArray(idx)
}
} else {
- syntaxError("invalid string interpolation: `$$', `$'ident or `$'BlockExpr expected")
+ syntaxError(s"invalid string interpolation $$$ch, expected: $$$$, $$identifier or $${expression}")
}
} else {
val isUnclosedLiteral = !isUnicodeEscape && (ch == SU || (!multiLine && (ch == CR || ch == LF)))
diff --git a/src/repl/scala/tools/nsc/interpreter/Formatting.scala b/src/repl/scala/tools/nsc/interpreter/Formatting.scala
deleted file mode 100644
index 4a9548730a..0000000000
--- a/src/repl/scala/tools/nsc/interpreter/Formatting.scala
+++ /dev/null
@@ -1,35 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package interpreter
-
-import util.stringFromWriter
-
-class Formatting(indent: Int) {
-
- private val indentation = " " * indent
-
- private def indenting(code: String): Boolean = {
- /** Heuristic to avoid indenting and thereby corrupting """-strings and XML literals. */
- val tokens = List("\"\"\"", "</", "/>")
- val noIndent = (code contains "\n") && (tokens exists code.contains)
-
- !noIndent
- }
- /** Indent some code by the width of the scala> prompt.
- * This way, compiler error messages read better.
- */
- def indentCode(code: String) = stringFromWriter(str =>
- for (line <- code.lines) {
- if (indenting(code)) str print indentation
- str println line
- str.flush()
- }
- )
-}
-object Formatting {
- def forPrompt(prompt: String) = new Formatting(prompt.lines.toList.last.length)
-}
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index a351d2da95..2ae3b207b7 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -111,11 +111,8 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
try body finally label = saved
}
- // the expanded prompt but without color escapes and without leading newline, for purposes of indenting
- lazy val formatting = Formatting.forPrompt(replProps.promptText)
lazy val reporter: ReplReporter = new ReplReporter(this)
- import formatting.indentCode
import reporter.{ printMessage, printUntruncatedMessage }
// This exists mostly because using the reporter too early leads to deadlock.
@@ -867,8 +864,8 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
|${preambleHeader format lineRep.readName}
|${envLines mkString (" ", ";\n ", ";\n")}
|$importsPreamble
- |${indentCode(toCompute)}""".stripMargin
- def preambleLength = preamble.length - toCompute.length - 1
+ |${toCompute}""".stripMargin
+ def preambleLength = preamble.length - toCompute.length
val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this
diff --git a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
index 3a0b69f41e..b01d242d44 100644
--- a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala
@@ -9,7 +9,7 @@ package interpreter
import reporters._
import IMain._
-import scala.reflect.internal.util.Position
+import scala.reflect.internal.util.{OffsetPosition, Position}
/** Like ReplGlobal, a layer for ensuring extra functionality.
*/
@@ -40,14 +40,25 @@ class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.i
case INFO => RESET
}
+ private val promptLength = replProps.promptText.lines.toList.last.length
+ private val indentation = " " * promptLength
+
+ // colorized console labels
+ override protected def clabel(severity: Severity): String = {
+ val label0 = super.clabel(severity)
+ if (replProps.colorOk) s"${severityColor(severity)}${label0}${RESET}" else label0
+ }
+
+ // shift indentation for source text entered at prompt
override def print(pos: Position, msg: String, severity: Severity) {
- val prefix = (
- if (replProps.colorOk)
- severityColor(severity) + clabel(severity) + RESET
- else
- clabel(severity)
- )
- printMessage(pos, prefix + msg)
+ val adjusted =
+ if (pos.source.file.name == "<console>")
+ new OffsetPosition(pos.source, pos.offset.getOrElse(0)) {
+ override def lineContent = s"${indentation}${super.lineContent}"
+ override def lineCaret = s"${indentation}${super.lineCaret}"
+ }
+ else pos
+ super.print(adjusted, msg, severity)
}
override def printMessage(msg: String) {
@@ -63,12 +74,8 @@ class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.i
else Console.println("[init] " + msg)
}
- override def displayPrompt() {
- if (intp.totalSilence) ()
- else super.displayPrompt()
- }
+ override def displayPrompt() = if (!intp.totalSilence) super.displayPrompt()
override def rerunWithDetails(setting: reflect.internal.settings.MutableSettings#Setting, name: String) =
s"; for details, enable `:setting $name' or `:replay $name'"
-
}