diff options
Diffstat (limited to 'src/compiler')
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 { |