summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-29 21:16:58 +0000
committerPaul Phillips <paulp@improving.org>2011-01-29 21:16:58 +0000
commit4b9e197b968633c4b0e3605cdea9f052bdc4bd04 (patch)
tree499f2d8fc5e3b732bc76eef874c2694b812572ba
parentf89016a8736f7b09ea1dd74baa6c45bb39e47444 (diff)
downloadscala-4b9e197b968633c4b0e3605cdea9f052bdc4bd04.tar.gz
scala-4b9e197b968633c4b0e3605cdea9f052bdc4bd04.tar.bz2
scala-4b9e197b968633c4b0e3605cdea9f052bdc4bd04.zip
A :phase command for :power mode.
from that point forward will be run as atPhase(phase) { <line> }. Reasonably flexible syntax: scala> :phase erasure.next Active phase is now: Lazyvals (erasure.next) scala> :phase typer+3 Active phase is now: Refchecks (typer+3) scala> :phase clear Cleared active phase. No review.
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala47
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala19
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Phased.scala37
3 files changed, 93 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 5c57e70927..8e1f883b91 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -207,9 +207,21 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
List(
NoArgs("dump", "displays a view of the interpreter's internal state", power.toString _),
LineArg("phase", "set the implicit phase for power commands", phaseCommand),
- LineArg("symfilter", "change the filter for symbol printing", symfilterCmd)
+ LineArg("symfilter", "change the filter for symbol printing", symfilterCmd),
+ LineArg("wrap", "code to wrap around all executions", wrapCommand)
)
}
+ private def wrapCommand(line: String): Result = {
+ if (line == "") {
+ intp.setExecutionWrapper("")
+ "Cleared wrapper."
+ }
+ else {
+ intp.setExecutionWrapper(line)
+ "Set wrapper to '" + line + "'"
+ }
+ }
+
private def symfilterCmd(line: String): Result = {
if (line == "") {
power.vars.symfilter set "_ => true"
@@ -220,8 +232,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
"Set symbol filter to '" + line + "'."
}
}
- private def phaseCommand(_name: String): Result = {
- val name = _name.toLowerCase
+ private def pathToPhased = intp.pathToTerm("power") + ".phased"
+ private def phaseCommand(name: String): Result = {
// This line crashes us in TreeGen:
//
// if (intp.power.phased set name) "..."
@@ -234,10 +246,31 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
// at scala.tools.nsc.ast.TreeGen.mkAttributedStableRef(TreeGen.scala:143)
//
// But it works like so, type annotated.
- val x: Phased = power.phased
- if (name == "") "Active phase is '" + x.get + "'"
- else if (x set name) "Active phase is now '" + name + "'"
- else "'" + name + "' does not appear to be a valid phase."
+ val phased: Phased = power.phased
+ import phased.NoPhaseName
+
+ if (name == "clear") {
+ phased.set(NoPhaseName)
+ intp.clearExecutionWrapper()
+ "Cleared active phase."
+ }
+ else if (name == "") phased.get match {
+ case NoPhaseName => "Usage: :phase <expr> (e.g. typer, erasure.next, erasure+3)"
+ case ph => "Active phase is '%s'. (To clear, :phase clear)".format(phased.get)
+ }
+ else {
+ val what = phased.parse(name)
+ if (what.isEmpty || !phased.set(what))
+ "'" + name + "' does not appear to represent a valid phase."
+ else {
+ intp.setExecutionWrapper(pathToPhased)
+ val activeMessage =
+ if (what.toString.length == name.length) "" + what
+ else "%s (%s)".format(what, name)
+
+ "Active phase is now: " + activeMessage
+ }
+ }
}
/** Available commands */
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 794e6c158a..7b58999ac1 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -196,6 +196,12 @@ class IMain(val settings: Settings, out: PrintWriter) {
/** whether to bind the lastException variable */
private var bindLastException = true
+ /** A string representing code to be wrapped around all lines. */
+ private var _executionWrapper: String = ""
+ def executionWrapper = _executionWrapper
+ def setExecutionWrapper(code: String) = _executionWrapper = code
+ def clearExecutionWrapper() = _executionWrapper = ""
+
/** Temporarily stop binding lastException */
def withoutBindingLastException[T](operation: => T): T = {
val wasBinding = bindLastException
@@ -268,6 +274,15 @@ class IMain(val settings: Settings, out: PrintWriter) {
private def allHandlers = prevRequests.toList flatMap (_.handlers)
private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _))
+ def pathToTerm(id: String): String = {
+ val name = id.toTermName
+ if (boundNameMap contains name) {
+ val req = boundNameMap(name)
+ req.fullPath(name)
+ }
+ else id
+ }
+
def printAllTypeOf = {
prevRequests foreach { req =>
req.typeOf foreach { case (k, v) => Console.println(k + " => " + v) }
@@ -924,10 +939,10 @@ class IMain(val settings: Settings, out: PrintWriter) {
val preamble = """
|object %s {
| %s
- | val scala_repl_result: String = {
+ | val scala_repl_result: String = %s {
| %s
| (""
- """.stripMargin.format(resultObjectName, valueExtractor, objectName + accessPath)
+ """.stripMargin.format(resultObjectName, valueExtractor, executionWrapper, objectName + accessPath)
val postamble = """
| )
diff --git a/src/compiler/scala/tools/nsc/interpreter/Phased.scala b/src/compiler/scala/tools/nsc/interpreter/Phased.scala
index ffe1904154..a9c87618f8 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Phased.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Phased.scala
@@ -13,7 +13,7 @@ trait Phased {
val global: Global
import global._
- private var active: PhaseName = Typer
+ private var active: PhaseName = NoPhaseName
private var multi: Seq[PhaseName] = Nil
def get = active
@@ -30,6 +30,39 @@ trait Phased {
}
}
+ private def parsePhaseChange(str: String): Option[Int] = {
+ if (str == "") Some(0)
+ else if (str startsWith ".prev") parsePhaseChange(str drop 5) map (_ - 1)
+ else if (str startsWith ".next") parsePhaseChange(str drop 5) map (_ + 1)
+ else str.head match {
+ case '+' | '-' =>
+ val (num, rest) = str.tail.span(_.isDigit)
+ val diff = if (str.head == '+') num.toInt else -num.toInt
+ parsePhaseChange(rest) map (_ + diff)
+ case _ =>
+ None
+ }
+ }
+
+ /** Takes a string like 4, typer+2, typer.next, etc.
+ * and turns it into a PhaseName instance.
+ */
+ private def parseInternal(str: String): PhaseName = {
+ if (str.isEmpty) NoPhaseName
+ else if (str forall (_.isDigit)) PhaseName(str.toInt)
+ else {
+ val (name, rest) = str.toLowerCase span (_.isLetter)
+ val start = PhaseName(name)
+ val change = parsePhaseChange(rest)
+
+ if (start.isEmpty || change.isEmpty) NoPhaseName
+ else PhaseName(start.id + change.get)
+ }
+ }
+ def parse(str: String): PhaseName =
+ try parseInternal(str)
+ catch { case _: Exception => NoPhaseName }
+
def apply[T](body: => T): T = atPhase(get)(body)
def multi[T](body: => T): Seq[T] = multi map (ph => at(ph)(body))
def all[T](body: => T): Seq[T] = ats(PhaseName.all)(body)
@@ -65,6 +98,7 @@ trait Phased {
lazy val nameMap = all.map(x => x.name -> x).toMap withDefaultValue NoPhaseName
multi = all
+ def apply(id: Int): PhaseName = all find (_.id == id) getOrElse NoPhaseName
implicit def apply(s: String): PhaseName = nameMap(s)
implicit def defaultPhaseName: PhaseName = active
}
@@ -72,6 +106,7 @@ trait Phased {
lazy val id = phase.id
lazy val name = toString.toLowerCase
def phase = currentRun.phaseNamed(name)
+ def isEmpty = this eq NoPhaseName
// Execute some code during this phase.
def apply[T](body: => T): T = atPhase(phase)(body)