summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala74
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala143
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala10
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Phased.scala115
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala137
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/package.scala1
-rw-r--r--test/files/run/treePrint.scala4
8 files changed, 368 insertions, 120 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 09c75c6fa3..8cbc904947 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -324,7 +324,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
// XXX temporarily putting this here because of tricky initialization order issues
// so right now it's not bound until after you issue a command.
if (prevRequests.size == 1)
- quietBind("settings", "scala.tools.nsc.InterpreterSettings", isettings)
+ quietBind("settings", isettings)
// println("\n s1 = %s\n s2 = %s\n s3 = %s".format(
// tripart(referencedNameMap.keysIterator.toSet, boundNameMap.keysIterator.toSet): _*
@@ -523,7 +523,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
/** Parse a line into a sequence of trees. Returns None if the input is incomplete. */
- private def parse(line: String): Option[List[Tree]] = {
+ def parse(line: String): Option[List[Tree]] = {
var justNeedsMore = false
reporter.withIncompleteHandler((pos,msg) => {justNeedsMore = true}) {
// simple parse: just parse it, nothing else
@@ -669,6 +669,12 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
/** A name creator used for objects created by <code>bind()</code>. */
private lazy val newBinder = new NameCreator("binder")
+ def bindToType[T: ClassManifest](name: String, value: T): IR.Result =
+ bind(name, classManifest[T].erasure.getName, value)
+
+ def bind[T: ClassManifest](name: String, value: Any): IR.Result =
+ bind(name, classManifest[T].erasure.getName, value)
+
/** Bind a specified name to a specified value. The name may
* later be used by expressions passed to interpret.
*
@@ -694,6 +700,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
interpret("val %s = %s.value".format(name, binderName))
}
+ def quietBind[T: ClassManifest](name: String, value: T): IR.Result =
+ quietBind(name, classManifest[T].erasure.getName, value)
def quietBind(name: String, clazz: Class[_], value: Any): IR.Result =
quietBind(name, clazz.getName, value) // XXX need to port toTypeString
def quietBind(name: String, boundType: String, value: Any): IR.Result =
@@ -1056,11 +1064,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
override def contextPrelude = super.contextPrelude + "/* The repl internal portion of the stack trace is elided. */\n"
}
- quietBind("lastException", classOf[Exceptional], ex)
+ quietBind("lastException", ex)
ex.contextHead + "\n(access lastException for the full trace)"
}
private def bindUnexceptionally(t: Throwable) = {
- quietBind("lastException", classOf[Throwable], t)
+ quietBind("lastException", t)
stackTraceString(t)
}
@@ -1097,64 +1105,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
override def toString = "Request(line=%s, %s trees)".format(line, trees.size)
}
- /** A container class for methods to be injected into the repl
- * in power mode.
- */
- object power {
- lazy val compiler: repl.compiler.type = repl.compiler
- import compiler.{ phaseNames, atPhase, currentRun }
-
- def mkContext(code: String = "") = compiler.analyzer.rootContext(mkUnit(code))
- def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what))
- def mkSourceFile(code: String) = new BatchSourceFile("<console>", code)
- def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code))
-
- def mkTree(code: String): Tree = mkTrees(code).headOption getOrElse EmptyTree
- def mkTrees(code: String): List[Tree] = parse(code) getOrElse Nil
- def mkTypedTrees(code: String*): List[compiler.Tree] = {
- class TyperRun extends compiler.Run {
- override def stopPhase(name: String) = name == "superaccessors"
- }
-
- reporter.reset
- val run = new TyperRun
- run compileSources (code.toList.zipWithIndex map {
- case (s, i) => new BatchSourceFile("<console %d>".format(i), s)
- })
- run.units.toList map (_.body)
- }
- def mkTypedTree(code: String) = mkTypedTrees(code).head
- def mkType(id: String): compiler.Type = stringToCompilerType(id)
-
- def dump(): String = (
- ("Names used: " :: allreferencedNames) ++
- ("\nIdentifiers: " :: unqualifiedIds)
- ) mkString " "
-
- lazy val allPhases: List[Phase] = phaseNames map (currentRun phaseNamed _)
- def atAllPhases[T](op: => T): List[(String, T)] = allPhases map (ph => (ph.name, atPhase(ph)(op)))
- def showAtAllPhases(op: => Any): Unit =
- atAllPhases(op.toString) foreach { case (ph, op) => Console.println("%15s -> %s".format(ph, op take 240)) }
- }
-
- def unleash(): Unit = beQuietDuring {
- interpret("import scala.tools.nsc._")
- repl.bind("repl", "scala.tools.nsc.Interpreter", this)
- interpret("val global: repl.compiler.type = repl.compiler")
- interpret("val power: repl.power.type = repl.power")
- // interpret("val replVars = repl.replVars")
- }
-
- /** Artificial object demonstrating completion */
- // lazy val replVars = CompletionAware(
- // Map[String, CompletionAware](
- // "ids" -> CompletionAware(() => unqualifiedIds, completionAware _),
- // "synthVars" -> CompletionAware(() => allBoundNames filter isSynthVarName map (_.toString)),
- // "types" -> CompletionAware(() => allSeenTypes map (_.toString)),
- // "implicits" -> CompletionAware(() => allImplicits map (_.toString))
- // )
- // )
-
/** Returns the name of the most recent interpreter result.
* Mostly this exists so you can conveniently invoke methods on
* the previous result.
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index 4131061faa..32391ba2ba 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -26,9 +26,6 @@ import io.File
trait InterpreterControl {
self: InterpreterLoop =>
- // the default result means "keep running, and don't record that line"
- val defaultResult = Result(true, None)
-
private def isQuoted(s: String) =
(s.length >= 2) && (s.head == s.last) && ("\"'" contains s.head)
@@ -49,12 +46,12 @@ trait InterpreterControl {
}
case class LineArg(name: String, help: String, f: (String) => Result) extends Command {
- def usage(): String = ":" + name + " <line>"
+ def usage(): String = ":" + name + " "
def apply(args: List[String]) = f(args mkString " ")
}
case class OneArg(name: String, help: String, f: (String) => Result) extends Command {
- def usage(): String = ":" + name + " <arg>"
+ def usage(): String = ":" + name + " "
def apply(args: List[String]) =
if (args.size == 1) f(args.head)
else commandError("requires exactly one argument")
@@ -66,16 +63,26 @@ trait InterpreterControl {
}
// the result of a single command
- case class Result(keepRunning: Boolean, lineToRecord: Option[String])
+ case class Result(val keepRunning: Boolean, val lineToRecord: Option[String])
+ object Result {
+ // the default result means "keep running, and don't record that line"
+ val default = Result(true, None)
+
+ // most commands do not want to micromanage the Result, but they might want
+ // to print something to the console, so we accomodate Unit and String returns.
+ implicit def resultFromUnit(x: Unit): Result = default
+ implicit def resultFromString(msg: String): Result = {
+ out println msg
+ default
+ }
+ }
}
-/** The
- * <a href="http://scala-lang.org/" target="_top">Scala</a>
- * interactive shell. It provides a read-eval-print loop around
- * the Interpreter class.
- * After instantiation, clients should call the <code>main()</code> method.
+/** The Scala interactive shell. It provides a read-eval-print loop
+ * around the Interpreter class.
+ * After instantiation, clients should call the main() method.
*
- * <p>If no in0 is specified, then input will come from the console, and
+ * If no in0 is specified, then input will come from the console, and
* the class will attempt to provide input editing feature such as
* input history.
*
@@ -95,6 +102,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
var settings: Settings = _ // set by main()
var interpreter: Interpreter = _ // set by createInterpreter()
+ var replPower: Power = _
// classpath entries added via :cp
var addedClasspath: String = ""
@@ -141,6 +149,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
if (interpreter ne null) {
interpreter.close
interpreter = null
+ replPower = null
Thread.currentThread.setContextClassLoader(originalClassLoader)
}
}
@@ -224,26 +233,15 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
/** Prompt to print when awaiting input */
val prompt = Properties.shellPromptString
- // most commands do not want to micromanage the Result, but they might want
- // to print something to the console, so we accomodate Unit and String returns.
- object CommandImplicits {
- implicit def u2ir(x: Unit): Result = defaultResult
- implicit def s2ir(s: String): Result = {
- out println s
- defaultResult
- }
- }
-
/** Standard commands **/
val standardCommands: List[Command] = {
- import CommandImplicits._
List(
LineArg("cp", "add an entry (jar or directory) to the classpath", addClasspath),
NoArgs("help", "print this help message", printHelp),
VarArgs("history", "show the history (optional arg: lines to show)", printHistory),
LineArg("h?", "search the history", searchHistory),
OneArg("load", "load and interpret a Scala file", load),
- NoArgs("power", "enable power user mode", power),
+ NoArgs("power", "enable power user mode", powerCmd),
NoArgs("quit", "exit the interpreter", () => Result(false, None)),
NoArgs("replay", "reset execution and replay all previous commands", replay),
LineArg("sh", "fork a shell and run a command", runShellCmd),
@@ -252,26 +250,52 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
/** Power user commands */
- var powerUserOn = false
val powerCommands: List[Command] = {
- import CommandImplicits._
List(
- OneArg("completions", "generate list of completions for a given String", completions),
- NoArgs("dump", "displays a view of the interpreter's internal state", () => interpreter.power.dump())
-
- // VarArgs("tree", "displays ASTs for specified identifiers",
- // (xs: List[String]) => interpreter dumpTrees xs)
- // LineArg("meta", "given code which produces scala code, executes the results",
- // (xs: List[String]) => )
+ NoArgs("dump", "displays a view of the interpreter's internal state", replPower.toString _),
+ LineArg("phase", "set the implicit phase for power commands", phaseCommand),
+ LineArg("symfilter", "change the filter for symbol printing", symfilterCmd)
)
}
+ private def symfilterCmd(line: String): Result = {
+ if (line == "") {
+ replPower.vars.symfilter set "_ => true"
+ "Remove symbol filter."
+ }
+ else {
+ replPower.vars.symfilter set line
+ "Set symbol filter to '" + line + "'."
+ }
+ }
+ private def phaseCommand(_name: String): Result = {
+ val name = _name.toLowerCase
+ // This line crashes us in TreeGen:
+ //
+ // if (interpreter.power.phased set name) "..."
+ //
+ // Exception in thread "main" java.lang.AssertionError: assertion failed: ._7.type
+ // at scala.Predef$.assert(Predef.scala:99)
+ // at scala.tools.nsc.ast.TreeGen.mkAttributedQualifier(TreeGen.scala:69)
+ // at scala.tools.nsc.ast.TreeGen.mkAttributedQualifier(TreeGen.scala:44)
+ // at scala.tools.nsc.ast.TreeGen.mkAttributedRef(TreeGen.scala:101)
+ // at scala.tools.nsc.ast.TreeGen.mkAttributedStableRef(TreeGen.scala:143)
+ //
+ // But it works like so, type annotated.
+ val x: Phased = replPower.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."
+ }
/** Available commands */
- def commands: List[Command] = standardCommands ::: (if (powerUserOn) powerCommands else Nil)
+ def commands: List[Command] = standardCommands ++ (
+ if (replPower == null) Nil
+ else powerCommands
+ )
/** The main read-eval-print loop for the interpreter. It calls
- * <code>command()</code> for each line of input, and stops when
- * <code>command()</code> returns <code>false</code>.
+ * command() for each line of input, and stops when
+ * command() returns false.
*/
def repl() {
def readOneLine() = {
@@ -287,6 +311,11 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
case _ => true
}
+ if (sys.props contains PowerProperty) {
+ plushln("Starting in power mode, one moment...\n")
+ powerCmd()
+ }
+
while (processLine(readOneLine)) { }
}
@@ -359,19 +388,16 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
injectAndName(xs)
}
- def power() {
- val powerUserBanner =
- """** Power User mode enabled - BEEP BOOP **
- |** scala.tools.nsc._ has been imported **
- |** New vals! Try repl, global, power **
- |** New cmds! :help to discover them **
- |** New defs! Type power.<tab> to reveal **""".stripMargin
+ def powerCmd(): Result = {
+ if (replPower != null)
+ return "Already in power mode."
- powerUserOn = true
- interpreter.unleash()
+ replPower = new Power(interpreter) { }
+ replPower.unleash()
injectOne("history", in.historyList)
in.completion foreach (x => injectOne("completion", x))
- out println powerUserBanner
+
+ replPower.banner
}
def verbosity() = {
@@ -553,7 +579,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
}
- // runs :load <file> on any files passed via -i
+ // runs :load `file` on any files passed via -i
def loadFiles(settings: Settings) = settings match {
case settings: GenericRunnerSettings =>
for (filename <- settings.loadfiles.value) {
@@ -600,20 +626,31 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
private def objClass(x: Any) = x.asInstanceOf[AnyRef].getClass
private def objName(x: Any) = {
val clazz = objClass(x)
- val typeParams = clazz.getTypeParameters
- val basename = clazz.getName
- val tpString = if (typeParams.isEmpty) "" else "[%s]".format(typeParams map (_ => "_") mkString ", ")
+ clazz.getName + tpString(clazz)
+ }
+
+ def tpString[T: ClassManifest] : String =
+ tpString(classManifest[T].erasure)
+
+ def tpString(clazz: Class[_]): String = {
+ clazz.getTypeParameters.size match {
+ case 0 => ""
+ case x => List.fill(x)("_").mkString("[", ", ", "]")
+ }
+ }
- basename + tpString
+ def inject[T: ClassManifest](name: String, value: T): (String, String) = {
+ interpreter.bind[T](name, value)
+ (name, objName(value))
}
// injects one value into the repl; returns pair of name and class
- def injectOne(name: String, obj: Any): Tuple2[String, String] = {
+ def injectOne(name: String, obj: Any): (String, String) = {
val className = objName(obj)
interpreter.quietBind(name, className, obj)
(name, className)
}
- def injectAndName(obj: Any): Tuple2[String, String] = {
+ def injectAndName(obj: Any): (String, String) = {
val name = interpreter.getVarName
val className = objName(obj)
interpreter.bind(name, className, obj)
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 03f6432baf..c10a3f64e8 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -113,10 +113,6 @@ class Completion(val repl: Interpreter) extends CompletionOutput {
def methodSignatureString(sym: Symbol) = {
def asString = new MethodSymbolOutput(sym).methodString()
-
- if (isCompletionDebug)
- repl.power.showAtAllPhases(asString)
-
atPhase(currentRun.typerPhase)(asString)
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala
index 78b9f1c31c..d74ef8a663 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala
@@ -92,6 +92,16 @@ trait CompletionAware {
object CompletionAware {
val Empty = new CompletionAware { def completions(verbosity: Int) = Nil }
+ /** Artificial object demonstrating completion */
+ // lazy val replVars = CompletionAware(
+ // Map[String, CompletionAware](
+ // "ids" -> CompletionAware(() => unqualifiedIds, completionAware _),
+ // "synthVars" -> CompletionAware(() => allBoundNames filter isSynthVarName map (_.toString)),
+ // "types" -> CompletionAware(() => allSeenTypes map (_.toString)),
+ // "implicits" -> CompletionAware(() => allImplicits map (_.toString))
+ // )
+ // )
+
// class Forwarder(underlying: CompletionAware) extends CompletionAware {
// override def completions() = underlying.completions()
// override def filterNotFunction(s: String) = underlying.filterNotFunction(s)
diff --git a/src/compiler/scala/tools/nsc/interpreter/Phased.scala b/src/compiler/scala/tools/nsc/interpreter/Phased.scala
new file mode 100644
index 0000000000..ffe1904154
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/Phased.scala
@@ -0,0 +1,115 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+/** Mix this into an object and use it as a phasing
+ * swiss army knife.
+ */
+trait Phased {
+ val global: Global
+ import global._
+
+ private var active: PhaseName = Typer
+ private var multi: Seq[PhaseName] = Nil
+
+ def get = active
+ def set(phase: PhaseName): Boolean = phase match {
+ case NoPhaseName => false
+ case name => active = name ; true
+ }
+ def getMulti = multi
+ def setMulti(phases: Seq[PhaseName]): Boolean = {
+ if (phases contains NoPhaseName) false
+ else {
+ multi = phases
+ true
+ }
+ }
+
+ 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)
+
+ def at[T](ph: PhaseName)(body: => T): T = {
+ val saved = get
+ set(ph)
+ try apply(body)
+ finally set(saved)
+ }
+ def ats[T](phs: Seq[PhaseName])(body: => T): Seq[T] = {
+ val saved = multi
+ setMulti(phs)
+ try multi(body)
+ finally setMulti(saved)
+ }
+
+ def atshow[T](phs: Seq[PhaseName])(body: => T): Unit =
+ atz[T](phs)(body) foreach {
+ case (ph, op) => Console.println("%15s -> %s".format(ph, op.toString take 240))
+ }
+
+ def atz[T](phs: Seq[PhaseName])(body: => T): Seq[(PhaseName, T)] =
+ phs zip ats(phs)(body)
+
+ object PhaseName {
+ lazy val all = List(
+ Parser, Namer, Packageobjects, Typer, Superaccessors, Pickler, Refchecks,
+ Selectiveanf, Liftcode, Selectivecps, Uncurry, Tailcalls, Specialize,
+ Explicitouter, Erasure, Lazyvals, Lambdalift, Constructors, Flatten, Mixin,
+ Cleanup, Icode, Inliner, Closelim, Dce, Jvm, Terminal
+ )
+ lazy val nameMap = all.map(x => x.name -> x).toMap withDefaultValue NoPhaseName
+ multi = all
+
+ implicit def apply(s: String): PhaseName = nameMap(s)
+ implicit def defaultPhaseName: PhaseName = active
+ }
+ sealed abstract class PhaseName {
+ lazy val id = phase.id
+ lazy val name = toString.toLowerCase
+ def phase = currentRun.phaseNamed(name)
+
+ // Execute some code during this phase.
+ def apply[T](body: => T): T = atPhase(phase)(body)
+ }
+
+ case object Parser extends PhaseName
+ case object Namer extends PhaseName
+ case object Packageobjects extends PhaseName
+ case object Typer extends PhaseName
+ case object Superaccessors extends PhaseName
+ case object Pickler extends PhaseName
+ case object Refchecks extends PhaseName
+ case object Selectiveanf extends PhaseName
+ case object Liftcode extends PhaseName
+ case object Selectivecps extends PhaseName
+ case object Uncurry extends PhaseName
+ case object Tailcalls extends PhaseName
+ case object Specialize extends PhaseName
+ case object Explicitouter extends PhaseName
+ case object Erasure extends PhaseName
+ case object Lazyvals extends PhaseName
+ case object Lambdalift extends PhaseName
+ case object Constructors extends PhaseName
+ case object Flatten extends PhaseName
+ case object Mixin extends PhaseName
+ case object Cleanup extends PhaseName
+ case object Icode extends PhaseName
+ case object Inliner extends PhaseName
+ case object Closelim extends PhaseName
+ case object Dce extends PhaseName
+ case object Jvm extends PhaseName
+ case object Terminal extends PhaseName
+ case object NoPhaseName extends PhaseName {
+ override lazy val id = -1
+ override lazy val name = phase.name
+ override def phase = NoPhase
+ }
+
+ implicit def phaseEnumToPhase(name: PhaseName): Phase = name.phase
+ implicit def phaseNameToPhase(name: String): Phase = currentRun.phaseNamed(name)
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
new file mode 100644
index 0000000000..ac8f08ec80
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -0,0 +1,137 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+import scala.collection.{ mutable, immutable }
+import mutable.{ HashMap }
+import scala.tools.nsc.util.{ NoPosition, BatchSourceFile }
+
+/** A class for methods to be injected into the repl in power mode.
+ */
+class Power(repl: Interpreter) {
+ val global: repl.compiler.type = repl.compiler
+
+ import global._
+ import definitions.{ getMember, getModule, getClass => getCompilerClass }
+ import repl.{ beQuietDuring, interpret, parse }
+
+ object phased extends Phased {
+ val global: Power.this.global.type = Power.this.global
+ }
+
+ class ReplSnippet[T](val path: String, initial: T) {
+ var code: String = ""
+ var value: T = initial
+
+ def set(code: String) = interpret(path + ".value = " + code)
+ def get: T = value
+ override def toString = "repl." + path + ".value = \"" + code + "\""
+ }
+
+ object vars {
+ private def create[T](name: String, initial: T): ReplSnippet[T] =
+ new ReplSnippet[T]("power.vars." + name, initial)
+
+ val symfilter = create("symfilter", (s: Symbol) => true)
+ }
+
+ def banner = """
+ |** Power User mode enabled - BEEP BOOP **
+ |** scala.tools.nsc._ has been imported **
+ |** New vals! Try repl, global, power **
+ |** New cmds! :help to discover them **
+ |** New defs! Type power.<tab> to reveal **
+ """.stripMargin.trim
+
+ def init = """
+ |import scala.tools.nsc._
+ |val global: repl.compiler.type = repl.compiler
+ |import global._
+ |import definitions._
+ |import power.{ phased, show, clazz, module }
+ """.stripMargin
+
+ /** Starts up power mode and runs whatever is in init.
+ */
+ def unleash(): Unit = {
+ def f = {
+ repl.bind[Interpreter]("repl", repl)
+ repl.bind[Power]("power", this)
+ init split '\n' foreach interpret
+ }
+ if (isReplDebug) f
+ else beQuietDuring { f }
+ }
+
+ object show {
+ private def defStrings(sym: Symbol, p: Symbol => Boolean) =
+ phased(sym.info.members filter p map (_.defString))
+
+ private def display(sym: Symbol, p: Symbol => Boolean) =
+ defStrings(sym, p) foreach println
+
+ def methods[T: Manifest] = display(clazz[T], _.isMethod)
+ def apply[T: Manifest] = display(clazz[T], vars.symfilter.get)
+ }
+
+ abstract class NameBased[T <: Name] {
+ def mkName(s: String): T
+ def mkSymbol(s: String): Symbol
+
+ def apply[T: Manifest] = mkSymbol(manifest[T].erasure.getName)
+ def tpe[T: Manifest] = apply[T].tpe
+ def members[T: Manifest] = tpe[T].members
+ def member[T: Manifest](name: Name) = getMember(apply[T], name)
+ def vmember[T: Manifest](name: String) = member[T](newTermName(name))
+ def tmember[T: Manifest](name: String) = member[T](newTypeName(name))
+ }
+ private def missingWrap(op: => Symbol): Symbol =
+ try op
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ object clazz extends NameBased[TypeName] {
+ def mkName(s: String) = newTypeName(s)
+ def mkSymbol(s: String): Symbol = missingWrap(getCompilerClass(s))
+ }
+ object module extends NameBased[TermName] {
+ def mkName(s: String) = newTermName(s)
+ def mkSymbol(s: String): Symbol = missingWrap(getModule(s))
+ }
+
+ def mkContext(code: String = "") = analyzer.rootContext(mkUnit(code))
+ def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what))
+ def mkSourceFile(code: String) = new BatchSourceFile("<console>", code)
+ def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code))
+
+ def mkTree(code: String): Tree = mkTrees(code).headOption getOrElse EmptyTree
+ def mkTrees(code: String): List[Tree] = parse(code) getOrElse Nil
+ def mkTypedTrees(code: String*): List[Tree] = {
+ class TyperRun extends Run {
+ override def stopPhase(name: String) = name == "superaccessors"
+ }
+
+ reporter.reset
+ val run = new TyperRun
+ run compileSources (code.toList.zipWithIndex map {
+ case (s, i) => new BatchSourceFile("<console %d>".format(i), s)
+ })
+ run.units.toList map (_.body)
+ }
+ def mkTypedTree(code: String) = mkTypedTrees(code).head
+ def mkType(id: String): Type = repl.stringToCompilerType(id)
+
+ override def toString = """
+ |** Power mode status **
+ |Default phase: %s
+ |Names: %s
+ |Identifiers: %s
+ """.stripMargin.format(
+ phased.get,
+ repl.allreferencedNames mkString " ",
+ repl.unqualifiedIds mkString " "
+ )
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/package.scala b/src/compiler/scala/tools/nsc/interpreter/package.scala
index 4ec1db9118..c59cf8228a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/package.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/package.scala
@@ -7,6 +7,7 @@ package scala.tools.nsc
package object interpreter {
private[nsc] val DebugProperty = "scala.repl.debug"
+ private[nsc] val PowerProperty = "scala.repl.power"
private[nsc] var _debug = false
private[nsc] def isReplDebug = _debug || (sys.props contains DebugProperty)
diff --git a/test/files/run/treePrint.scala b/test/files/run/treePrint.scala
index 1fd1394e25..4c5f852582 100644
--- a/test/files/run/treePrint.scala
+++ b/test/files/run/treePrint.scala
@@ -2,6 +2,7 @@
*/
object Test {
import scala.tools.nsc._
+ import interpreter._
import java.io.{ OutputStream, BufferedReader, StringReader, PrintWriter, Writer, OutputStreamWriter}
val code = """
@@ -34,7 +35,8 @@ object Test {
settings.Ycompacttrees.value = true
val repl = new Interpreter(settings, new PrintWriter(new NullOutputStream))
+ val power = new Power(repl)
repl.interpret("""def initialize = "Have to interpret something or we get errors." """)
- println(repl.power mkTree code)
+ println(power mkTree code)
}
}