diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/ILoop.scala | 75 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/Pasted.scala | 56 |
2 files changed, 65 insertions, 66 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 92655ba643..a0cc116df8 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -24,9 +24,9 @@ import io.AbstractFile import scala.collection.generic.Clearable import scala.concurrent.{ ExecutionContext, Await, Future, future } import ExecutionContext.Implicits._ -import java.io.{ BufferedReader, FileReader } +import java.io.{ BufferedReader, FileReader, StringReader } -import scala.util.{Try, Success, Failure} +import scala.util.{ Try, Success, Failure } /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. @@ -748,28 +748,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) result } - private object paste extends Pasted { - import scala.util.matching.Regex.quote - val ContinuePrompt = replProps.continuePrompt - val ContinueString = replProps.continueText // " | " - val PromptString = prompt.lines.toList.last - val anyPrompt = s"""\\s*(?:${quote(PromptString.trim)}|${quote(AltPromptString.trim)})\\s*""".r - - def isPrompted(line: String) = matchesPrompt(line) - def isPromptOnly(line: String) = line match { case anyPrompt() => true ; case _ => false } - - def interpret(line: String): Unit = { - echo(line.trim) - intp interpret line - echo("") - } - - def transcript(start: String) = { - echo("\n// Detected repl transcript paste: ctrl-D to finish.\n") - apply(Iterator(start) ++ readWhile(!isPromptOnly(_))) - } - - def unapply(line: String): Boolean = isPrompted(line) + private object paste extends Pasted(prompt) { + def interpret(line: String) = intp interpret line + def echo(message: String) = ILoop.this echo message } private object invocation { @@ -784,30 +765,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) * read, go ahead and interpret it. Return the full string * to be recorded for replay, if any. */ - def interpretStartingWith(code: String): Option[String] = { + @tailrec final def interpretStartingWith(code: String): Option[String] = { // signal completion non-completion input has been received in.completion.resetVerbosity() - def reallyInterpret = intp.interpret(code) match { - case IR.Error => None - case IR.Success => Some(code) - case IR.Incomplete if in.interactive && code.endsWith("\n\n") => - echo("You typed two blank lines. Starting a new command.") - None - case IR.Incomplete => - in.readLine(paste.ContinuePrompt) match { - case null => - // we know compilation is going to fail since we're at EOF and the - // parser thinks the input is still incomplete, but since this is - // a file being read non-interactively we want to fail. So we send - // it straight to the compiler for the nice error message. - intp.compileString(code) - None - - case line => interpretStartingWith(code + "\n" + line) - } - } - /* Here we place ourselves between the user and the interpreter and examine * the input they are ostensibly submitting. We intervene in several cases: * @@ -820,9 +781,29 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) code match { case "" => None case lineComment() => None // line comment, do nothing - case paste() if !paste.running => paste.transcript(code) ; None + case paste() if !paste.running => paste.transcript(Iterator(code) ++ readWhile(!paste.isPromptOnly(_))) match { + case Some(s) => interpretStartingWith(s) + case _ => None + } case invocation() if intp.mostRecentVar != "" => interpretStartingWith(intp.mostRecentVar + code) - case _ => reallyInterpret + case _ => intp.interpret(code) match { + case IR.Error => None + case IR.Success => Some(code) + case IR.Incomplete if in.interactive && code.endsWith("\n\n") => + echo("You typed two blank lines. Starting a new command.") + None + case IR.Incomplete => in.readLine(paste.ContinuePrompt) match { + case null => + // we know compilation is going to fail since we're at EOF and the + // parser thinks the input is still incomplete, but since this is + // a file being read non-interactively we want to fail. So we send + // it straight to the compiler for the nice error message. + intp.compileString(code) + None + + case line => interpretStartingWith(s"$code\n$line") + } + } } } diff --git a/src/repl/scala/tools/nsc/interpreter/Pasted.scala b/src/repl/scala/tools/nsc/interpreter/Pasted.scala index f8d8c2ddb1..3a7eda1b77 100644 --- a/src/repl/scala/tools/nsc/interpreter/Pasted.scala +++ b/src/repl/scala/tools/nsc/interpreter/Pasted.scala @@ -15,19 +15,23 @@ package interpreter * a transcript should itself be pasteable and should achieve * the same result. */ -abstract class Pasted { - def interpret(line: String): Unit - def ContinueString: String - def PromptString: String - def AltPromptString: String = "scala> " +abstract class Pasted(prompt: String) { + def interpret(line: String): IR.Result + def echo(message: String): Unit - /* `testBoth` cannot be a val, as `Pasted` is inherited by `object paste` in ILoop, - which would cause `val testBoth` to be initialized before `val PromptString` was. + val PromptString = prompt.lines.toList.last + val AltPromptString = "scala> " + val ContinuePrompt = replProps.continuePrompt + val ContinueString = replProps.continueText // " | " + val anyPrompt = { + import scala.util.matching.Regex.quote + s"""\\s*(?:${quote(PromptString.trim)}|${quote(AltPromptString.trim)})\\s*""".r + } + + def isPrompted(line: String) = matchesPrompt(line) + def isPromptOnly(line: String) = line match { case anyPrompt() => true ; case _ => false } - object paste extends Pasted { - val PromptString = prompt.lines.toList.last - */ - private def testBoth = PromptString != AltPromptString + private val testBoth = PromptString != AltPromptString private val spacey = " \t".toSet def matchesPrompt(line: String) = matchesString(line, PromptString) || testBoth && matchesString(line, AltPromptString) @@ -91,13 +95,26 @@ abstract class Pasted { case _ => code } - def run(): Unit = { - println("// Replaying %d commands from transcript.\n" format cmds.size) - cmds foreach { cmd => - print(ActualPromptString) - interpret(cmd) - } + def interpreted(line: String) = { + echo(line.trim) + val res = interpret(line) + if (res != IR.Incomplete) echo("") + res + } + def incompletely(cmd: String) = { + print(ActualPromptString) + interpreted(cmd) == IR.Incomplete } + def run(): Option[String] = { + echo(s"// Replaying ${cmds.size} commands from transcript.\n") + cmds find incompletely + } + } + + // Run transcript and return incomplete line if any. + def transcript(lines: TraversableOnce[String]): Option[String] = { + echo("\n// Detected repl transcript. Paste more, or ctrl-D to finish.\n") + apply(lines) } /** Commands start on lines beginning with "scala>" and each successive @@ -105,9 +122,10 @@ abstract class Pasted { * Everything else is discarded. When the end of the transcript is spotted, * all the commands are replayed. */ - def apply(lines: TraversableOnce[String]) = { + def apply(lines: TraversableOnce[String]): Option[String] = { isRunning = true - try new PasteAnalyzer(lines.toList) run() + try new PasteAnalyzer(lines.toList).run() finally isRunning = false } + def unapply(line: String): Boolean = isPrompted(line) } |