summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-04-06 18:48:15 +0000
committerPaul Phillips <paulp@improving.org>2011-04-06 18:48:15 +0000
commitf36e7acd02134fed6f27a61e82bf454a68684499 (patch)
tree17eadf7ddc0c5e19f352d570805b29319a60fe9a /src/compiler
parent1cf60d304d1a88c4e79ca4636f49d4676f2bfe04 (diff)
downloadscala-f36e7acd02134fed6f27a61e82bf454a68684499.tar.gz
scala-f36e7acd02134fed6f27a61e82bf454a68684499.tar.bz2
scala-f36e7acd02134fed6f27a61e82bf454a68684499.zip
The beautification of repl pasting had the prob...
The beautification of repl pasting had the problem that the new beautiful output was not itself pastable. Now I have achieved "paste idempotence". No review.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala8
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Pasted.scala93
2 files changed, 70 insertions, 31 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 8aa5f1a006..75503be3d1 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -605,8 +605,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
out.println("")
}
- def transcript(start: String) =
+ def transcript(start: String) = {
+ // Printing this message doesn't work very well becaues it's buried in the
+ // transcript they just pasted. Todo: a short timer goes off when
+ // lines stop coming which tells them to hit ctrl-D.
+ //
+ // out.println("// Detected repl transcript paste: ctrl-D to finish.")
apply(Iterator(start) ++ readWhile(_.trim != PromptString.trim))
+ }
}
import paste.{ ContinueString, PromptString }
diff --git a/src/compiler/scala/tools/nsc/interpreter/Pasted.scala b/src/compiler/scala/tools/nsc/interpreter/Pasted.scala
index df106e1f00..83321356a3 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Pasted.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Pasted.scala
@@ -9,12 +9,21 @@ package interpreter
/** If it looks like they're pasting in a scala interpreter
* transcript, remove all the formatting we inserted so we
* can make some sense of it.
+ *
+ * Most of the interesting code in here is due to my goal of
+ * "paste idempotence" i.e. the transcript resulting from pasting
+ * a transcript should itself be pasteable and should achieve
+ * the same result.
*/
abstract class Pasted {
def ContinueString: String
def PromptString: String
def interpret(line: String): Unit
+ def matchesPrompt(line: String) = matchesString(line, PromptString)
+ def matchesContinue(line: String) = matchesString(line, ContinueString)
+ def running = isRunning
+
private def matchesString(line: String, target: String): Boolean = (
(line startsWith target) ||
(line.nonEmpty && " \t".toSet(line.head) && matchesString(line.tail, target))
@@ -23,12 +32,61 @@ abstract class Pasted {
case -1 => line
case idx => line drop (idx + target.length)
}
+ private var isRunning = false
+ private val resReference = """(?<!^)(res\d+)""".r
+ private val resCreation = """^\s*(res\d+):.*""".r
+ private val resAssign = """^val (res\d+).*""".r
- def matchesPrompt(line: String) = matchesString(line, PromptString)
- def matchesContinue(line: String) = matchesString(line, ContinueString)
+ private class PasteAnalyzer(val lines: List[String]) {
+ val referenced = lines flatMap (resReference findAllIn _.trim.stripPrefix("res")) toSet
+ val cmds = lines reduceLeft append split PromptString filterNot (_.trim == "") toList
- private var isRunning = false
- def running = isRunning
+ /** If it's a prompt or continuation line, strip the formatting bits and
+ * assemble the code. Otherwise ship it off to be analyzed for res references
+ * and discarded.
+ */
+ def append(code: String, line: String): String =
+ if (matchesPrompt(line)) code + "\n" + line
+ else if (matchesContinue(line)) code + "\n" + stripString(line, ContinueString)
+ else fixResRefs(code, line)
+
+ /** If the line looks like
+ * res15: Int
+ *
+ * and the additional conditions hold that:
+ * 1) res15 is referenced from elsewhere in the transcript
+ * 2) the preceding repl line is not "val res15 = ..." because that
+ * indicates it has already been "val-ified" on a previous paste
+ *
+ * then we go back in time to the preceding scala> prompt and
+ * rewrite the line containing <expr> as
+ * val res15 = { <expr> }
+ * and the rest as they say is rewritten history.
+ *
+ * In all other cases, discard the line.
+ */
+ def fixResRefs(code: String, line: String) = line match {
+ case resCreation(resName) if referenced(resName) =>
+ code.lastIndexOf(PromptString) match {
+ case -1 => code
+ case idx =>
+ val (str1, str2) = code splitAt (idx + PromptString.length)
+ str2 match {
+ case resAssign(`resName`) => code
+ case _ => "%sval %s = { %s }".format(str1, resName, str2)
+ }
+ }
+ case _ => code
+ }
+
+ def run() {
+ println("// Replaying %d commands from transcript.\n" format cmds.size)
+ cmds foreach { cmd =>
+ print(PromptString)
+ interpret(cmd)
+ }
+ }
+ }
/** Commands start on lines beginning with "scala>" and each successive
* line which begins with the continuation string is appended to that command.
@@ -36,33 +94,8 @@ abstract class Pasted {
* all the commands are replayed.
*/
def apply(lines: TraversableOnce[String]) = {
- val cmds = lines reduceLeft append split PromptString filterNot (_.trim == "") toList;
- println("// Replaying %d commands from transcript.\n" format cmds.size)
-
isRunning = true
- try cmds foreach interpret
+ try new PasteAnalyzer(lines.toList) run()
finally isRunning = false
}
-
- private def append(code: String, line: String): String =
- if (matchesPrompt(line)) code + "\n" + line
- else if (matchesContinue(line)) code + "\n" + stripString(line, ContinueString)
- else fixResRefs(code, line)
-
- /** If the line looks like
- * res15: Int
- * then we go back in time to the preceding scala> prompt and rewrite
- * the line containing <expr> as
- * val res15 = { <expr> }
- * and the rest as they say is rewritten history.
- *
- * In all other cases, discard the line.
- */
- private val resRegex = """^\s*(res\d+):.*""".r
- private def fixResRefs(code: String, line: String) = line match {
- case resRegex(resName) if code contains PromptString =>
- val (str1, str2) = code splitAt code.lastIndexOf(PromptString) + PromptString.length
- "%sval %s = { %s }".format(str1, resName, str2)
- case _ => code
- }
}