From 48cc8b47fcadaa187026ca0422178c9094e4b412 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 10 Mar 2013 17:17:58 -0700 Subject: Modularized the repl. Following in the footsteps of scaladoc and interactive. The interpreter sources move into src/repl, and are given a separate build target. As with the others, at present they are still packaged into scala-compiler.jar. A summary of changes: - repl requires use of ReplGlobal (this was already implied) - macro code's repl-specific classloader hack pulled into overridable method and overridden in ReplGlobal - removed -Ygen-javap option to eliminate backend's dependency on javap - removed -Yrepl-debug option (can still be enabled with -Dscala.repl.debug) - pushed javap code into src/repl so javax.tools dependency can bee weakened to the repl only - removed some "show pickled" related code which hasn't worked right in a while and isn't the right way to do it anymore anyway. Will return to fix showPickled and provide it with some tests. --- build.xml | 39 +- src/compiler/scala/tools/nsc/Global.scala | 2 +- src/compiler/scala/tools/nsc/Interpreter.scala | 12 - src/compiler/scala/tools/nsc/InterpreterLoop.scala | 12 - .../scala/tools/nsc/MainGenericRunner.scala | 106 -- .../tools/nsc/backend/jvm/BytecodeWriters.scala | 30 - .../scala/tools/nsc/backend/jvm/GenASM.scala | 59 +- .../nsc/interpreter/AbstractFileClassLoader.scala | 108 -- .../nsc/interpreter/AbstractOrMissingHandler.scala | 41 - .../scala/tools/nsc/interpreter/ByteCode.scala | 42 - .../scala/tools/nsc/interpreter/CommandLine.scala | 13 - .../scala/tools/nsc/interpreter/Completion.scala | 49 - .../tools/nsc/interpreter/CompletionAware.scala | 53 - .../tools/nsc/interpreter/CompletionOutput.scala | 85 -- .../nsc/interpreter/ConsoleReaderHelper.scala | 63 -- .../scala/tools/nsc/interpreter/Delimited.scala | 41 - .../scala/tools/nsc/interpreter/ExprTyper.scala | 99 -- .../scala/tools/nsc/interpreter/Formatting.scala | 35 - .../scala/tools/nsc/interpreter/ILoop.scala | 749 ------------- .../scala/tools/nsc/interpreter/IMain.scala | 1121 ------------------- .../scala/tools/nsc/interpreter/ISettings.scala | 54 - .../scala/tools/nsc/interpreter/Imports.scala | 181 ---- .../tools/nsc/interpreter/InteractiveReader.scala | 49 - .../tools/nsc/interpreter/JLineCompletion.scala | 352 ------ .../scala/tools/nsc/interpreter/JLineReader.scala | 68 -- .../scala/tools/nsc/interpreter/Logger.scala | 14 - .../scala/tools/nsc/interpreter/LoopCommands.scala | 86 -- .../tools/nsc/interpreter/MemberHandlers.scala | 219 ---- .../scala/tools/nsc/interpreter/NamedParam.scala | 45 - .../scala/tools/nsc/interpreter/Naming.scala | 105 -- .../scala/tools/nsc/interpreter/Parsed.scala | 60 -- .../scala/tools/nsc/interpreter/Pasted.scala | 101 -- .../scala/tools/nsc/interpreter/Phased.scala | 143 --- .../scala/tools/nsc/interpreter/Power.scala | 326 ------ .../scala/tools/nsc/interpreter/ReplConfig.scala | 49 - .../scala/tools/nsc/interpreter/ReplDir.scala | 48 - .../scala/tools/nsc/interpreter/ReplGlobal.scala | 56 - .../scala/tools/nsc/interpreter/ReplProps.scala | 27 - .../scala/tools/nsc/interpreter/ReplReporter.scala | 34 - .../scala/tools/nsc/interpreter/ReplStrings.scala | 32 - .../scala/tools/nsc/interpreter/ReplVals.scala | 82 -- .../scala/tools/nsc/interpreter/Results.scala | 22 - .../scala/tools/nsc/interpreter/RichClass.scala | 36 - .../scala/tools/nsc/interpreter/SimpleReader.scala | 40 - .../scala/tools/nsc/interpreter/TypeStrings.scala | 242 ----- .../scala/tools/nsc/interpreter/package.scala | 157 --- .../interpreter/session/FileBackedHistory.scala | 84 -- .../tools/nsc/interpreter/session/History.scala | 22 - .../nsc/interpreter/session/JLineHistory.scala | 49 - .../nsc/interpreter/session/SimpleHistory.scala | 58 - .../tools/nsc/interpreter/session/package.scala | 23 - .../scala/tools/nsc/settings/ScalaSettings.scala | 1 - .../scala/tools/nsc/typechecker/Macros.scala | 23 +- .../scala/tools/nsc/typechecker/TypeStrings.scala | 244 +++++ .../tools/nsc/util/AbstractFileClassLoader.scala | 107 ++ .../scala/tools/nsc/util/ShowPickled.scala | 4 +- src/compiler/scala/tools/reflect/StdTags.scala | 4 +- .../scala/tools/reflect/ToolBoxFactory.scala | 2 +- src/compiler/scala/tools/util/Javap.scala | 694 +----------- src/repl/scala/tools/nsc/Interpreter.scala | 12 + src/repl/scala/tools/nsc/InterpreterLoop.scala | 12 + src/repl/scala/tools/nsc/MainGenericRunner.scala | 105 ++ .../nsc/interpreter/AbstractFileClassLoader.scala | 7 + .../nsc/interpreter/AbstractOrMissingHandler.scala | 41 + .../scala/tools/nsc/interpreter/ByteCode.scala | 32 + .../scala/tools/nsc/interpreter/CommandLine.scala | 13 + .../scala/tools/nsc/interpreter/Completion.scala | 49 + .../tools/nsc/interpreter/CompletionAware.scala | 53 + .../tools/nsc/interpreter/CompletionOutput.scala | 85 ++ .../nsc/interpreter/ConsoleReaderHelper.scala | 63 ++ .../scala/tools/nsc/interpreter/Delimited.scala | 41 + .../scala/tools/nsc/interpreter/ExprTyper.scala | 99 ++ .../scala/tools/nsc/interpreter/Formatting.scala | 35 + src/repl/scala/tools/nsc/interpreter/ILoop.scala | 748 +++++++++++++ src/repl/scala/tools/nsc/interpreter/IMain.scala | 1122 ++++++++++++++++++++ .../scala/tools/nsc/interpreter/ISettings.scala | 54 + src/repl/scala/tools/nsc/interpreter/Imports.scala | 181 ++++ .../tools/nsc/interpreter/InteractiveReader.scala | 49 + .../tools/nsc/interpreter/JLineCompletion.scala | 352 ++++++ .../scala/tools/nsc/interpreter/JLineReader.scala | 68 ++ .../scala/tools/nsc/interpreter/JavapClass.scala | 693 ++++++++++++ src/repl/scala/tools/nsc/interpreter/Logger.scala | 14 + .../scala/tools/nsc/interpreter/LoopCommands.scala | 86 ++ .../tools/nsc/interpreter/MemberHandlers.scala | 219 ++++ .../scala/tools/nsc/interpreter/NamedParam.scala | 46 + src/repl/scala/tools/nsc/interpreter/Naming.scala | 105 ++ src/repl/scala/tools/nsc/interpreter/Parsed.scala | 60 ++ src/repl/scala/tools/nsc/interpreter/Pasted.scala | 101 ++ src/repl/scala/tools/nsc/interpreter/Phased.scala | 143 +++ src/repl/scala/tools/nsc/interpreter/Power.scala | 326 ++++++ .../scala/tools/nsc/interpreter/ReplConfig.scala | 49 + src/repl/scala/tools/nsc/interpreter/ReplDir.scala | 48 + .../scala/tools/nsc/interpreter/ReplGlobal.scala | 64 ++ .../scala/tools/nsc/interpreter/ReplProps.scala | 27 + .../scala/tools/nsc/interpreter/ReplReporter.scala | 34 + .../scala/tools/nsc/interpreter/ReplStrings.scala | 32 + .../scala/tools/nsc/interpreter/ReplVals.scala | 82 ++ src/repl/scala/tools/nsc/interpreter/Results.scala | 22 + .../scala/tools/nsc/interpreter/RichClass.scala | 36 + .../scala/tools/nsc/interpreter/SimpleReader.scala | 40 + .../scala/tools/nsc/interpreter/StdReplTags.scala | 15 + src/repl/scala/tools/nsc/interpreter/package.scala | 157 +++ .../interpreter/session/FileBackedHistory.scala | 84 ++ .../tools/nsc/interpreter/session/History.scala | 22 + .../nsc/interpreter/session/JLineHistory.scala | 49 + .../nsc/interpreter/session/SimpleHistory.scala | 58 + .../tools/nsc/interpreter/session/package.scala | 23 + 107 files changed, 6285 insertions(+), 6273 deletions(-) delete mode 100644 src/compiler/scala/tools/nsc/Interpreter.scala delete mode 100644 src/compiler/scala/tools/nsc/InterpreterLoop.scala delete mode 100644 src/compiler/scala/tools/nsc/MainGenericRunner.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ByteCode.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/CommandLine.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Completion.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Delimited.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Formatting.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ILoop.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/IMain.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ISettings.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Imports.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/JLineReader.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Logger.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/NamedParam.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Naming.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Parsed.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Pasted.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Phased.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Power.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplDir.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplGlobal.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplProps.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplReporter.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplStrings.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/ReplVals.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/Results.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/RichClass.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/package.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/session/FileBackedHistory.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/session/History.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/session/JLineHistory.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/session/SimpleHistory.scala delete mode 100644 src/compiler/scala/tools/nsc/interpreter/session/package.scala create mode 100644 src/compiler/scala/tools/nsc/typechecker/TypeStrings.scala create mode 100644 src/compiler/scala/tools/nsc/util/AbstractFileClassLoader.scala create mode 100644 src/repl/scala/tools/nsc/Interpreter.scala create mode 100644 src/repl/scala/tools/nsc/InterpreterLoop.scala create mode 100644 src/repl/scala/tools/nsc/MainGenericRunner.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ByteCode.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/CommandLine.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Completion.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/CompletionAware.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/CompletionOutput.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Delimited.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ExprTyper.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Formatting.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ILoop.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/IMain.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ISettings.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Imports.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/InteractiveReader.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/JLineCompletion.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/JLineReader.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/JavapClass.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Logger.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/LoopCommands.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/NamedParam.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Naming.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Parsed.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Pasted.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Phased.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Power.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplConfig.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplDir.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplGlobal.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplProps.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplReporter.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplStrings.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/ReplVals.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/Results.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/RichClass.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/SimpleReader.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/StdReplTags.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/package.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/session/FileBackedHistory.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/session/History.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/session/JLineHistory.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/session/SimpleHistory.scala create mode 100644 src/repl/scala/tools/nsc/interpreter/session/package.scala diff --git a/build.xml b/build.xml index c1deb7ce6f..7e4948c938 100644 --- a/build.xml +++ b/build.xml @@ -1095,6 +1095,32 @@ QUICK BUILD (QUICK) + + + + + + + + + + + + + + + + + + + + + - + @@ -1229,6 +1255,7 @@ QUICK BUILD (QUICK) + @@ -1247,6 +1274,7 @@ QUICK BUILD (QUICK) + @@ -1358,11 +1386,12 @@ QUICK BUILD (QUICK) + + + - - @@ -1488,6 +1517,7 @@ PACKED QUICK BUILD (PACK) + @@ -1998,10 +2028,11 @@ SBT Compiler Interface jvmargs="${scalacfork.jvmargs}"> - + + diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c0f611daa7..7ee3ee551f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -999,7 +999,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) object typeDeconstruct extends { val global: Global.this.type = Global.this - } with interpreter.StructuredTypeStrings + } with typechecker.StructuredTypeStrings /** There are common error conditions where when the exception hits * here, currentRun.currentUnit is null. This robs us of the knowledge diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala deleted file mode 100644 index 434f19f21b..0000000000 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ /dev/null @@ -1,12 +0,0 @@ -package scala.tools.nsc - -import interpreter._ -import java.io._ - -/** A compatibility stub. - */ -@deprecated("Use a class in the scala.tools.nsc.interpreter package.", "2.9.0") -class Interpreter(settings: Settings, out: PrintWriter) extends IMain(settings, out) { - def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true)) - def this() = this(new Settings()) -} \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala deleted file mode 100644 index a0be3f4fdb..0000000000 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ /dev/null @@ -1,12 +0,0 @@ -package scala.tools.nsc - -import interpreter._ -import java.io._ - -/** A compatibility stub. - */ -@deprecated("Use a class in the scala.tools.nsc.interpreter package.", "2.9.0") -class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) extends ILoop(in0, out) { - def this(in0: BufferedReader, out: PrintWriter) = this(Some(in0), out) - def this() = this(None, new PrintWriter(scala.Console.out)) -} diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala deleted file mode 100644 index adb03ca374..0000000000 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ /dev/null @@ -1,106 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2006-2013 LAMP/EPFL - * @author Lex Spoon - */ - -package scala.tools.nsc - -import io.{ File } -import util.{ ClassPath, ScalaClassLoader } -import Properties.{ versionString, copyrightString } -import interpreter.{ ILoop } -import GenericRunnerCommand._ - -object JarRunner extends CommonRunner { - def runJar(settings: GenericRunnerSettings, jarPath: String, arguments: Seq[String]): Either[Throwable, Boolean] = { - val jar = new io.Jar(jarPath) - val mainClass = jar.mainClass getOrElse sys.error("Cannot find main class for jar: " + jarPath) - val jarURLs = ClassPath expandManifestPath jarPath - val urls = if (jarURLs.isEmpty) File(jarPath).toURL +: settings.classpathURLs else jarURLs - - if (settings.Ylogcp.value) { - Console.err.println("Running jar with these URLs as the classpath:") - urls foreach println - } - - runAndCatch(urls, mainClass, arguments) - } -} - -/** An object that runs Scala code. It has three possible - * sources for the code to run: pre-compiled code, a script file, - * or interactive entry. - */ -class MainGenericRunner { - def errorFn(ex: Throwable): Boolean = { - ex.printStackTrace() - false - } - def errorFn(str: String): Boolean = { - Console.err println str - false - } - - def process(args: Array[String]): Boolean = { - val command = new GenericRunnerCommand(args.toList, (x: String) => errorFn(x)) - import command.{ settings, howToRun, thingToRun } - def sampleCompiler = new Global(settings) // def so its not created unless needed - - if (!command.ok) return errorFn("\n" + command.shortUsageMsg) - else if (settings.version.value) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString)) - else if (command.shouldStopWithInfo) return errorFn(command getInfoMessage sampleCompiler) - - def isE = !settings.execute.isDefault - def dashe = settings.execute.value - - def isI = !settings.loadfiles.isDefault - def dashi = settings.loadfiles.value - - // Deadlocks on startup under -i unless we disable async. - if (isI) - settings.Yreplsync.value = true - - def combinedCode = { - val files = if (isI) dashi map (file => File(file).slurp()) else Nil - val str = if (isE) List(dashe) else Nil - - files ++ str mkString "\n\n" - } - - def runTarget(): Either[Throwable, Boolean] = howToRun match { - case AsObject => - ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments) - case AsScript => - ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments) - case AsJar => - JarRunner.runJar(settings, thingToRun, command.arguments) - case Error => - Right(false) - case _ => - // We start the repl when no arguments are given. - Right(new ILoop process settings) - } - - /** If -e and -i were both given, we want to execute the -e code after the - * -i files have been included, so they are read into strings and prepended to - * the code given in -e. The -i option is documented to only make sense - * interactively so this is a pretty reasonable assumption. - * - * This all needs a rewrite though. - */ - if (isE) { - ScriptRunner.runCommand(settings, combinedCode, thingToRun +: command.arguments) - } - else runTarget() match { - case Left(ex) => errorFn(ex) - case Right(b) => b - } - } -} - -object MainGenericRunner extends MainGenericRunner { - def main(args: Array[String]) { - if (!process(args)) - sys.exit(1) - } -} diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 941ccd9a2d..c1cd3204e0 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -9,7 +9,6 @@ package backend.jvm import java.io.{ DataOutputStream, FileOutputStream, OutputStream, File => JFile } import scala.tools.nsc.io._ import scala.tools.nsc.util.ScalaClassLoader -import scala.tools.util.{ Javap, JavapClass } import java.util.jar.Attributes.Name import scala.language.postfixOps @@ -59,35 +58,6 @@ trait BytecodeWriters { override def close() = writer.close() } - /** To be mixed-in with the BytecodeWriter that generates - * the class file to be disassembled. - */ - trait JavapBytecodeWriter extends BytecodeWriter { - val baseDir = Directory(settings.Ygenjavap.value).createDirectory() - val cl = ScalaClassLoader.appLoader - - def emitJavap(classFile: AbstractFile, javapFile: File) { - val pw = javapFile.printWriter() - try { - val javap = new JavapClass(cl, pw) { - override def findBytes(path: String): Array[Byte] = classFile.toByteArray - } - javap(Seq("-verbose", "-protected", classFile.name)) foreach (_.show()) - } finally pw.close() - } - abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { - super.writeClass(label, jclassName, jclassBytes, sym) - - val classFile = getFile(sym, jclassName, ".class") - val segments = jclassName.split("[./]") - val javapFile = segments.foldLeft(baseDir: Path)(_ / _) changeExtension "javap" toFile; - javapFile.parent.createDirectory() - - if (Javap.isAvailable(cl)) emitJavap(classFile, javapFile) - else warning("No javap on classpath, skipping javap output.") - } - } - trait ClassBytecodeWriter extends BytecodeWriter { def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) { val outfile = getFile(sym, jclassName, ".class") diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 388efb4625..4a3d1805d9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -72,19 +72,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { new DirectToJarfileWriter(f.file) case _ => - import scala.tools.util.Javap - if (settings.Ygenjavap.isDefault) { - if(settings.Ydumpclasses.isDefault) - new ClassBytecodeWriter { } - else - new ClassBytecodeWriter with DumpBytecodeWriter { } - } - else if (Javap.isAvailable()) new ClassBytecodeWriter with JavapBytecodeWriter { } - else { - warning("No javap on classpath, skipping javap output.") + if (settings.Ydumpclasses.isDefault) new ClassBytecodeWriter { } - } - + else + new ClassBytecodeWriter with DumpBytecodeWriter { } // TODO A ScalapBytecodeWriter could take asm.util.Textifier as starting point. // Three areas where javap ouput is less than ideal (e.g. when comparing versions of the same classfile) are: // (a) unreadable pickle; @@ -2519,7 +2510,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { if (nextBlock != whereto) jcode goTo labels(whereto) // SI-6102: Determine whether eliding this JUMP results in an empty range being covered by some EH. - // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range" + // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range" else if (newNormal.isJumpOnly(b) && m.exh.exists(eh => eh.covers(b))) { debugwarn("Had a jump only block that wasn't collapsed") emit(asm.Opcodes.NOP) @@ -3084,7 +3075,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { assert(nonICode.hasNext, "empty block") nonICode.next.isInstanceOf[JUMP] } - + /** * Returns the list of instructions in a block that follow all ICode only instructions, * where an ICode only instruction is one that won't make it to the JVM @@ -3101,7 +3092,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { * Returns the target of a block that is "jump only" which is defined * as being a block that consists only of 0 or more instructions that * won't make it to the JVM followed by a JUMP. - * + * * @param b The basic block to examine * @return Some(target) if b is a "jump only" block or None if it's not */ @@ -3150,12 +3141,12 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { def rephraseGotos(detour: mutable.Map[BasicBlock, BasicBlock]) { def lookup(b: BasicBlock) = detour.getOrElse(b, b) - + m.code.startBlock = lookup(m.code.startBlock) - + for(eh <- m.exh) eh.setStartBlock(lookup(eh.startBlock)) - + for (b <- m.blocks) { def replaceLastInstruction(i: Instruction) = { if (b.lastInstruction != i) { @@ -3164,18 +3155,18 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { b.replaceInstruction(idxLast, i) } } - + b.lastInstruction match { case JUMP(whereto) => replaceLastInstruction(JUMP(lookup(whereto))) case CJUMP(succ, fail, cond, kind) => replaceLastInstruction(CJUMP(lookup(succ), lookup(fail), cond, kind)) - case CZJUMP(succ, fail, cond, kind) => + case CZJUMP(succ, fail, cond, kind) => replaceLastInstruction(CZJUMP(lookup(succ), lookup(fail), cond, kind)) case SWITCH(tags, labels) => val newLabels = (labels map lookup) replaceLastInstruction(SWITCH(tags, newLabels)) - case _ => () + case _ => () } } } @@ -3203,7 +3194,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { // blocks for (key <- detour.keySet) { // we use the Robert Floyd's classic Tortoise and Hare algorithm - @tailrec + @tailrec def findDestination(tortoise: BasicBlock, hare: BasicBlock): BasicBlock = { if (tortoise == hare) // cycle detected, map key to key @@ -3227,7 +3218,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { } detour } - + val detour = computeDetour rephraseGotos(detour) @@ -3235,33 +3226,33 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { val (remappings, cycles) = detour partition {case (source, target) => source != target} for ((source, target) <- remappings) { debuglog(s"Will elide jump only block $source because it can be jumped around to get to $target.") - if (m.startBlock == source) debugwarn("startBlock should have been re-wired by now") + if (m.startBlock == source) debugwarn("startBlock should have been re-wired by now") } val sources = remappings.keySet val targets = remappings.values.toSet val intersection = sources intersect targets - + if (intersection.nonEmpty) debugwarn(s"contradiction: we seem to have some source and target overlap in blocks ${intersection.mkString}. Map was ${detour.mkString}") - + for ((source, _) <- cycles) { debuglog(s"Block $source is in a do-nothing infinite loop. Did the user write 'while(true){}'?") } } } - + /** * Removes all blocks that are unreachable in a method using a standard reachability analysis. */ def elimUnreachableBlocks(m: IMethod) { - assert(m.hasCode, "code-less method") - + assert(m.hasCode, "code-less method") + // assume nothing is reachable until we prove it can be reached val reachable = mutable.Set[BasicBlock]() - + // the set of blocks that we know are reachable but have // yet to be marked reachable, initially only the start block val worklist = mutable.Set(m.startBlock) - + while (worklist.nonEmpty) { val block = worklist.head worklist remove block @@ -3271,7 +3262,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { // think are unreachable worklist ++= (block.successors filterNot reachable) } - + // exception handlers need to be told not to cover unreachable blocks // and exception handlers that no longer cover any blocks need to be // removed entirely @@ -3282,9 +3273,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { unusedExceptionHandlers += exh } } - + // remove the unusued exception handler references - if (settings.debug.value) + if (settings.debug.value) for (exh <- unusedExceptionHandlers) debuglog(s"eliding exception handler $exh because it does not cover any reachable blocks") m.exh = m.exh filterNot unusedExceptionHandlers diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala deleted file mode 100644 index e909cd945d..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala +++ /dev/null @@ -1,108 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - */ - -package scala.tools.nsc -package interpreter - -import scala.tools.nsc.io.AbstractFile -import util.ScalaClassLoader -import java.net.{ URL, URLConnection, URLStreamHandler } -import scala.collection.{ mutable, immutable } - -/** - * A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}. - * - * @author Lex Spoon - */ -class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) - extends ClassLoader(parent) - with ScalaClassLoader -{ - protected def classNameToPath(name: String): String = - if (name endsWith ".class") name - else name.replace('.', '/') + ".class" - - protected def findAbstractFile(name: String): AbstractFile = { - var file: AbstractFile = root - val pathParts = name split '/' - - for (dirPart <- pathParts.init) { - file = file.lookupName(dirPart, directory = true) - if (file == null) - return null - } - - file.lookupName(pathParts.last, directory = false) match { - case null => null - case file => file - } - } - - protected def dirNameToPath(name: String): String = - name.replace('.', '/') - - protected def findAbstractDir(name: String): AbstractFile = { - var file: AbstractFile = root - val pathParts = dirNameToPath(name) split '/' - - for (dirPart <- pathParts) { - file = file.lookupName(dirPart, directory = true) - if (file == null) - return null - } - - file - } - - // parent delegation in JCL uses getResource; so either add parent.getResAsStream - // or implement findResource, which we do here as a study in scarlet (my complexion - // after looking at CLs and URLs) - override def findResource(name: String): URL = findAbstractFile(name) match { - case null => null - case file => new URL(null, "repldir:" + file.path, new URLStreamHandler { - override def openConnection(url: URL): URLConnection = new URLConnection(url) { - override def connect() { } - override def getInputStream = file.input - } - }) - } - - // this inverts delegation order: super.getResAsStr calls parent.getRes if we fail - override def getResourceAsStream(name: String) = findAbstractFile(name) match { - case null => super.getResourceAsStream(name) - case file => file.input - } - // ScalaClassLoader.classBytes uses getResAsStream, so we'll try again before delegating - override def classBytes(name: String): Array[Byte] = findAbstractFile(classNameToPath(name)) match { - case null => super.classBytes(name) - case file => file.toByteArray - } - override def findClass(name: String): JClass = { - val bytes = classBytes(name) - if (bytes.length == 0) - throw new ClassNotFoundException(name) - else - defineClass(name, bytes, 0, bytes.length) - } - - private val packages = mutable.Map[String, Package]() - - override def definePackage(name: String, specTitle: String, specVersion: String, specVendor: String, implTitle: String, implVersion: String, implVendor: String, sealBase: URL): Package = { - throw new UnsupportedOperationException() - } - - override def getPackage(name: String): Package = { - findAbstractDir(name) match { - case null => super.getPackage(name) - case file => packages.getOrElseUpdate(name, { - val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader]) - ctor.setAccessible(true) - ctor.newInstance(name, null, null, null, null, null, null, null, this) - }) - } - } - - override def getPackages(): Array[Package] = - root.iterator.filter(_.isDirectory).map(dir => getPackage(dir.name)).toArray -} diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala deleted file mode 100644 index e66e4eff29..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends PartialFunction[Throwable, T] { - def isDefinedAt(t: Throwable) = t match { - case _: AbstractMethodError => true - case _: NoSuchMethodError => true - case _: MissingRequirementError => true - case _: NoClassDefFoundError => true - case _ => false - } - def apply(t: Throwable) = t match { - case x @ (_: AbstractMethodError | _: NoSuchMethodError | _: NoClassDefFoundError) => - onError(""" - |Failed to initialize compiler: %s. - |This is most often remedied by a full clean and recompile. - |Otherwise, your classpath may continue bytecode compiled by - |different and incompatible versions of scala. - |""".stripMargin.format(x.getClass.getName split '.' last) - ) - x.printStackTrace() - value - case x: MissingRequirementError => - onError(""" - |Failed to initialize compiler: %s not found. - |** Note that as of 2.8 scala does not assume use of the java classpath. - |** For the old behavior pass -usejavacp to scala, or if using a Settings - |** object programatically, settings.usejavacp.value = true.""".stripMargin.format(x.req) - ) - value - } -} - -object AbstractOrMissingHandler { - def apply[T]() = new AbstractOrMissingHandler[T](Console println _, null.asInstanceOf[T]) -} diff --git a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala deleted file mode 100644 index 48890a21c6..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala +++ /dev/null @@ -1,42 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import java.lang.reflect -import util.ScalaClassLoader -import ScalaClassLoader.appLoader -import scala.reflect.NameTransformer._ - -object ByteCode { - /** Until I figure out why I can't get scalap onto the classpath such - * that the compiler will bootstrap, we have to use reflection. - */ - private lazy val DECODER: Option[AnyRef] = - for (clazz <- appLoader.tryToLoadClass[AnyRef]("scala.tools.scalap.Decode$")) yield - clazz.getField(MODULE_INSTANCE_NAME).get(null) - - private def decoderMethod(name: String, args: JClass*): Option[reflect.Method] = { - for (decoder <- DECODER ; m <- Option(decoder.getClass.getMethod(name, args: _*))) yield m - } - - private lazy val aliasMap = { - for (module <- DECODER ; method <- decoderMethod("typeAliases", classOf[String])) yield - method.invoke(module, _: String).asInstanceOf[Option[Map[String, String]]] - } - - /** Scala sig bytes. - */ - def scalaSigBytesForPath(path: String) = - for { - module <- DECODER - method <- decoderMethod("scalaSigAnnotationBytes", classOf[String]) - names <- method.invoke(module, path).asInstanceOf[Option[Array[Byte]]] - } - yield names - - def aliasesForPackage(pkg: String) = aliasMap flatMap (_(pkg)) -} diff --git a/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala b/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala deleted file mode 100644 index 0ab92ab769..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/CommandLine.scala +++ /dev/null @@ -1,13 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Lex Spoon - */ - -package scala.tools.nsc -package interpreter - -/** A command line for the interpreter. - */ -class CommandLine(arguments: List[String], error: String => Unit) extends CompilerCommand(arguments, error) { - override def cmdName = "scala" -} diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala deleted file mode 100644 index 84a5cb49ae..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala +++ /dev/null @@ -1,49 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import Completion._ - -/** An implementation-agnostic completion interface which makes no - * reference to the jline classes. - */ -trait Completion { - type ExecResult - def resetVerbosity(): Unit - def completer(): ScalaCompleter -} -object NoCompletion extends Completion { - type ExecResult = Nothing - def resetVerbosity() = () - def completer() = NullCompleter -} - -object Completion { - case class Candidates(cursor: Int, candidates: List[String]) { } - val NoCandidates = Candidates(-1, Nil) - - object NullCompleter extends ScalaCompleter { - def complete(buffer: String, cursor: Int): Candidates = NoCandidates - } - trait ScalaCompleter { - def complete(buffer: String, cursor: Int): Candidates - } - - def looksLikeInvocation(code: String) = ( - (code != null) - && (code startsWith ".") - && !(code == ".") - && !(code startsWith "./") - && !(code startsWith "..") - ) - object Forwarder { - def apply(forwardTo: () => Option[CompletionAware]): CompletionAware = new CompletionAware { - def completions(verbosity: Int) = forwardTo() map (_ completions verbosity) getOrElse Nil - override def follow(s: String) = forwardTo() flatMap (_ follow s) - } - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala deleted file mode 100644 index 3dd5d93390..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/CompletionAware.scala +++ /dev/null @@ -1,53 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -/** An interface for objects which are aware of tab completion and - * will supply their own candidates and resolve their own paths. - */ -trait CompletionAware { - /** The complete list of unqualified Strings to which this - * object will complete. - */ - def completions(verbosity: Int): List[String] - - /** The next completor in the chain. - */ - def follow(id: String): Option[CompletionAware] = None - - /** A list of useful information regarding a specific uniquely - * identified completion. This is specifically written for the - * following situation, but should be useful elsewhere too: - * - * x.y.z.methodName - * - * If "methodName" is among z's completions, and verbosity > 0 - * indicating tab has been pressed twice consecutively, then we - * call alternativesFor and show a list of overloaded method - * signatures. - */ - def alternativesFor(id: String): List[String] = Nil - - /** Given string 'buf', return a list of all the strings - * to which it can complete. This may involve delegating - * to other CompletionAware objects. - */ - def completionsFor(parsed: Parsed): List[String] = { - import parsed.{ buffer, verbosity } - val comps = completions(verbosity) filter (_ startsWith buffer) - val exact = comps contains buffer - - val results = - if (parsed.isEmpty) comps - else if (parsed.isUnqualified && !parsed.isLastDelimiter) - if (verbosity > 0 && exact) alternativesFor(buffer) - else comps - else follow(parsed.bufferHead) map (_ completionsFor parsed.bufferTail) getOrElse Nil - - results.sorted - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala deleted file mode 100644 index d24ad60974..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala +++ /dev/null @@ -1,85 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -/** This has a lot of duplication with other methods in Symbols and Types, - * but repl completion utility is very sensitive to precise output. Best - * thing would be to abstract an interface for how such things are printed, - * as is also in progress with error messages. - */ -trait CompletionOutput { - val global: Global - - import global._ - import definitions.{ isTupleType, isFunctionType, isRepeatedParamType } - - /** Reducing fully qualified noise for some common packages. - */ - val typeTransforms = List( - "java.lang." -> "", - "scala.collection.immutable." -> "immutable.", - "scala.collection.mutable." -> "mutable.", - "scala.collection.generic." -> "generic." - ) - - def quietString(tp: String): String = - typeTransforms.foldLeft(tp) { - case (str, (prefix, replacement)) => - if (str startsWith prefix) replacement + (str stripPrefix prefix) - else str - } - - class MethodSymbolOutput(method: Symbol) { - val pkg = method.ownerChain find (_.isPackageClass) map (_.fullName) getOrElse "" - - def relativize(str: String): String = quietString(str stripPrefix (pkg + ".")) - def relativize(tp: Type): String = relativize(tp.dealiasWiden.toString) - - def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]") - def parenList(params: List[Any]) = params.mkString("(", ", ", ")") - - def methodTypeToString(mt: MethodType) = - (mt.paramss map paramsString mkString "") + ": " + relativize(mt.finalResultType) - - def typeToString(tp: Type): String = relativize( - tp match { - case x if isFunctionType(x) => functionString(x) - case x if isTupleType(x) => tupleString(x) - case x if isRepeatedParamType(x) => typeToString(x.typeArgs.head) + "*" - case mt @ MethodType(_, _) => methodTypeToString(mt) - case x => x.toString - } - ) - - def tupleString(tp: Type) = parenList(tp.dealiasWiden.typeArgs map relativize) - def functionString(tp: Type) = tp.dealiasWiden.typeArgs match { - case List(t, r) => t + " => " + r - case xs => parenList(xs.init) + " => " + xs.last - } - - def tparamsString(tparams: List[Symbol]) = braceList(tparams map (_.defString)) - def paramsString(params: List[Symbol]) = { - def paramNameString(sym: Symbol) = if (sym.isSynthetic) "" else sym.nameString + ": " - def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.dealiasWiden) - - val isImplicit = params.nonEmpty && params.head.isImplicit - val strs = (params map paramString) match { - case x :: xs if isImplicit => ("implicit " + x) :: xs - case xs => xs - } - parenList(strs) - } - - def methodString() = - method.keyString + " " + method.nameString + (method.info.dealiasWiden match { - case NullaryMethodType(resType) => ": " + typeToString(resType) - case PolyType(tparams, resType) => tparamsString(tparams) + typeToString(resType) - case mt @ MethodType(_, _) => methodTypeToString(mt) - case x => x.toString - }) - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala b/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala deleted file mode 100644 index 48af261937..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala +++ /dev/null @@ -1,63 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import scala.tools.jline.console.{ ConsoleReader, CursorBuffer } - -trait ConsoleReaderHelper extends ConsoleReader { - def terminal = getTerminal() - def width = terminal.getWidth() - def height = terminal.getHeight() - - def readOneKey(prompt: String): Int - def eraseLine(): Unit - - private val marginSize = 3 - private def morePrompt = "--More--" - private def emulateMore(): Int = { - val key = readOneKey(morePrompt) - try key match { - case '\r' | '\n' => 1 - case 'q' => -1 - case _ => height - 1 - } - finally { - eraseLine() - // TODO: still not quite managing to erase --More-- and get - // back to a scala prompt without another keypress. - if (key == 'q') { - putString(getPrompt()) - redrawLine() - flush() - } - } - } - - override def printColumns(items: JCollection[_ <: CharSequence]): Unit = - printColumns(items: List[String]) - - def printColumns(items: List[String]): Unit = { - if (items forall (_ == "")) - return - - val longest = items map (_.length) max - var linesLeft = if (isPaginationEnabled()) height - 1 else Int.MaxValue - val columnSize = longest + marginSize - val padded = items map ("%-" + columnSize + "s" format _) - val groupSize = 1 max (width / columnSize) // make sure it doesn't divide to 0 - - padded grouped groupSize foreach { xs => - println(xs.mkString) - linesLeft -= 1 - if (linesLeft <= 0) { - linesLeft = emulateMore() - if (linesLeft < 0) - return - } - } - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/Delimited.scala b/src/compiler/scala/tools/nsc/interpreter/Delimited.scala deleted file mode 100644 index e88a044931..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/Delimited.scala +++ /dev/null @@ -1,41 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import scala.tools.jline.console.completer.ArgumentCompleter.{ ArgumentDelimiter, ArgumentList } - -class JLineDelimiter extends ArgumentDelimiter { - def toJLine(args: List[String], cursor: Int) = args match { - case Nil => new ArgumentList(new Array[String](0), 0, 0, cursor) - case xs => new ArgumentList(xs.toArray, xs.size - 1, xs.last.length, cursor) - } - - def delimit(buffer: CharSequence, cursor: Int) = { - val p = Parsed(buffer.toString, cursor) - toJLine(p.args, cursor) - } - def isDelimiter(buffer: CharSequence, cursor: Int) = Parsed(buffer.toString, cursor).isDelimiter -} - -trait Delimited { - self: Parsed => - - def delimited: Char => Boolean - def escapeChars: List[Char] = List('\\') - - /** Break String into args based on delimiting function. - */ - protected def toArgs(s: String): List[String] = - if (s == "") Nil - else (s indexWhere isDelimiterChar) match { - case -1 => List(s) - case idx => (s take idx) :: toArgs(s drop (idx + 1)) - } - - def isDelimiterChar(ch: Char) = delimited(ch) - def isEscapeChar(ch: Char): Boolean = escapeChars contains ch -} diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala deleted file mode 100644 index 9edd54b939..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala +++ /dev/null @@ -1,99 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import scala.tools.nsc.ast.parser.Tokens.EOF - -trait ExprTyper { - val repl: IMain - - import repl._ - import global.{ reporter => _, Import => _, _ } - import definitions._ - import syntaxAnalyzer.UnitParser - import naming.freshInternalVarName - - object codeParser { - val global: repl.global.type = repl.global - def applyRule[T](code: String, rule: UnitParser => T): T = { - reporter.reset() - val scanner = newUnitParser(code) - val result = rule(scanner) - - if (!reporter.hasErrors) - scanner.accept(EOF) - - result - } - def stmts(code: String) = applyRule(code, _.templateStats()) - } - - /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */ - def parse(line: String): Option[List[Tree]] = debugging(s"""parse("$line")""") { - var isIncomplete = false - reporter.withIncompleteHandler((_, _) => isIncomplete = true) { - val trees = codeParser.stmts(line) - if (reporter.hasErrors) Some(Nil) - else if (isIncomplete) None - else Some(trees) - } - } - - def symbolOfLine(code: String): Symbol = { - def asExpr(): Symbol = { - val name = freshInternalVarName() - // Typing it with a lazy val would give us the right type, but runs - // into compiler bugs with things like existentials, so we compile it - // behind a def and strip the NullaryMethodType which wraps the expr. - val line = "def " + name + " = " + code - - interpretSynthetic(line) match { - case IR.Success => - val sym0 = symbolOfTerm(name) - // drop NullaryMethodType - sym0.cloneSymbol setInfo exitingTyper(sym0.info.finalResultType) - case _ => NoSymbol - } - } - def asDefn(): Symbol = { - val old = repl.definedSymbolList.toSet - - interpretSynthetic(code) match { - case IR.Success => - repl.definedSymbolList filterNot old match { - case Nil => NoSymbol - case sym :: Nil => sym - case syms => NoSymbol.newOverloaded(NoPrefix, syms) - } - case _ => NoSymbol - } - } - def asError(): Symbol = { - interpretSynthetic(code) - NoSymbol - } - beSilentDuring(asExpr()) orElse beSilentDuring(asDefn()) orElse asError() - } - - private var typeOfExpressionDepth = 0 - def typeOfExpression(expr: String, silent: Boolean = true): Type = { - if (typeOfExpressionDepth > 2) { - repldbg("Terminating typeOfExpression recursion for expression: " + expr) - return NoType - } - typeOfExpressionDepth += 1 - // Don't presently have a good way to suppress undesirable success output - // while letting errors through, so it is first trying it silently: if there - // is an error, and errors are desired, then it re-evaluates non-silently - // to induce the error message. - try beSilentDuring(symbolOfLine(expr).tpe) match { - case NoType if !silent => symbolOfLine(expr).tpe // generate error - case tpe => tpe - } - finally typeOfExpressionDepth -= 1 - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/Formatting.scala b/src/compiler/scala/tools/nsc/interpreter/Formatting.scala deleted file mode 100644 index 43e653edfd..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/Formatting.scala +++ /dev/null @@ -1,35 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package interpreter - -import util.stringFromWriter - -trait Formatting { - def prompt: String - - def spaces(code: String): String = { - /** Heuristic to avoid indenting and thereby corrupting """-strings and XML literals. */ - val tokens = List("\"\"\"", "") - val noIndent = (code contains "\n") && (tokens exists code.contains) - - if (noIndent) "" - else prompt drop 1 map (_ => ' ') - } - /** Indent some code by the width of the scala> prompt. - * This way, compiler error messages read better. - */ - def indentCode(code: String) = { - val indent = spaces(code) - stringFromWriter(str => - for (line <- code.lines) { - str print indent - str print (line + "\n") - str.flush() - } - ) - } -} diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala deleted file mode 100644 index 2ea255319d..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ /dev/null @@ -1,749 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Alexander Spoon - */ - -package scala.tools.nsc -package interpreter - -import Predef.{ println => _, _ } -import java.io.{ BufferedReader, FileReader } -import session._ -import scala.annotation.tailrec -import scala.util.Properties.{ jdkHome, javaVersion, versionString, javaVmName } -import scala.tools.util.{ Javap } -import util.{ ClassPath, Exceptional, stringFromWriter, stringFromStream } -import io.{ File, Directory } -import util.ScalaClassLoader -import ScalaClassLoader._ -import scala.tools.util._ -import scala.language.{implicitConversions, existentials} -import scala.reflect.classTag -import scala.tools.reflect.StdRuntimeTags._ -import scala.concurrent.{ ExecutionContext, Await, Future, future } -import ExecutionContext.Implicits._ - -/** The Scala interactive shell. It provides a read-eval-print loop - * around the Interpreter class. - * After instantiation, clients should call the main() method. - * - * 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. - * - * @author Moez A. Abdel-Gawad - * @author Lex Spoon - * @version 1.2 - */ -class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) - extends AnyRef - with LoopCommands -{ - def this(in0: BufferedReader, out: JPrintWriter) = this(Some(in0), out) - def this() = this(None, new JPrintWriter(Console.out, true)) - - @deprecated("Use `intp` instead.", "2.9.0") def interpreter = intp - @deprecated("Use `intp` instead.", "2.9.0") def interpreter_= (i: Interpreter): Unit = intp = i - - var in: InteractiveReader = _ // the input stream from which commands come - var settings: Settings = _ - var intp: IMain = _ - - private var globalFuture: Future[Boolean] = _ - - /** Print a welcome message */ - def printWelcome() { - echo(s""" - |Welcome to Scala $versionString ($javaVmName, Java $javaVersion). - |Type in expressions to have them evaluated. - |Type :help for more information.""".trim.stripMargin - ) - replinfo("[info] started at " + new java.util.Date) - } - - protected def asyncMessage(msg: String) { - if (isReplInfo || isReplPower) - echoAndRefresh(msg) - } - - override def echoCommandMessage(msg: String) { - intp.reporter printUntruncatedMessage msg - } - - lazy val power = new Power(intp, new StdReplVals(this))(tagOfStdReplVals, classTag[StdReplVals]) - def history = in.history - - // classpath entries added via :cp - var addedClasspath: String = "" - - /** A reverse list of commands to replay if the user requests a :replay */ - var replayCommandStack: List[String] = Nil - - /** A list of commands to replay if the user requests a :replay */ - def replayCommands = replayCommandStack.reverse - - /** Record a command for replay should the user request a :replay */ - def addReplay(cmd: String) = replayCommandStack ::= cmd - - def savingReplayStack[T](body: => T): T = { - val saved = replayCommandStack - try body - finally replayCommandStack = saved - } - def savingReader[T](body: => T): T = { - val saved = in - try body - finally in = saved - } - - /** Close the interpreter and set the var to null. */ - def closeInterpreter() { - if (intp ne null) { - intp.close() - intp = null - } - } - - class ILoopInterpreter extends IMain(settings, out) { - outer => - - override lazy val formatting = new Formatting { - def prompt = ILoop.this.prompt - } - override protected def parentClassLoader = - settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader ) - } - - /** Create a new interpreter. */ - def createInterpreter() { - if (addedClasspath != "") - settings.classpath append addedClasspath - - intp = new ILoopInterpreter - } - - /** print a friendly help message */ - def helpCommand(line: String): Result = { - if (line == "") helpSummary() - else uniqueCommand(line) match { - case Some(lc) => echo("\n" + lc.help) - case _ => ambiguousError(line) - } - } - private def helpSummary() = { - val usageWidth = commands map (_.usageMsg.length) max - val formatStr = "%-" + usageWidth + "s %s" - - echo("All commands can be abbreviated, e.g. :he instead of :help.") - - commands foreach { cmd => - echo(formatStr.format(cmd.usageMsg, cmd.help)) - } - } - private def ambiguousError(cmd: String): Result = { - matchingCommands(cmd) match { - case Nil => echo(cmd + ": no such command. Type :help for help.") - case xs => echo(cmd + " is ambiguous: did you mean " + xs.map(":" + _.name).mkString(" or ") + "?") - } - Result(keepRunning = true, None) - } - private def matchingCommands(cmd: String) = commands filter (_.name startsWith cmd) - private def uniqueCommand(cmd: String): Option[LoopCommand] = { - // this lets us add commands willy-nilly and only requires enough command to disambiguate - matchingCommands(cmd) match { - case List(x) => Some(x) - // exact match OK even if otherwise appears ambiguous - case xs => xs find (_.name == cmd) - } - } - - /** Show the history */ - lazy val historyCommand = new LoopCommand("history", "show the history (optional num is commands to show)") { - override def usage = "[num]" - def defaultLines = 20 - - def apply(line: String): Result = { - if (history eq NoHistory) - return "No history available." - - val xs = words(line) - val current = history.index - val count = try xs.head.toInt catch { case _: Exception => defaultLines } - val lines = history.asStrings takeRight count - val offset = current - lines.size + 1 - - for ((line, index) <- lines.zipWithIndex) - echo("%3d %s".format(index + offset, line)) - } - } - - // When you know you are most likely breaking into the middle - // of a line being typed. This softens the blow. - protected def echoAndRefresh(msg: String) = { - echo("\n" + msg) - in.redrawLine() - } - protected def echo(msg: String) = { - out println msg - out.flush() - } - - /** Search the history */ - def searchHistory(_cmdline: String) { - val cmdline = _cmdline.toLowerCase - val offset = history.index - history.size + 1 - - for ((line, index) <- history.asStrings.zipWithIndex ; if line.toLowerCase contains cmdline) - echo("%d %s".format(index + offset, line)) - } - - private val currentPrompt = Properties.shellPromptString - - /** Prompt to print when awaiting input */ - def prompt = currentPrompt - - import LoopCommand.{ cmd, nullary } - - /** Standard commands **/ - lazy val standardCommands = List( - cmd("cp", "", "add a jar or directory to the classpath", addClasspath), - cmd("help", "[command]", "print this summary or command-specific help", helpCommand), - historyCommand, - cmd("h?", "", "search the history", searchHistory), - cmd("imports", "[name name ...]", "show import history, identifying sources of names", importsCommand), - cmd("implicits", "[-v]", "show the implicits in scope", intp.implicitsCommand), - cmd("javap", "", "disassemble a file or class name", javapCommand), - cmd("load", "", "load and interpret a Scala file", loadCommand), - nullary("paste", "enter paste mode: all input up to ctrl-D compiled together", pasteCommand), - nullary("power", "enable power user mode", powerCmd), - nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)), - nullary("replay", "reset execution and replay all previous commands", replay), - nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand), - shCommand, - nullary("silent", "disable/enable automatic printing of results", verbosity), - cmd("type", "[-v] ", "display the type of an expression without evaluating it", typeCommand), - nullary("warnings", "show the suppressed warnings from the most recent line which had any", warningsCommand) - ) - - /** Power user commands */ - lazy val powerCommands: List[LoopCommand] = List( - cmd("phase", "", "set the implicit phase for power commands", phaseCommand) - ) - - private def importsCommand(line: String): Result = { - val tokens = words(line) - val handlers = intp.languageWildcardHandlers ++ intp.importHandlers - - handlers.filterNot(_.importedSymbols.isEmpty).zipWithIndex foreach { - case (handler, idx) => - val (types, terms) = handler.importedSymbols partition (_.name.isTypeName) - val imps = handler.implicitSymbols - val found = tokens filter (handler importsSymbolNamed _) - val typeMsg = if (types.isEmpty) "" else types.size + " types" - val termMsg = if (terms.isEmpty) "" else terms.size + " terms" - val implicitMsg = if (imps.isEmpty) "" else imps.size + " are implicit" - val foundMsg = if (found.isEmpty) "" else found.mkString(" // imports: ", ", ", "") - val statsMsg = List(typeMsg, termMsg, implicitMsg) filterNot (_ == "") mkString ("(", ", ", ")") - - intp.reporter.printMessage("%2d) %-30s %s%s".format( - idx + 1, - handler.importString, - statsMsg, - foundMsg - )) - } - } - - private def findToolsJar() = { - val jdkPath = Directory(jdkHome) - val jar = jdkPath / "lib" / "tools.jar" toFile - - if (jar isFile) - Some(jar) - else if (jdkPath.isDirectory) - jdkPath.deepFiles find (_.name == "tools.jar") - else None - } - private def addToolsJarToLoader() = { - val cl = findToolsJar() match { - case Some(tools) => ScalaClassLoader.fromURLs(Seq(tools.toURL), intp.classLoader) - case _ => intp.classLoader - } - if (Javap.isAvailable(cl)) { - repldbg(":javap available.") - cl - } - else { - repldbg(":javap unavailable: no tools.jar at " + jdkHome) - intp.classLoader - } - } - - protected def newJavap() = - JavapClass(addToolsJarToLoader(), new IMain.ReplStrippingWriter(intp), Some(intp)) - - private lazy val javap = substituteAndLog[Javap]("javap", NoJavap)(newJavap()) - - // Still todo: modules. - private def typeCommand(line0: String): Result = { - line0.trim match { - case "" => ":type [-v] " - case s if s startsWith "-v " => intp.typeCommandInternal(s stripPrefix "-v " trim, verbose = true) - case s => intp.typeCommandInternal(s, verbose = false) - } - } - - private def warningsCommand(): Result = { - if (intp.lastWarnings.isEmpty) - "Can't find any cached warnings." - else - intp.lastWarnings foreach { case (pos, msg) => intp.reporter.warning(pos, msg) } - } - - private def javapCommand(line: String): Result = { - if (javap == null) - ":javap unavailable, no tools.jar at %s. Set JDK_HOME.".format(jdkHome) - else if (line == "") - ":javap [-lcsvp] [path1 path2 ...]" - else - javap(words(line)) foreach { res => - if (res.isError) return "Failed: " + res.value - else res.show() - } - } - - private def pathToPhaseWrapper = intp.originalPath("$r") + ".phased.atCurrent" - - private def phaseCommand(name: String): Result = { - val phased: Phased = power.phased - import phased.NoPhaseName - - if (name == "clear") { - phased.set(NoPhaseName) - intp.clearExecutionWrapper() - "Cleared active phase." - } - else if (name == "") phased.get match { - case NoPhaseName => "Usage: :phase (e.g. typer, erasure.next, erasure+3)" - case ph => "Active phase is '%s'. (To clear, :phase clear)".format(phased.get) - } - else { - val what = phased.parse(name) - if (what.isEmpty || !phased.set(what)) - "'" + name + "' does not appear to represent a valid phase." - else { - intp.setExecutionWrapper(pathToPhaseWrapper) - val activeMessage = - if (what.toString.length == name.length) "" + what - else "%s (%s)".format(what, name) - - "Active phase is now: " + activeMessage - } - } - } - - /** Available commands */ - def commands: List[LoopCommand] = standardCommands ++ ( - if (isReplPower) powerCommands else Nil - ) - - val replayQuestionMessage = - """|That entry seems to have slain the compiler. Shall I replay - |your session? I can re-run each line except the last one. - |[y/n] - """.trim.stripMargin - - private val crashRecovery: PartialFunction[Throwable, Boolean] = { - case ex: Throwable => - echo(intp.global.throwableAsString(ex)) - - ex match { - case _: NoSuchMethodError | _: NoClassDefFoundError => - echo("\nUnrecoverable error.") - throw ex - case _ => - def fn(): Boolean = - try in.readYesOrNo(replayQuestionMessage, { echo("\nYou must enter y or n.") ; fn() }) - catch { case _: RuntimeException => false } - - if (fn()) replay() - else echo("\nAbandoning crashed session.") - } - true - } - - // return false if repl should exit - def processLine(line: String): Boolean = { - import scala.concurrent.duration._ - Await.ready(globalFuture, 60.seconds) - - (line ne null) && (command(line) match { - case Result(false, _) => false - case Result(_, Some(line)) => addReplay(line) ; true - case _ => true - }) - } - - private def readOneLine() = { - out.flush() - in readLine prompt - } - - /** The main read-eval-print loop for the repl. It calls - * command() for each line of input, and stops when - * command() returns false. - */ - @tailrec final def loop() { - if ( try processLine(readOneLine()) catch crashRecovery ) - loop() - } - - /** interpret all lines from a specified file */ - def interpretAllFrom(file: File) { - savingReader { - savingReplayStack { - file applyReader { reader => - in = SimpleReader(reader, out, interactive = false) - echo("Loading " + file + "...") - loop() - } - } - } - } - - /** create a new interpreter and replay the given commands */ - def replay() { - reset() - if (replayCommandStack.isEmpty) - echo("Nothing to replay.") - else for (cmd <- replayCommands) { - echo("Replaying: " + cmd) // flush because maybe cmd will have its own output - command(cmd) - echo("") - } - } - def resetCommand() { - echo("Resetting interpreter state.") - if (replayCommandStack.nonEmpty) { - echo("Forgetting this session history:\n") - replayCommands foreach echo - echo("") - replayCommandStack = Nil - } - if (intp.namedDefinedTerms.nonEmpty) - echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", ")) - if (intp.definedTypes.nonEmpty) - echo("Forgetting defined types: " + intp.definedTypes.mkString(", ")) - - reset() - } - def reset() { - intp.reset() - unleashAndSetPhase() - } - - /** fork a shell and run a command */ - lazy val shCommand = new LoopCommand("sh", "run a shell command (result is implicitly => List[String])") { - override def usage = "" - def apply(line: String): Result = line match { - case "" => showUsage() - case _ => - val toRun = classOf[ProcessResult].getName + "(" + string2codeQuoted(line) + ")" - intp interpret toRun - () - } - } - - def withFile(filename: String)(action: File => Unit) { - val f = File(filename) - - if (f.exists) action(f) - else echo("That file does not exist") - } - - def loadCommand(arg: String) = { - var shouldReplay: Option[String] = None - withFile(arg)(f => { - interpretAllFrom(f) - shouldReplay = Some(":load " + arg) - }) - Result(keepRunning = true, shouldReplay) - } - - def addClasspath(arg: String): Unit = { - val f = File(arg).normalize - if (f.exists) { - addedClasspath = ClassPath.join(addedClasspath, f.path) - val totalClasspath = ClassPath.join(settings.classpath.value, addedClasspath) - echo("Added '%s'. Your new classpath is:\n\"%s\"".format(f.path, totalClasspath)) - replay() - } - else echo("The path '" + f + "' doesn't seem to exist.") - } - - def powerCmd(): Result = { - if (isReplPower) "Already in power mode." - else enablePowerMode(isDuringInit = false) - } - def enablePowerMode(isDuringInit: Boolean) = { - replProps.power setValue true - unleashAndSetPhase() - asyncEcho(isDuringInit, power.banner) - } - private def unleashAndSetPhase() { - if (isReplPower) { - power.unleash() - // Set the phase to "typer" - intp beSilentDuring phaseCommand("typer") - } - } - - def asyncEcho(async: Boolean, msg: => String) { - if (async) asyncMessage(msg) - else echo(msg) - } - - def verbosity() = { - val old = intp.printResults - intp.printResults = !old - echo("Switched " + (if (old) "off" else "on") + " result printing.") - } - - /** Run one command submitted by the user. Two values are returned: - * (1) whether to keep running, (2) the line to record for replay, - * if any. */ - def command(line: String): Result = { - if (line startsWith ":") { - val cmd = line.tail takeWhile (x => !x.isWhitespace) - uniqueCommand(cmd) match { - case Some(lc) => lc(line.tail stripPrefix cmd dropWhile (_.isWhitespace)) - case _ => ambiguousError(cmd) - } - } - else if (intp.global == null) Result(keepRunning = false, None) // Notice failure to create compiler - else Result(keepRunning = true, interpretStartingWith(line)) - } - - private def readWhile(cond: String => Boolean) = { - Iterator continually in.readLine("") takeWhile (x => x != null && cond(x)) - } - - def pasteCommand(): Result = { - echo("// Entering paste mode (ctrl-D to finish)\n") - val code = readWhile(_ => true) mkString "\n" - echo("\n// Exiting paste mode, now interpreting.\n") - intp interpret code - () - } - - private object paste extends Pasted { - val ContinueString = " | " - val PromptString = "scala> " - - def interpret(line: String): Unit = { - echo(line.trim) - intp interpret line - echo("") - } - - def transcript(start: String) = { - echo("\n// Detected repl transcript paste: ctrl-D to finish.\n") - apply(Iterator(start) ++ readWhile(_.trim != PromptString.trim)) - } - } - import paste.{ ContinueString, PromptString } - - /** Interpret expressions starting with the first line. - * Read lines until a complete compilation unit is available - * or until a syntax error has been seen. If a full unit is - * read, go ahead and interpret it. Return the full string - * to be recorded for replay, if any. - */ - def interpretStartingWith(code: String): Option[String] = { - // signal completion non-completion input has been received - in.completion.resetVerbosity() - - def reallyInterpret = { - val reallyResult = intp.interpret(code) - (reallyResult, reallyResult match { - case IR.Error => None - case IR.Success => Some(code) - case IR.Incomplete => - if (in.interactive && code.endsWith("\n\n")) { - echo("You typed two blank lines. Starting a new command.") - None - } - else in.readLine(ContinueString) match { - case null => - // we know compilation is going to fail since we're at EOF and the - // 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. - intp.compileString(code) - None - - case line => interpretStartingWith(code + "\n" + line) - } - }) - } - - /** Here we place ourselves between the user and the interpreter and examine - * the input they are ostensibly submitting. We intervene in several cases: - * - * 1) If the line starts with "scala> " it is assumed to be an interpreter paste. - * 2) If the line starts with "." (but not ".." or "./") it is treated as an invocation - * on the previous result. - * 3) If the Completion object's execute returns Some(_), we inject that value - * and avoid the interpreter, as it's likely not valid scala code. - */ - if (code == "") None - else if (!paste.running && code.trim.startsWith(PromptString)) { - paste.transcript(code) - None - } - else if (Completion.looksLikeInvocation(code) && intp.mostRecentVar != "") { - interpretStartingWith(intp.mostRecentVar + code) - } - else if (code.trim startsWith "//") { - // line comment, do nothing - None - } - else - reallyInterpret._2 - } - - // runs :load `file` on any files passed via -i - def loadFiles(settings: Settings) = settings match { - case settings: GenericRunnerSettings => - for (filename <- settings.loadfiles.value) { - val cmd = ":load " + filename - command(cmd) - addReplay(cmd) - echo("") - } - case _ => - } - - /** Tries to create a JLineReader, falling back to SimpleReader: - * unless settings or properties are such that it should start - * with SimpleReader. - */ - def chooseReader(settings: Settings): InteractiveReader = { - if (settings.Xnojline.value || Properties.isEmacsShell) - SimpleReader() - else try new JLineReader( - if (settings.noCompletion.value) NoCompletion - else new JLineCompletion(intp) - ) - catch { - case ex @ (_: Exception | _: NoClassDefFoundError) => - echo("Failed to created JLineReader: " + ex + "\nFalling back to SimpleReader.") - SimpleReader() - } - } - - private def loopPostInit() { - in match { - case x: JLineReader => x.consoleReader.postInit - case _ => - } - // Bind intp somewhere out of the regular namespace where - // we can get at it in generated code. - intp.quietBind(NamedParam[IMain]("$intp", intp)(tagOfIMain, classTag[IMain])) - // Auto-run code via some setting. - ( replProps.replAutorunCode.option - flatMap (f => io.File(f).safeSlurp()) - foreach (intp quietRun _) - ) - // classloader and power mode setup - intp.setContextClassLoader() - if (isReplPower) { - replProps.power setValue true - unleashAndSetPhase() - asyncMessage(power.banner) - } - } - def process(settings: Settings): Boolean = savingContextLoader { - this.settings = settings - createInterpreter() - - // sets in to some kind of reader depending on environmental cues - in = in0.fold(chooseReader(settings))(r => SimpleReader(r, out, interactive = true)) - globalFuture = future { - intp.initializeSynchronous() - loopPostInit() - loadFiles(settings) - !intp.reporter.hasErrors - } - printWelcome() - - try loop() - catch AbstractOrMissingHandler() - finally closeInterpreter() - - true - } - - @deprecated("Use `process` instead", "2.9.0") - def main(settings: Settings): Unit = process(settings) //used by sbt -} - -object ILoop { - implicit def loopToInterpreter(repl: ILoop): IMain = repl.intp - - // Designed primarily for use by test code: take a String with a - // bunch of code, and prints out a transcript of what it would look - // like if you'd just typed it into the repl. - def runForTranscript(code: String, settings: Settings): String = { - import java.io.{ BufferedReader, StringReader, OutputStreamWriter } - - stringFromStream { ostream => - Console.withOut(ostream) { - val output = new JPrintWriter(new OutputStreamWriter(ostream), true) { - override def write(str: String) = { - // completely skip continuation lines - if (str forall (ch => ch.isWhitespace || ch == '|')) () - // print a newline on empty scala prompts - else if ((str contains '\n') && (str.trim == "scala> ")) super.write("\n") - else super.write(str) - } - } - val input = new BufferedReader(new StringReader(code)) { - override def readLine(): String = { - val s = super.readLine() - // helping out by printing the line being interpreted. - if (s != null) - output.println(s) - s - } - } - val repl = new ILoop(input, output) - if (settings.classpath.isDefault) - settings.classpath.value = sys.props("java.class.path") - - repl process settings - } - } - } - - /** Creates an interpreter loop with default settings and feeds - * the given code to it as input. - */ - def run(code: String, sets: Settings = new Settings): String = { - import java.io.{ BufferedReader, StringReader, OutputStreamWriter } - - stringFromStream { ostream => - Console.withOut(ostream) { - val input = new BufferedReader(new StringReader(code)) - val output = new JPrintWriter(new OutputStreamWriter(ostream), true) - val repl = new ILoop(input, output) - - if (sets.classpath.isDefault) - sets.classpath.value = sys.props("java.class.path") - - repl process sets - } - } - } - def run(lines: List[String]): String = run(lines map (_ + "\n") mkString) -} diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala deleted file mode 100644 index c54b01dbb0..0000000000 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ /dev/null @@ -1,1121 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package interpreter - -import Predef.{ println => _, _ } -import util.stringFromWriter -import scala.reflect.internal.util._ -import java.net.URL -import scala.sys.BooleanProp -import scala.tools.nsc.io.AbstractFile -import reporters._ -import scala.tools.util.PathResolver -import scala.tools.nsc.util.ScalaClassLoader -import ScalaClassLoader.URLClassLoader -import scala.tools.nsc.util.Exceptional.unwrap -import scala.collection.{ mutable, immutable } -import IMain._ -import java.util.concurrent.Future -import scala.reflect.runtime.{ universe => ru } -import scala.reflect.{ ClassTag, classTag } -import scala.tools.reflect.StdRuntimeTags._ - -/** An interpreter for Scala code. - * - * The main public entry points are compile(), interpret(), and bind(). - * The compile() method loads a complete Scala file. The interpret() method - * executes one line of Scala code at the request of the user. The bind() - * method binds an object to a variable that can then be used by later - * interpreted code. - * - * The overall approach is based on compiling the requested code and then - * using a Java classloader and Java reflection to run the code - * and access its results. - * - * In more detail, a single compiler instance is used - * to accumulate all successfully compiled or interpreted Scala code. To - * "interpret" a line of code, the compiler generates a fresh object that - * includes the line of code and which has public member(s) to export - * all variables defined by that code. To extract the result of an - * interpreted line to show the user, a second "result object" is created - * which imports the variables exported by the above object and then - * exports members called "$eval" and "$print". To accomodate user expressions - * that read from variables or methods defined in previous statements, "import" - * statements are used. - * - * This interpreter shares the strengths and weaknesses of using the - * full compiler-to-Java. The main strength is that interpreted code - * behaves exactly as does compiled code, including running at full speed. - * The main weakness is that redefining classes and methods is not handled - * properly, because rebinding at the Java level is technically difficult. - * - * @author Moez A. Abdel-Gawad - * @author Lex Spoon - */ -class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Imports { - imain => - - object replOutput extends ReplOutput(settings.Yreploutdir) { } - - @deprecated("Use replOutput.dir instead", "2.11.0") - def virtualDirectory = replOutput.dir - // Used in a test case. - def showDirectory() = replOutput.show(out) - - private[nsc] var printResults = true // whether to print result lines - private[nsc] var totalSilence = false // whether to print anything - private var _initializeComplete = false // compiler is initialized - private var _isInitialized: Future[Boolean] = null // set up initialization future - private var bindExceptions = true // whether to bind the lastException variable - private var _executionWrapper = "" // code to be wrapped around all lines - - /** We're going to go to some trouble to initialize the compiler asynchronously. - * It's critical that nothing call into it until it's been initialized or we will - * run into unrecoverable issues, but the perceived repl startup time goes - * through the roof if we wait for it. So we initialize it with a future and - * use a lazy val to ensure that any attempt to use the compiler object waits - * on the future. - */ - private var _classLoader: AbstractFileClassLoader = null // active classloader - private val _compiler: Global = newCompiler(settings, reporter) // our private compiler - - def compilerClasspath: Seq[URL] = ( - if (isInitializeComplete) global.classPath.asURLs - else new PathResolver(settings).result.asURLs // the compiler's classpath - ) - def settings = initialSettings - // Run the code body with the given boolean settings flipped to true. - def withoutWarnings[T](body: => T): T = beQuietDuring { - val saved = settings.nowarn.value - if (!saved) - settings.nowarn.value = true - - try body - finally if (!saved) settings.nowarn.value = false - } - - /** construct an interpreter that reports to Console */ - def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true)) - def this() = this(new Settings()) - - lazy val formatting: Formatting = new Formatting { - val prompt = Properties.shellPromptString - } - lazy val reporter: ReplReporter = new ReplReporter(this) - - import formatting._ - import reporter.{ printMessage, withoutTruncating } - - // This exists mostly because using the reporter too early leads to deadlock. - private def echo(msg: String) { Console println msg } - private def _initSources = List(new BatchSourceFile("", "class $repl_$init { }")) - private def _initialize() = { - try { - // todo. if this crashes, REPL will hang - new _compiler.Run() compileSources _initSources - _initializeComplete = true - true - } - catch AbstractOrMissingHandler() - } - private def tquoted(s: String) = "\"\"\"" + s + "\"\"\"" - private val logScope = scala.sys.props contains "scala.repl.scope" - private def scopelog(msg: String) = if (logScope) Console.err.println(msg) - - // argument is a thunk to execute after init is done - def initialize(postInitSignal: => Unit) { - synchronized { - if (_isInitialized == null) { - _isInitialized = io.spawn { - try _initialize() - finally postInitSignal - } - } - } - } - def initializeSynchronous(): Unit = { - if (!isInitializeComplete) { - _initialize() - assert(global != null, global) - } - } - def isInitializeComplete = _initializeComplete - - /** the public, go through the future compiler */ - lazy val global: Global = { - if (isInitializeComplete) _compiler - else { - // If init hasn't been called yet you're on your own. - if (_isInitialized == null) { - repldbg("Warning: compiler accessed before init set up. Assuming no postInit code.") - initialize(()) - } - // blocks until it is ; false means catastrophic failure - if (_isInitialized.get()) _compiler - else null - } - } - - import global._ - import definitions.{ ObjectClass, termMember, dropNullaryMethod} - - lazy val runtimeMirror = ru.runtimeMirror(classLoader) - - private def noFatal(body: => Symbol): Symbol = try body catch { case _: FatalError => NoSymbol } - - def getClassIfDefined(path: String) = ( - noFatal(runtimeMirror staticClass path) - orElse noFatal(rootMirror staticClass path) - ) - def getModuleIfDefined(path: String) = ( - noFatal(runtimeMirror staticModule path) - orElse noFatal(rootMirror staticModule path) - ) - - implicit class ReplTypeOps(tp: Type) { - def andAlso(fn: Type => Type): Type = if (tp eq NoType) tp else fn(tp) - } - - // TODO: If we try to make naming a lazy val, we run into big time - // scalac unhappiness with what look like cycles. It has not been easy to - // reduce, but name resolution clearly takes different paths. - object naming extends { - val global: imain.global.type = imain.global - } with Naming { - // make sure we don't overwrite their unwisely named res3 etc. - def freshUserTermName(): TermName = { - val name = newTermName(freshUserVarName()) - if (replScope containsName name) freshUserTermName() - else name - } - def isInternalTermName(name: Name) = isInternalVarName("" + name) - } - import naming._ - - object deconstruct extends { - val global: imain.global.type = imain.global - } with StructuredTypeStrings - - lazy val memberHandlers = new { - val intp: imain.type = imain - } with MemberHandlers - import memberHandlers._ - - /** Temporarily be quiet */ - def beQuietDuring[T](body: => T): T = { - val saved = printResults - printResults = false - try body - finally printResults = saved - } - def beSilentDuring[T](operation: => T): T = { - val saved = totalSilence - totalSilence = true - try operation - finally totalSilence = saved - } - - def quietRun[T](code: String) = beQuietDuring(interpret(code)) - - /** takes AnyRef because it may be binding a Throwable or an Exceptional */ - private def withLastExceptionLock[T](body: => T, alt: => T): T = { - assert(bindExceptions, "withLastExceptionLock called incorrectly.") - bindExceptions = false - - try beQuietDuring(body) - catch logAndDiscard("withLastExceptionLock", alt) - finally bindExceptions = true - } - - def executionWrapper = _executionWrapper - def setExecutionWrapper(code: String) = _executionWrapper = code - def clearExecutionWrapper() = _executionWrapper = "" - - /** interpreter settings */ - lazy val isettings = new ISettings(this) - - /** Instantiate a compiler. Overridable. */ - protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = { - settings.outputDirs setSingleOutput replOutput.dir - settings.exposeEmptyPackage.value = true - new Global(settings, reporter) with ReplGlobal { override def toString: String = "" } - } - - /** Parent classloader. Overridable. */ - protected def parentClassLoader: ClassLoader = - settings.explicitParentLoader.getOrElse( this.getClass.getClassLoader() ) - - /* A single class loader is used for all commands interpreted by this Interpreter. - It would also be possible to create a new class loader for each command - to interpret. The advantages of the current approach are: - - - Expressions are only evaluated one time. This is especially - significant for I/O, e.g. "val x = Console.readLine" - - The main disadvantage is: - - - Objects, classes, and methods cannot be rebound. Instead, definitions - shadow the old ones, and old code objects refer to the old - definitions. - */ - def resetClassLoader() = { - repldbg("Setting new classloader: was " + _classLoader) - _classLoader = null - ensureClassLoader() - } - final def ensureClassLoader() { - if (_classLoader == null) - _classLoader = makeClassLoader() - } - def classLoader: AbstractFileClassLoader = { - ensureClassLoader() - _classLoader - } - - def backticked(s: String): String = ( - (s split '.').toList map { - case "_" => "_" - case s if nme.keywords(newTermName(s)) => s"`$s`" - case s => s - } mkString "." - ) - - abstract class PhaseDependentOps { - def shift[T](op: => T): T - - def path(name: => Name): String = shift(path(symbolOfName(name))) - def path(sym: Symbol): String = backticked(shift(sym.fullName)) - def sig(sym: Symbol): String = shift(sym.defString) - } - object typerOp extends PhaseDependentOps { - def shift[T](op: => T): T = exitingTyper(op) - } - object flatOp extends PhaseDependentOps { - def shift[T](op: => T): T = exitingFlatten(op) - } - - def originalPath(name: String): String = originalPath(name: TermName) - def originalPath(name: Name): String = typerOp path name - def originalPath(sym: Symbol): String = typerOp path sym - def flatPath(sym: Symbol): String = flatOp shift sym.javaClassName - def translatePath(path: String) = { - val sym = if (path endsWith "$") symbolOfTerm(path.init) else symbolOfIdent(path) - sym match { - case NoSymbol => None - case _ => Some(flatPath(sym)) - } - } - def translateEnclosingClass(n: String) = { - def enclosingClass(s: Symbol): Symbol = - if (s == NoSymbol || s.isClass) s else enclosingClass(s.owner) - enclosingClass(symbolOfTerm(n)) match { - case NoSymbol => None - case c => Some(flatPath(c)) - } - } - - private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(replOutput.dir, parent) { - /** Overridden here to try translating a simple name to the generated - * class name if the original attempt fails. This method is used by - * getResourceAsStream as well as findClass. - */ - override protected def findAbstractFile(name: String): AbstractFile = - super.findAbstractFile(name) match { - case null => translatePath(name) map (super.findAbstractFile(_)) orNull - case file => file - } - } - private def makeClassLoader(): AbstractFileClassLoader = - new TranslatingClassLoader(parentClassLoader match { - case null => ScalaClassLoader fromURLs compilerClasspath - case p => new URLClassLoader(compilerClasspath, p) - }) - - // Set the current Java "context" class loader to this interpreter's class loader - def setContextClassLoader() = classLoader.setAsContext() - - def allDefinedNames: List[Name] = exitingTyper(replScope.toList.map(_.name).sorted) - def unqualifiedIds: List[String] = allDefinedNames map (_.decode) sorted - - /** Most recent tree handled which wasn't wholly synthetic. */ - private def mostRecentlyHandledTree: Option[Tree] = { - prevRequests.reverse foreach { req => - req.handlers.reverse foreach { - case x: MemberDefHandler if x.definesValue && !isInternalTermName(x.name) => return Some(x.member) - case _ => () - } - } - None - } - - private def updateReplScope(sym: Symbol, isDefined: Boolean) { - def log(what: String) { - val mark = if (sym.isType) "t " else "v " - val name = exitingTyper(sym.nameString) - val info = cleanTypeAfterTyper(sym) - val defn = sym defStringSeenAs info - - scopelog(f"[$mark$what%6s] $name%-25s $defn%s") - } - if (ObjectClass isSubClass sym.owner) return - // unlink previous - replScope lookupAll sym.name foreach { sym => - log("unlink") - replScope unlink sym - } - val what = if (isDefined) "define" else "import" - log(what) - replScope enter sym - } - - def recordRequest(req: Request) { - if (req == null) - return - - prevRequests += req - - // warning about serially defining companions. It'd be easy - // enough to just redefine them together but that may not always - // be what people want so I'm waiting until I can do it better. - exitingTyper { - req.defines filterNot (s => req.defines contains s.companionSymbol) foreach { newSym => - val oldSym = replScope lookup newSym.name.companionName - if (Seq(oldSym, newSym).permutations exists { case Seq(s1, s2) => s1.isClass && s2.isModule }) { - replwarn(s"warning: previously defined $oldSym is not a companion to $newSym.") - replwarn("Companions must be defined together; you may wish to use :paste mode for this.") - } - } - } - exitingTyper { - req.imports foreach (sym => updateReplScope(sym, isDefined = false)) - req.defines foreach (sym => updateReplScope(sym, isDefined = true)) - } - } - - private[nsc] def replwarn(msg: => String) { - if (!settings.nowarnings.value) - printMessage(msg) - } - - def compileSourcesKeepingRun(sources: SourceFile*) = { - val run = new Run() - reporter.reset() - run compileSources sources.toList - (!reporter.hasErrors, run) - } - - /** Compile an nsc SourceFile. Returns true if there are - * no compilation errors, or false otherwise. - */ - def compileSources(sources: SourceFile*): Boolean = - compileSourcesKeepingRun(sources: _*)._1 - - /** Compile a string. Returns true if there are no - * compilation errors, or false otherwise. - */ - def compileString(code: String): Boolean = - compileSources(new BatchSourceFile("