Permalink
Browse files

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.
  • Loading branch information...
1 parent 1b6297f commit 48cc8b47fcadaa187026ca0422178c9094e4b412 @paulp paulp committed Mar 11, 2013
Showing with 823 additions and 811 deletions.
  1. +35 −4 build.xml
  2. +1 −1 src/compiler/scala/tools/nsc/Global.scala
  3. +0 −30 src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
  4. +25 −34 src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
  5. +0 −1 src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
  6. +8 −15 src/compiler/scala/tools/nsc/typechecker/Macros.scala
  7. +10 −8 src/compiler/scala/tools/nsc/{interpreter → typechecker}/TypeStrings.scala
  8. +2 −3 src/compiler/scala/tools/nsc/{interpreter → util}/AbstractFileClassLoader.scala
  9. +1 −3 src/compiler/scala/tools/nsc/util/ShowPickled.scala
  10. +1 −3 src/compiler/scala/tools/reflect/StdTags.scala
  11. +1 −1 src/compiler/scala/tools/reflect/ToolBoxFactory.scala
  12. +6 −688 src/compiler/scala/tools/util/Javap.scala
  13. 0 src/{compiler → repl}/scala/tools/nsc/Interpreter.scala
  14. 0 src/{compiler → repl}/scala/tools/nsc/InterpreterLoop.scala
  15. +1 −2 src/{compiler → repl}/scala/tools/nsc/MainGenericRunner.scala
  16. +7 −0 src/repl/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
  17. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala
  18. +0 −10 src/{compiler → repl}/scala/tools/nsc/interpreter/ByteCode.scala
  19. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/CommandLine.scala
  20. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Completion.scala
  21. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/CompletionAware.scala
  22. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/CompletionOutput.scala
  23. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ConsoleReaderHelper.scala
  24. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Delimited.scala
  25. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ExprTyper.scala
  26. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Formatting.scala
  27. +1 −2 src/{compiler → repl}/scala/tools/nsc/interpreter/ILoop.scala
  28. +7 −6 src/{compiler → repl}/scala/tools/nsc/interpreter/IMain.scala
  29. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ISettings.scala
  30. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Imports.scala
  31. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/InteractiveReader.scala
  32. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/JLineCompletion.scala
  33. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/JLineReader.scala
  34. +693 −0 src/repl/scala/tools/nsc/interpreter/JavapClass.scala
  35. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Logger.scala
  36. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/LoopCommands.scala
  37. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/MemberHandlers.scala
  38. +1 −0 src/{compiler → repl}/scala/tools/nsc/interpreter/NamedParam.scala
  39. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Naming.scala
  40. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Parsed.scala
  41. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Pasted.scala
  42. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Phased.scala
  43. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Power.scala
  44. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplConfig.scala
  45. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplDir.scala
  46. +8 −0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplGlobal.scala
  47. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplProps.scala
  48. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplReporter.scala
  49. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplStrings.scala
  50. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/ReplVals.scala
  51. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/Results.scala
  52. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/RichClass.scala
  53. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/SimpleReader.scala
  54. +15 −0 src/repl/scala/tools/nsc/interpreter/StdReplTags.scala
  55. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/package.scala
  56. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/session/FileBackedHistory.scala
  57. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/session/History.scala
  58. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/session/JLineHistory.scala
  59. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/session/SimpleHistory.scala
  60. 0 src/{compiler → repl}/scala/tools/nsc/interpreter/session/package.scala
View
@@ -1095,6 +1095,32 @@ QUICK BUILD (QUICK)
<stopwatch name="quick.comp.timer" action="total"/>
</target>
+ <target name="quick.pre-repl" depends="quick.comp">
+ <uptodate property="quick.repl.available" targetfile="${build-quick.dir}/repl.complete">
+ <srcfiles dir="${src.dir}/repl" />
+ </uptodate>
+ </target>
+
+ <target name="quick.repl" depends="quick.pre-repl" unless="quick.repl.available">
+ <mkdir dir="${build-quick.dir}/classes/repl"/>
+ <scalacfork
+ destdir="${build-quick.dir}/classes/repl"
+ compilerpathref="quick.classpath"
+ params="${scalac.args.quick}"
+ srcdir="${src.dir}/repl"
+ jvmargs="${scalacfork.jvmargs}">
+ <include name="**/*.scala"/>
+ <compilationpath>
+ <pathelement location="${build-quick.dir}/classes/library"/>
+ <pathelement location="${build-quick.dir}/classes/reflect"/>
+ <pathelement location="${build-quick.dir}/classes/compiler"/>
+ <pathelement location="${build-quick.dir}/classes/repl"/>
+ <pathelement location="${jline.jar}"/>
+ </compilationpath>
+ </scalacfork>
+ <touch file="${build-quick.dir}/repl.complete" verbose="no"/>
+ </target>
+
<target name="quick.swing" depends="quick.comp" if="has.java6" unless="quick.comp.available">
<scalacfork
destdir="${build-quick.dir}/classes/library"
@@ -1107,7 +1133,7 @@ QUICK BUILD (QUICK)
</scalacfork>
</target>
- <target name="quick.pre-plugins" depends="quick.comp">
+ <target name="quick.pre-plugins" depends="quick.repl" unless="quick.repl.available">
<uptodate property="quick.plugins.available" targetfile="${build-quick.dir}/plugins.complete">
<srcfiles dir="${src.dir}/continuations"/>
</uptodate>
@@ -1229,6 +1255,7 @@ QUICK BUILD (QUICK)
<pathelement location="${build-quick.dir}/classes/library"/>
<pathelement location="${build-quick.dir}/classes/reflect"/>
<pathelement location="${build-quick.dir}/classes/compiler"/>
+ <pathelement location="${build-quick.dir}/classes/repl"/>
<pathelement location="${build-quick.dir}/classes/scalap"/>
<pathelement location="${build-quick.dir}/classes/partest"/>
<path refid="asm.classpath"/>
@@ -1247,6 +1274,7 @@ QUICK BUILD (QUICK)
<pathelement location="${build-quick.dir}/classes/library"/>
<pathelement location="${build-quick.dir}/classes/reflect"/>
<pathelement location="${build-quick.dir}/classes/compiler"/>
+ <pathelement location="${build-quick.dir}/classes/repl"/>
<pathelement location="${build-quick.dir}/classes/scalap"/>
<pathelement location="${build-quick.dir}/classes/partest"/>
<pathelement location="${ant.jar}"/>
@@ -1358,11 +1386,12 @@ QUICK BUILD (QUICK)
<pathelement location="${build-quick.dir}/classes/library"/>
<pathelement location="${build-quick.dir}/classes/reflect"/>
<pathelement location="${build-quick.dir}/classes/compiler"/>
+ <pathelement location="${build-quick.dir}/classes/repl"/>
<pathelement location="${build-quick.dir}/classes/scalap"/>
+ <pathelement location="${jline.jar}"/>
+ <path refid="asm.classpath"/>
<path refid="forkjoin.classpath"/>
<path refid="aux.libs"/>
- <path refid="asm.classpath"/>
- <pathelement location="${jline.jar}"/>
</path>
<taskdef name="quick-bin" classname="scala.tools.ant.ScalaTool" classpathref="quick.bin.classpath"/>
<mkdir dir="${build-quick.dir}/bin"/>
@@ -1488,6 +1517,7 @@ PACKED QUICK BUILD (PACK)
<fileset dir="${build-quick.dir}/classes/compiler"/>
<fileset dir="${build-quick.dir}/classes/scaladoc"/>
<fileset dir="${build-quick.dir}/classes/interactive"/>
+ <fileset dir="${build-quick.dir}/classes/repl"/>
<fileset dir="${build-asm.dir}/classes"/>
</jar>
<copy file="${jline.jar}" toDir="${build-pack.dir}/lib"/>
@@ -1998,10 +2028,11 @@ SBT Compiler Interface
jvmargs="${scalacfork.jvmargs}">
<include name="**/*.scala"/>
<compilationpath>
- <pathelement location="${build-quick.dir}/classes/scaladoc"/>
<pathelement location="${build-quick.dir}/classes/library"/>
<pathelement location="${build-quick.dir}/classes/reflect"/>
<pathelement location="${build-quick.dir}/classes/compiler"/>
+ <pathelement location="${build-quick.dir}/classes/scaladoc"/>
+ <pathelement location="${build-quick.dir}/classes/repl"/>
<pathelement location="${sbt.interface.jar}"/>
<path refid="forkjoin.classpath"/>
</compilationpath>
@@ -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
@@ -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")
@@ -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,41 +3218,41 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
detour
}
-
+
val detour = computeDetour
rephraseGotos(detour)
if (settings.debug.value) {
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
@@ -188,7 +188,6 @@ trait ScalaSettings extends AbsScalaSettings
val Ypmatdebug = BooleanSetting("-Ypmat-debug", "Trace all pattern matcher activity.")
val Yposdebug = BooleanSetting("-Ypos-debug", "Trace position validation.")
val Yreifydebug = BooleanSetting("-Yreify-debug", "Trace reification.")
- val Yrepldebug = BooleanSetting("-Yrepl-debug", "Trace all repl activity.") andThen (interpreter.replProps.debug setValue _)
val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.")
val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.")
@@ -43,8 +43,15 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
import definitions._
import treeInfo.{isRepeatedParamType => _, _}
import MacrosStats._
+
def globalSettings = global.settings
+ protected def findMacroClassLoader(): ClassLoader = {
+ val classpath = global.classPath.asURLs
+ macroLogVerbose("macro classloader: initializing from -cp: %s".format(classpath))
+ ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+ }
+
/** `MacroImplBinding` and its companion module are responsible for
* serialization/deserialization of macro def -> impl bindings.
*
@@ -474,21 +481,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
* Loads classes from from -cp (aka the library classpath).
* Is also capable of detecting REPL and reusing its classloader.
*/
- lazy val macroClassloader: ClassLoader = {
- val classpath = global.classPath.asURLs
- macroLogVerbose("macro classloader: initializing from -cp: %s".format(classpath))
- val loader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
-
- // a heuristic to detect the REPL
- if (global.settings.exposeEmptyPackage.value) {
- macroLogVerbose("macro classloader: initializing from a REPL classloader: %s".format(global.classPath.asURLs))
- import scala.tools.nsc.interpreter._
- val virtualDirectory = global.settings.outputDirs.getSingleOutput.get
- new AbstractFileClassLoader(virtualDirectory, loader) {}
- } else {
- loader
- }
- }
+ lazy val macroClassloader: ClassLoader = findMacroClassLoader()
/** Produces a function that can be used to invoke macro implementation for a given macro definition:
* 1) Looks up macro implementation symbol in this universe.
Oops, something went wrong.

0 comments on commit 48cc8b4

Please sign in to comment.