diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 74 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterLoop.scala | 143 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/Completion.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/Phased.scala | 115 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/Power.scala | 137 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/package.scala | 1 | ||||
-rw-r--r-- | test/files/run/treePrint.scala | 4 |
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) } } |