summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-28 16:24:29 +0000
committerPaul Phillips <paulp@improving.org>2011-01-28 16:24:29 +0000
commitad3910e7fe0aedbab09ba6a85614f41b45e8b107 (patch)
tree5b3d8c4da7bf647ef7011c0758771f5a77d4e578 /src/compiler
parent834c065736573b11a1b51111edb032b2d3ca9b14 (diff)
downloadscala-ad3910e7fe0aedbab09ba6a85614f41b45e8b107.tar.gz
scala-ad3910e7fe0aedbab09ba6a85614f41b45e8b107.tar.bz2
scala-ad3910e7fe0aedbab09ba6a85614f41b45e8b107.zip
More repl housecleaning.
interpreter and the interpreter loop has become so fuzzy it can hardly be said to exist. In this commit I take a step or two toward clearer boundaries, and also fix some gratuitous name inconsistencies with the rest of trunk. A Global should be called "global" in the absence of a compelling reason otherwise. Also, now having had a couple years to explore every inch of the design space, I can announce that where possible to use them, distinguished objects like NoType and NoSymbol are far superior to swaddling things in Option. Applied this piece of canon to Completion and History. No review.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala90
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala173
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala31
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/History.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala42
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineReader.scala25
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/NamedParam.scala31
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala28
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala2
11 files changed, 226 insertions, 205 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 8cbc904947..d5a9e80326 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -157,28 +157,23 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
/** the public, go through the future compiler */
- lazy val compiler: Global = {
+ lazy val global: Global = {
initialize()
// blocks until it is ; false means catastrophic failure
if (_isInitialized()) _compiler
else null
}
+ @deprecated("Use `global` for access to the compiler instance.")
+ lazy val compiler = global
- import compiler.{ Traverser, CompilationUnit, Symbol, Name, TermName, TypeName, Type, TypeRef, NullaryMethodType }
- import compiler.{
- Tree, TermTree, ValOrDefDef, ValDef, DefDef, Assign, ClassDef,
- ModuleDef, Ident, BackQuotedIdent, Select, TypeDef, Import, MemberDef, DocDef,
- ImportSelector, EmptyTree, NoType }
- import compiler.{ opt, nme, newTermName, newTypeName }
+ import global._
+ import definitions.{ EmptyPackage, getMember }
import nme.{
INTERPRETER_VAR_PREFIX, INTERPRETER_SYNTHVAR_PREFIX, INTERPRETER_LINE_PREFIX,
INTERPRETER_IMPORT_WRAPPER, INTERPRETER_WRAPPER_SUFFIX, USCOREkw
}
- import compiler.definitions
- import definitions.{ EmptyPackage, getMember }
-
/** Temporarily be quiet */
def beQuietDuring[T](operation: => T): T = {
val wasPrinting = printResults
@@ -194,6 +189,8 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
finally totalSilence = saved
}
+ def quietRun[T](code: String) = beQuietDuring(interpret(code))
+
/** whether to bind the lastException variable */
private var bindLastException = true
@@ -530,7 +527,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
def simpleParse(code: String): List[Tree] = {
reporter.reset
val unit = new CompilationUnit(new BatchSourceFile("<console>", code))
- val scanner = new compiler.syntaxAnalyzer.UnitParser(unit)
+ val scanner = new syntaxAnalyzer.UnitParser(unit)
scanner.templateStatSeq(false)._2
}
@@ -555,7 +552,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
*/
def compileSources(sources: SourceFile*): Boolean = {
reporter.reset
- new compiler.Run() compileSources sources.toList
+ new Run() compileSources sources.toList
!reporter.hasErrors
}
@@ -572,11 +569,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
if (code.lines exists (_.trim endsWith "// show")) {
Console println code
parse(code) match {
- case Some(trees) => trees foreach (t => DBG(compiler.asCompactString(t)))
+ case Some(trees) => trees foreach (t => DBG(asCompactString(t)))
case _ => DBG("Parse error:\n\n" + code)
}
}
- val run = new compiler.Run()
+ val run = new Run()
run.compileSources(List(new BatchSourceFile(label, code)))
run
}
@@ -655,7 +652,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
else IR.Error
}
- if (compiler == null) IR.Error
+ if (global == null) IR.Error
else requestFromLine(line, synthetic) match {
case Left(result) => result
case Right(req) =>
@@ -669,6 +666,9 @@ 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 bind[T](p: NamedParam[T]): IR.Result =
+ bind(p.name, p.tpe, p.value)
+
def bindToType[T: ClassManifest](name: String, value: T): IR.Result =
bind(name, classManifest[T].erasure.getName, value)
@@ -837,7 +837,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
private class TypeAliasHandler(typeDef: TypeDef) extends MemberHandler(typeDef) {
lazy val TypeDef(mods, name, _, _) = typeDef
- def isAlias() = mods.isPublic && compiler.treeInfo.isAliasTypeDef(typeDef)
+ def isAlias() = mods.isPublic && treeInfo.isAliasTypeDef(typeDef)
override lazy val boundNames = if (isAlias) List(name) else Nil
override def resultExtractionCode(req: Request, code: PrintWriter) =
@@ -1015,7 +1015,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
!reporter.hasErrors
}
- def afterTyper[T](op: => T): T = compiler.atPhase(objRun.typerPhase.next)(op)
+ def afterTyper[T](op: => T): T = atPhase(objRun.typerPhase.next)(op)
/** The outermost wrapper object */
lazy val outerResObjSym: Symbol = getMember(EmptyPackage, newTermName(objectName))
@@ -1029,7 +1029,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
/* typeOf lookup with encoding */
- def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(compiler encode name))
+ def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(global.encode(name)))
def simpleNameOfType(name: TypeName) = (compilerTypeOf get name) map (_.typeSymbol.simpleName)
private def typeMap[T](f: Type => T): Map[Name, T] = {
@@ -1124,7 +1124,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
private def requestForIdent(line: String): Option[Request] = requestForName(newTermName(line))
// XXX literals.
- def stringToCompilerType(id: String): compiler.Type = {
+ def stringToCompilerType(id: String): Type = {
// if it's a recognized identifier, the type of that; otherwise treat the
// String like a value (e.g. scala.collection.Map) .
def findType = typeForIdent(id) match {
@@ -1284,7 +1284,6 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
/** Utility methods for the Interpreter. */
object Interpreter {
-
import scala.collection.generic.CanBuildFrom
def partialFlatMap[A, B, CC[X] <: Traversable[X]]
(coll: CC[A])
@@ -1298,57 +1297,6 @@ object Interpreter {
b.result
}
- object DebugParam {
- implicit def tuple2debugparam[T](x: (String, T))(implicit m: Manifest[T]): DebugParam[T] =
- DebugParam(x._1, x._2)
-
- implicit def any2debugparam[T](x: T)(implicit m: Manifest[T]): DebugParam[T] =
- DebugParam("p" + getCount(), x)
-
- private var counter = 0
- def getCount() = { counter += 1; counter }
- }
- case class DebugParam[T](name: String, param: T)(implicit m: Manifest[T]) {
- val manifest = m
- val typeStr = {
- val str = manifest.toString
- // I'm sure there are more to be discovered...
- val regexp1 = """(.*?)\[(.*)\]""".r
- val regexp2str = """.*\.type#"""
- val regexp2 = (regexp2str + """(.*)""").r
-
- (str.replaceAll("""\n""", "")) match {
- case regexp1(clazz, typeArgs) => "%s[%s]".format(clazz, typeArgs.replaceAll(regexp2str, ""))
- case regexp2(clazz) => clazz
- case _ => str
- }
- }
- }
- // provide the enclosing type T
- // in order to set up the interpreter's classpath and parent class loader properly
- def breakIf[T: Manifest](assertion: => Boolean, args: DebugParam[_]*): Unit =
- if (assertion) break[T](args.toList)
-
- // start a repl, binding supplied args
- def break[T: Manifest](args: List[DebugParam[_]]): Unit = {
- val intLoop = new InterpreterLoop
- intLoop.settings = new Settings(Console.println)
- intLoop.settings.embeddedDefaults[T]
- intLoop.createInterpreter
- intLoop.in = InteractiveReader.createDefault(intLoop.interpreter)
-
- // rebind exit so people don't accidentally call sys.exit by way of predef
- intLoop.interpreter.beQuietDuring {
- intLoop.interpreter.interpret("""def exit = println("Type :quit to resume program execution.")""")
- for (p <- args) {
- intLoop.interpreter.bind(p.name, p.typeStr, p.param)
- Console println "%s: %s".format(p.name, p.typeStr)
- }
- }
- intLoop.repl()
- intLoop.closeInterpreter
- }
-
def codegenln(leadingPlus: Boolean, xs: String*): String = codegen(leadingPlus, (xs ++ Array("\n")): _*)
def codegenln(xs: String*): String = codegenln(true, xs: _*)
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index 32391ba2ba..6bb9428528 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -94,16 +94,14 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
def this(in0: BufferedReader, out: PrintWriter) = this(Some(in0), out)
def this() = this(None, new PrintWriter(Console.out))
- /** The input stream from which commands come, set by main() */
- var in: InteractiveReader = _
+ var in: InteractiveReader = _ // the input stream from which commands come
+ var settings: Settings = _
+ var intp: Interpreter = _
+ var power: Power = _
/** The context class loader at the time this object was created */
protected val originalClassLoader = Thread.currentThread.getContextClassLoader
- var settings: Settings = _ // set by main()
- var interpreter: Interpreter = _ // set by createInterpreter()
- var replPower: Power = _
-
// classpath entries added via :cp
var addedClasspath: String = ""
@@ -130,10 +128,10 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
ignoring(classOf[Exception]) {
SignalManager("INT") = {
- if (interpreter == null)
+ if (intp == null)
onExit()
- else if (interpreter.lineManager.running)
- interpreter.lineManager.cancel()
+ else if (intp.lineManager.running)
+ intp.lineManager.cancel()
else if (in.currentLine != "") {
// non-empty buffer, so make them hit ctrl-C a second time
SignalManager("INT") = onExit()
@@ -146,10 +144,10 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
/** Close the interpreter and set the var to null. */
def closeInterpreter() {
- if (interpreter ne null) {
- interpreter.close
- interpreter = null
- replPower = null
+ if (intp ne null) {
+ intp.close
+ intp = null
+ power = null
Thread.currentThread.setContextClassLoader(originalClassLoader)
}
}
@@ -159,7 +157,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
if (addedClasspath != "")
settings.classpath append addedClasspath
- interpreter = new Interpreter(settings, out) {
+ intp = new Interpreter(settings, out) {
override protected def createLineManager() = new Line.Manager {
override def onRunaway(line: Line[_]): Unit = {
val template = """
@@ -176,9 +174,9 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
override protected def parentClassLoader =
settings.explicitParentLoader.getOrElse( classOf[InterpreterLoop].getClassLoader )
}
- interpreter.setContextClassLoader()
+ intp.setContextClassLoader()
installSigIntHandler()
- // interpreter.quietBind("settings", "scala.tools.nsc.InterpreterSettings", interpreter.isettings)
+ // intp.quietBind("settings", "scala.tools.nsc.InterpreterSettings", intp.isettings)
}
/** print a friendly help message */
@@ -203,12 +201,14 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
/** Show the history */
- def printHistory(xs: List[String]) {
+ def printHistory(xs: List[String]): Result = {
+ if (in.history eq History.Empty)
+ return "No history available."
+
val defaultLines = 20
- val h = in.history getOrElse { return println("No history available.") }
- val current = h.index
+ val current = in.history.index
val count = try xs.head.toInt catch { case _: Exception => defaultLines }
- val lines = in.historyList takeRight count
+ val lines = in.history.asList takeRight count
val offset = current - lines.size + 1
for ((line, index) <- lines.zipWithIndex)
@@ -217,21 +217,20 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
/** Some print conveniences */
def println(x: Any) = out println x
- def plush(x: Any) = { out print x ; out.flush() }
+ def plush(x: Any) = { out print x ; out.flush() }
def plushln(x: Any) = { out println x ; out.flush() }
/** Search the history */
def searchHistory(_cmdline: String) {
val cmdline = _cmdline.toLowerCase
- val h = in.history getOrElse { return println("No history available.") }
- val offset = h.index - h.size + 1
+ val offset = in.history.index - in.history.size + 1
- for ((line, index) <- h.asStrings.zipWithIndex ; if line.toLowerCase contains cmdline)
+ for ((line, index) <- in.history.asStrings.zipWithIndex ; if line.toLowerCase contains cmdline)
println("%d %s".format(index + offset, line))
}
/** Prompt to print when awaiting input */
- val prompt = Properties.shellPromptString
+ def prompt = Properties.shellPromptString
/** Standard commands **/
val standardCommands: List[Command] = {
@@ -252,18 +251,18 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
/** Power user commands */
val powerCommands: List[Command] = {
List(
- NoArgs("dump", "displays a view of the interpreter's internal state", replPower.toString _),
+ 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)
)
}
private def symfilterCmd(line: String): Result = {
if (line == "") {
- replPower.vars.symfilter set "_ => true"
+ power.vars.symfilter set "_ => true"
"Remove symbol filter."
}
else {
- replPower.vars.symfilter set line
+ power.vars.symfilter set line
"Set symbol filter to '" + line + "'."
}
}
@@ -271,7 +270,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
val name = _name.toLowerCase
// This line crashes us in TreeGen:
//
- // if (interpreter.power.phased set name) "..."
+ // if (intp.power.phased set name) "..."
//
// Exception in thread "main" java.lang.AssertionError: assertion failed: ._7.type
// at scala.Predef$.assert(Predef.scala:99)
@@ -281,7 +280,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
// at scala.tools.nsc.ast.TreeGen.mkAttributedStableRef(TreeGen.scala:143)
//
// But it works like so, type annotated.
- val x: Phased = replPower.phased
+ 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."
@@ -289,15 +288,15 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
/** Available commands */
def commands: List[Command] = standardCommands ++ (
- if (replPower == null) Nil
+ if (power == null) Nil
else powerCommands
)
- /** The main read-eval-print loop for the interpreter. It calls
+ /** The main read-eval-print loop for the repl. It calls
* command() for each line of input, and stops when
* command() returns false.
*/
- def repl() {
+ def loop() {
def readOneLine() = {
out.flush
in readLine prompt
@@ -311,11 +310,6 @@ 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)) { }
}
@@ -327,7 +321,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
try file applyReader { reader =>
in = new SimpleReader(reader, out, false)
plushln("Loading " + file + "...")
- repl()
+ loop()
}
finally {
in = oldIn
@@ -348,10 +342,10 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
/** fork a shell and run a command */
def runShellCmd(cmd: String) {
- interpreter.beQuietDuring { interpreter.interpret("import _root_.scala.sys.process._") }
+ intp.beQuietDuring { intp.interpret("import _root_.scala.sys.process._") }
val xs = Process(cmd).lines
if (xs.nonEmpty)
- interpreter.bind("stdout", "scala.Stream[String]", xs)
+ intp.bind("stdout", "scala.Stream[String]", xs)
}
def withFile(filename: String)(action: File => Unit) {
@@ -381,28 +375,21 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
else out.println("The path '" + f + "' doesn't seem to exist.")
}
- def completions(arg: String): Unit = {
- val comp = in.completion getOrElse { return println("Completion unavailable.") }
- val xs = comp completions arg
-
- injectAndName(xs)
- }
-
def powerCmd(): Result = {
- if (replPower != null)
+ if (power != null)
return "Already in power mode."
- replPower = new Power(interpreter) { }
- replPower.unleash()
- injectOne("history", in.historyList)
- in.completion foreach (x => injectOne("completion", x))
+ power = new Power(intp) { }
+ power.unleash()
+ injectOne("history", in.history.asList)
+ injectOne("completion", in.completion)
- replPower.banner
+ power.banner
}
def verbosity() = {
- val old = interpreter.printResults
- interpreter.printResults = !old
+ val old = intp.printResults
+ intp.printResults = !old
out.println("Switched " + (if (old) "off" else "on") + " result printing.")
}
@@ -419,7 +406,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
// not a command
if (!line.startsWith(":")) {
// Notice failure to create compiler
- if (interpreter.compiler == null) return Result(false, None)
+ if (intp.global == null) return Result(false, None)
else return Result(true, interpretStartingWith(line))
}
@@ -507,7 +494,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
for (PasteCommand(cmd, trailing) <- xs) {
out.flush()
def runCode(code: String, extraLines: List[String]) {
- (interpreter interpret code) match {
+ (intp interpret code) match {
case IR.Incomplete if extraLines.nonEmpty =>
runCode(code + "\n" + extraLines.head, extraLines.tail)
case _ => ()
@@ -528,9 +515,9 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
*/
def interpretStartingWith(code: String): Option[String] = {
// signal completion non-completion input has been received
- in.completion foreach (_.resetVerbosity())
+ in.completion.resetVerbosity()
- def reallyInterpret = interpreter.interpret(code) match {
+ def reallyInterpret = intp.interpret(code) match {
case IR.Error => None
case IR.Success => Some(code)
case IR.Incomplete =>
@@ -544,7 +531,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
// 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.
- interpreter.compileString(code)
+ intp.compileString(code)
None
case line => interpretStartingWith(code + "\n" + line)
@@ -566,13 +553,13 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
interpretAsPastedTranscript(List(code))
None
}
- else if (Completion.looksLikeInvocation(code) && interpreter.mostRecentVar != "") {
- interpretStartingWith(interpreter.mostRecentVar + code)
+ else if (Completion.looksLikeInvocation(code) && intp.mostRecentVar != "") {
+ interpretStartingWith(intp.mostRecentVar + code)
}
else {
- if (interpreter.isParseable(code)) reallyInterpret
+ if (intp.isParseable(code)) reallyInterpret
else {
- val res = in.completion flatMap (_ execute code) map injectAndName
+ val res = (in.completion execute code) map injectAndName
if (res.isDefined) None // completion took responsibility, so do not parse
else reallyInterpret // we know it will fail, this is to show the error
}
@@ -601,14 +588,16 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
case None =>
// the interpreter is passed as an argument to expose tab completion info
if (settings.Xnojline.value || Properties.isEmacsShell) new SimpleReader
- else if (settings.noCompletion.value) InteractiveReader.createDefault()
- else InteractiveReader.createDefault(interpreter)
+ else InteractiveReader(
+ if (settings.noCompletion.value) Completion.Empty
+ else Completion(intp)
+ )
}
loadFiles(settings)
try {
// it is broken on startup; go ahead and exit
- if (interpreter.reporter.hasErrors) return
+ if (intp.reporter.hasErrors) return
printWelcome()
@@ -617,8 +606,12 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
// our best to look ready. Ideally the user will spend a
// couple seconds saying "wow, it starts so fast!" and by the time
// they type a command the compiler is ready to roll.
- interpreter.initialize()
- repl()
+ intp.initialize()
+ if (sys.props contains PowerProperty) {
+ plushln("Starting in power mode, one moment...\n")
+ powerCmd()
+ }
+ loop()
}
finally closeInterpreter()
}
@@ -640,20 +633,20 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
def inject[T: ClassManifest](name: String, value: T): (String, String) = {
- interpreter.bind[T](name, value)
+ intp.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): (String, String) = {
val className = objName(obj)
- interpreter.quietBind(name, className, obj)
+ intp.quietBind(name, className, obj)
(name, className)
}
def injectAndName(obj: Any): (String, String) = {
- val name = interpreter.getVarName
+ val name = intp.getVarName
val className = objName(obj)
- interpreter.bind(name, className, obj)
+ intp.bind(name, className, obj)
(name, className)
}
@@ -685,3 +678,35 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
}
}
}
+
+object InterpreterLoop {
+ implicit def loopToInterpreter(repl: InterpreterLoop): Interpreter = repl.intp
+
+ // provide the enclosing type T
+ // in order to set up the interpreter's classpath and parent class loader properly
+ def breakIf[T: Manifest](assertion: => Boolean, args: NamedParam[_]*): Unit =
+ if (assertion) break[T](args.toList)
+
+ // start a repl, binding supplied args
+ def break[T: Manifest](args: List[NamedParam[_]]): Unit = {
+ val msg = if (args.isEmpty) "" else " Binding " + args.size + " value%s.".format(
+ if (args.size == 1) "" else "s"
+ )
+ Console.println("Debug repl starting." + msg)
+ val repl = new InterpreterLoop {
+ override def prompt = "\ndebug> "
+ }
+ repl.settings = new Settings(Console println _)
+ repl.settings.embeddedDefaults[T]
+ repl.createInterpreter()
+ repl.in = InteractiveReader(repl)
+
+ // rebind exit so people don't accidentally call sys.exit by way of predef
+ repl.quietRun("""def exit = println("Type :quit to resume program execution.")""")
+ args foreach (p => repl.bind(p.name, p.tpe, p.value))
+ repl.loop()
+
+ Console.println("\nDebug repl exiting.")
+ repl.closeInterpreter()
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index c10a3f64e8..04a1a4014a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -13,6 +13,14 @@ import java.util.{ List => JList }
import util.returning
object Completion {
+ object Empty extends Completion {
+ def resetVerbosity() = ()
+ def execute(line: String) = None
+ def completer() = new NullCompleter
+ }
+
+ def apply(repl: Interpreter): Completion = new CompletionImpl(repl)
+
def looksLikeInvocation(code: String) = (
(code != null)
&& (code startsWith ".")
@@ -33,9 +41,19 @@ object Completion {
}
import Completion._
+trait Completion {
+ def resetVerbosity(): Unit
+ def execute(line: String): Option[Any]
+ def completer(): Completer
+}
+
// REPL completor - queries supplied interpreter for valid
// completions based on current contents of buffer.
-class Completion(val repl: Interpreter) extends CompletionOutput {
+class CompletionImpl(val repl: Interpreter) extends Completion with CompletionOutput {
+ val global: repl.global.type = repl.global
+ import global._
+ import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage }
+
// verbosity goes up with consecutive tabs
private var verbosity: Int = 0
def resetVerbosity() = verbosity = 0
@@ -44,10 +62,6 @@ class Completion(val repl: Interpreter) extends CompletionOutput {
def DBG(msg: => Any) = if (isCompletionDebug) println(msg.toString)
def debugging[T](msg: String): T => T = (res: T) => returning[T](res)(x => DBG(msg + x))
- lazy val global: repl.compiler.type = repl.compiler
- import global._
- import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage }
-
// XXX not yet used.
lazy val dottedPaths = {
def walk(tp: Type): scala.List[Symbol] = {
@@ -284,12 +298,7 @@ class Completion(val repl: Interpreter) extends CompletionOutput {
def completions(buf: String): List[String] =
topLevelFor(Parsed.dotted(buf + ".", buf.length + 1))
- // jline's entry point
- lazy val jline: ArgumentCompleter = {
- val c = new ArgumentCompleter(new JLineDelimiter, new JLineCompletion)
- c setStrict false
- c
- }
+ def completer() = new JLineCompletion
/** This gets a little bit hairy. It's no small feat delegating everything
* and also keeping track of exactly where the cursor is and where it's supposed
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
index 5167e3c4c5..047acdf701 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -12,7 +12,7 @@ package interpreter
* as is also in progress with error messages.
*/
trait CompletionOutput {
- self: Completion =>
+ self: CompletionImpl =>
import global._
import definitions.{ NothingClass, AnyClass, isTupleTypeOrSubtype, isFunctionType, isRepeatedParamType }
diff --git a/src/compiler/scala/tools/nsc/interpreter/History.scala b/src/compiler/scala/tools/nsc/interpreter/History.scala
index a90627a07b..da91a55365 100644
--- a/src/compiler/scala/tools/nsc/interpreter/History.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/History.scala
@@ -31,6 +31,7 @@ class History(val jhistory: JHistory) {
}
object History {
+ val Empty: History = null
val ScalaHistoryFile = ".scala_history"
def apply(): History = new History(
diff --git a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
index f58c6f038a..f094aab104 100644
--- a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
@@ -13,11 +13,15 @@ import InteractiveReader._
/** Reads lines from an input stream */
trait InteractiveReader {
-
- protected def readOneLine(prompt: String): String
val interactive: Boolean
- def init(): Unit = ()
- def reset(): Unit = ()
+ protected def readOneLine(prompt: String): String
+
+ def history: History
+ def completion: Completion
+
+ def init(): Unit
+ def reset(): Unit
+
def redrawLine(): Unit = ()
def currentLine = "" // the current buffer contents, if available
@@ -30,13 +34,6 @@ trait InteractiveReader {
catching(handler) { readOneLine(prompt) }
}
- // override if history is available
- def history: Option[History] = None
- def historyList = history map (_.asList) getOrElse Nil
-
- // override if completion is available
- def completion: Option[Completion] = None
-
// hack necessary for OSX jvm suspension because read calls are not restarted after SIGTSTP
private def restartSystemCall(e: Exception): Boolean =
Properties.isMac && (e.getMessage == msgEINTR)
@@ -44,17 +41,14 @@ trait InteractiveReader {
object InteractiveReader {
val msgEINTR = "Interrupted system call"
- def createDefault(): InteractiveReader = createDefault(null)
-
- /** Create an interactive reader. Uses <code>JLineReader</code> if the
- * library is available, but otherwise uses a <code>SimpleReader</code>.
- */
- def createDefault(interpreter: Interpreter): InteractiveReader =
- try new JLineReader(interpreter)
- catch {
- case e @ (_: Exception | _: NoClassDefFoundError) =>
- // println("Failed to create JLineReader(%s): %s".format(interpreter, e))
- new SimpleReader
- }
-}
+ def apply(): InteractiveReader = new SimpleReader
+ def apply(repl: Interpreter): InteractiveReader = apply(Completion(repl))
+ def apply(comp: Completion): InteractiveReader = {
+ try new JLineReader(comp)
+ catch { case e @ (_: Exception | _: NoClassDefFoundError) => apply() }
+ }
+
+ @deprecated("Use `apply` instead") def createDefault(repl: Interpreter): InteractiveReader = apply(repl)
+ @deprecated("Use `apply` instead") def createDefault(comp: Completion): InteractiveReader = apply(comp)
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
index a61c06f821..8f42305bcb 100644
--- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
@@ -11,25 +11,32 @@ import scala.tools.jline.console.ConsoleReader
import scala.tools.jline.console.completer._
/** Reads from the console using JLine */
-class JLineReader(interpreter: Interpreter) extends InteractiveReader {
- def this() = this(null)
+class JLineReader(val completion: Completion) extends InteractiveReader {
+ lazy val history = History()
+
+ def reset() = consoleReader.getTerminal().reset()
+ def init() = consoleReader.getTerminal().init()
- override lazy val history = Some(History())
- override lazy val completion = Option(interpreter) map (x => new Completion(x))
- override def reset() = consoleReader.getTerminal().reset()
- override def init() = consoleReader.getTerminal().init()
override def redrawLine() = {
consoleReader.flush()
consoleReader.drawLine()
consoleReader.flush()
}
+ def argCompletor: ArgumentCompleter = {
+ val c = new ArgumentCompleter(new JLineDelimiter, completion.completer())
+ c setStrict false
+ c
+ }
+
val consoleReader = {
val r = new ConsoleReader()
r setBellEnabled false
- history foreach { r setHistory _.jhistory }
- completion foreach { c =>
- r addCompleter c.jline
+ if (history ne History.Empty)
+ r setHistory history.jhistory
+
+ if (completion ne Completion.Empty) {
+ r addCompleter argCompletor
r setAutoprintThreshold 250 // max completion candidates without warning
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala
new file mode 100644
index 0000000000..62255b2aaf
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/NamedParam.scala
@@ -0,0 +1,31 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+object NamedParam {
+ def apply[T: Manifest](name: String, x: T): NamedParam[T] = new NamedParam[T](name, x)
+ def apply[T: Manifest](x: T): NamedParam[T] = apply(getParamName(), x)
+
+ implicit def fromValue[T: Manifest](x: T) = apply(x)
+ implicit def fromNameAndValue[T: Manifest](name: String, x: T) = apply(name, x)
+ implicit def fromTuple[T: Manifest](pair: (String, T)) = apply(pair._1, pair._2)
+
+ private val getParamName = {
+ var counter = 0
+ () => { counter += 1; "p" + counter }
+ }
+}
+
+class NamedParam[T: Manifest](val name: String, val value: T) {
+ val clazz = manifest[T].erasure.getName
+ val tparams = manifest[T].typeArguments match {
+ case Nil => ""
+ case xs => xs.mkString("[", ", ", "]")
+ }
+ val tpe = clazz + tparams
+ override def toString = name + ": " + tpe
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
index ac8f08ec80..9cd6619c2d 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Power.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -10,14 +10,14 @@ 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.
+/** A class for methods to be injected into the intp in power mode.
*/
-class Power(repl: Interpreter) {
- val global: repl.compiler.type = repl.compiler
+class Power(intp: Interpreter) {
+ val global: intp.global.type = intp.global
import global._
import definitions.{ getMember, getModule, getClass => getCompilerClass }
- import repl.{ beQuietDuring, interpret, parse }
+ import intp.{ beQuietDuring, interpret, parse }
object phased extends Phased {
val global: Power.this.global.type = Power.this.global
@@ -29,7 +29,7 @@ class Power(repl: Interpreter) {
def set(code: String) = interpret(path + ".value = " + code)
def get: T = value
- override def toString = "repl." + path + ".value = \"" + code + "\""
+ override def toString = "intp." + path + ".value = \"" + code + "\""
}
object vars {
@@ -40,16 +40,17 @@ class Power(repl: Interpreter) {
}
def banner = """
- |** Power User mode enabled - BEEP BOOP **
+ |** Power User mode enabled - BEEP BOOP WHIR **
|** scala.tools.nsc._ has been imported **
- |** New vals! Try repl, global, power **
+ |** global._ and definitions._ also imported **
+ |** New vals! Try repl, intp, 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
+ |val global: intp.global.type = intp.global
|import global._
|import definitions._
|import power.{ phased, show, clazz, module }
@@ -59,8 +60,9 @@ class Power(repl: Interpreter) {
*/
def unleash(): Unit = {
def f = {
- repl.bind[Interpreter]("repl", repl)
- repl.bind[Power]("power", this)
+ intp.bind[InterpreterLoop]("repl", this)
+ intp.bind[Interpreter]("intp", intp)
+ intp.bind[Power]("power", this)
init split '\n' foreach interpret
}
if (isReplDebug) f
@@ -122,7 +124,7 @@ class Power(repl: Interpreter) {
run.units.toList map (_.body)
}
def mkTypedTree(code: String) = mkTypedTrees(code).head
- def mkType(id: String): Type = repl.stringToCompilerType(id)
+ def mkType(id: String): Type = intp.stringToCompilerType(id)
override def toString = """
|** Power mode status **
@@ -131,7 +133,7 @@ class Power(repl: Interpreter) {
|Identifiers: %s
""".stripMargin.format(
phased.get,
- repl.allreferencedNames mkString " ",
- repl.unqualifiedIds mkString " "
+ intp.allreferencedNames mkString " ",
+ intp.unqualifiedIds mkString " "
)
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
index fa1c1d1b43..a28fb9c5fe 100644
--- a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
@@ -18,7 +18,11 @@ extends InteractiveReader {
def this() = this(Console.in, new PrintWriter(Console.out), true)
def this(in: File, out: PrintWriter, interactive: Boolean) = this(in.bufferedReader(), out, interactive)
- def close() = in.close()
+ lazy val history = History.Empty
+ lazy val completion = Completion.Empty
+
+ def init() = ()
+ def reset() = ()
def readOneLine(prompt: String): String = {
if (interactive) {
out.print(prompt)
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 61371c5ef8..60387c8335 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -102,7 +102,7 @@ abstract class SymbolTable extends reflect.generic.Universe
/** Break into repl debugger if assertion is true */
// def breakIf(assertion: => Boolean, args: Any*): Unit =
// if (assertion)
- // Interpreter.break(args.toList)
+ // InterpreterLoop.break(args.toList)
/** The set of all installed infotransformers */
var infoTransformers = new InfoTransformer {