summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-05-26 18:12:53 +0000
committerPaul Phillips <paulp@improving.org>2009-05-26 18:12:53 +0000
commit103c97f7deef02d81d6d87c21f751899c63683b1 (patch)
tree50680eb96e39e016f28df03582164cce1b73d5e2 /src/compiler
parent5e12bab4777dc63711834cd39bf8514fb7e8da40 (diff)
downloadscala-103c97f7deef02d81d6d87c21f751899c63683b1.tar.gz
scala-103c97f7deef02d81d6d87c21f751899c63683b1.tar.bz2
scala-103c97f7deef02d81d6d87c21f751899c63683b1.zip
A big yet interim patch emerging from my attemp...
A big yet interim patch emerging from my attempts to centralize common classloader-related code. As it turns out, not that much of the patch is directly associated with that. Most of it is cleanup in the neighborhoods I was visiting, but there are a few new library files about which I'm open to feedback: scala/util/control/Exception - lots of exception handling code. scala/net/Utility - what would be the first file in scala.net.*, more code to follow if that sounds like a good package idea. scala/util/ScalaClassLoader - mostly convenience methods right now, more sophistication to come Also, this adds a :jar command to the repl which adds a jar to your classpath and replays the session.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/ant/ScalaBazaar.scala2
-rw-r--r--src/compiler/scala/tools/ant/ScalaTool.scala28
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala310
-rw-r--r--src/compiler/scala/tools/ant/sabbus/Compiler.scala26
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala102
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala20
-rw-r--r--src/compiler/scala/tools/nsc/MainGenericRunner.scala53
-rw-r--r--src/compiler/scala/tools/nsc/ObjectRunner.scala72
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala20
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala4
12 files changed, 240 insertions, 402 deletions
diff --git a/src/compiler/scala/tools/ant/ScalaBazaar.scala b/src/compiler/scala/tools/ant/ScalaBazaar.scala
index 74f311a376..a787d08365 100644
--- a/src/compiler/scala/tools/ant/ScalaBazaar.scala
+++ b/src/compiler/scala/tools/ant/ScalaBazaar.scala
@@ -15,7 +15,7 @@ package scala.tools.ant {
import scala.collection.mutable.HashMap
import java.io.{File, FileInputStream, FileOutputStream,
FileWriter, StringReader}
- import java.net.{URL, URLClassLoader}
+ import java.net.URL
import java.util.{ArrayList, Vector}
import java.util.zip.{ZipOutputStream, ZipEntry}
diff --git a/src/compiler/scala/tools/ant/ScalaTool.scala b/src/compiler/scala/tools/ant/ScalaTool.scala
index 6917da1287..9fc02859c8 100644
--- a/src/compiler/scala/tools/ant/ScalaTool.scala
+++ b/src/compiler/scala/tools/ant/ScalaTool.scala
@@ -169,20 +169,17 @@ class ScalaTool extends MatchingTask {
private def error(message: String): Nothing =
throw new BuildException(message, getLocation())
+ // XXX encoding and generalize
+ private def getResourceAsCharStream(clazz: Class[_], resource: String): Stream[Char] = {
+ val stream = clazz.getClassLoader() getResourceAsStream resource
+ if (stream == null) Stream.empty
+ else Stream continually stream.read() takeWhile (_ != -1) map (_.asInstanceOf[Char])
+ }
+
private def readAndPatchResource(resource: String, tokens: Map[String, String]): String = {
- val chars = new Iterator[Char] {
- private val stream =
- this.getClass().getClassLoader().getResourceAsStream(resource)
- private def readStream(): Char = stream.read().asInstanceOf[Char]
- private var buf: Char = readStream()
- def hasNext: Boolean = (buf != (-1.).asInstanceOf[Char])
- def next: Char = {
- val bufbuf = buf
- buf = readStream()
- bufbuf
- }
- }
+ val chars = getResourceAsCharStream(this.getClass, resource).elements
val builder = new StringBuilder()
+
while (chars.hasNext) {
val char = chars.next
if (char == '@') {
@@ -212,13 +209,6 @@ class ScalaTool extends MatchingTask {
writer.close()
}
- private def expandUnixVar(vars: Map[String,String]): Map[String,String] =
- vars transform { (x, vari) => vari.replaceAll("#([^#]*)#", "\\$$1") }
-
- private def expandWinVar(vars: Map[String,String]): Map[String,String] =
- vars transform { (x, vari) => vari.replaceAll("#([^#]*)#", "%_$1%") }
-
-
/*============================================================================*\
** The big execute method **
\*============================================================================*/
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index e9007c4238..3ede08f40c 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -12,7 +12,7 @@ package scala.tools.ant
import java.io.{File,PrintWriter,BufferedWriter,FileWriter}
-import org.apache.tools.ant.{BuildException, Project}
+import org.apache.tools.ant.{ BuildException, Project, AntClassLoader }
import org.apache.tools.ant.taskdefs.{MatchingTask,Java}
import org.apache.tools.ant.types.{Path, Reference, FileSet}
import org.apache.tools.ant.util.{FileUtils, GlobPatternMapper,
@@ -106,6 +106,10 @@ class Scalac extends MatchingTask {
* <code>unchecked</code> properties. */
object Flag extends PermissibleValue {
val values = List("yes", "no", "on", "off")
+ def toBoolean(flag: String) =
+ if (flag == "yes" || flag == "on") Some(true)
+ else if (flag == "no" || flag == "off") Some(false)
+ else None
}
/** The directories that contain source files to compile. */
@@ -164,23 +168,39 @@ class Scalac extends MatchingTask {
* (not only the number of files). */
protected var scalacDebugging: Boolean = false
+ /** Helpers */
+ private def setOrAppend(old: Option[Path], arg: Path): Option[Path] = old match {
+ case Some(x) => x append arg ; Some(x)
+ case None => Some(arg)
+ }
+ private def pathAsList(p: Option[Path], name: String): List[File] = p match {
+ case None => error("Member '" + name + "' is empty.")
+ case Some(x) => x.list.toList map nameToFile
+ }
+ private def createNewPath(getter: () => Option[Path], setter: (Option[Path]) => Unit) = {
+ if (getter().isEmpty)
+ setter(Some(new Path(getProject())))
+
+ getter().get.createPath()
+ }
+
+ private def plural(xs: List[Any]) = if (xs.size > 1) "s" else ""
+ private def plural(x: Int) = if (x > 1) "s" else ""
+
/*============================================================================*\
** Properties setters **
\*============================================================================*/
+
/** Sets the srcdir attribute. Used by Ant.
* @param input The value of <code>origin</code>. */
def setSrcdir(input: Path) {
- if (origin.isEmpty) origin = Some(input)
- else origin.get.append(input)
+ origin = setOrAppend(origin, input)
}
/** Sets the <code>origin</code> as a nested src Ant parameter.
* @return An origin path to be configured. */
- def createSrc(): Path = {
- if (origin.isEmpty) origin = Some(new Path(getProject()))
- origin.get.createPath()
- }
+ def createSrc(): Path = createNewPath(origin _, origin = _)
/** Sets the <code>origin</code> as an external reference Ant parameter.
* @param input A reference to an origin path. */
@@ -194,20 +214,16 @@ class Scalac extends MatchingTask {
/** Sets the <code>classpath</code> attribute. Used by Ant.
* @param input The value of <code>classpath</code>. */
def setClasspath(input: Path) {
- if (classpath.isEmpty) classpath = Some(input)
- else classpath.get.append(input)
+ classpath = setOrAppend(classpath, input)
}
/** Sets the <code>compilerPath</code> attribute. Used by Ant.
* @param input The value of <code>compilerPath</code>. */
def setCompilerPath(input : Path) {
- if(compilerPath.isEmpty) compilerPath = Some(input)
- else compilerPath.get.append(input)
+ compilerPath = setOrAppend(compilerPath, input)
}
- def createCompilerPath: Path = {
- if (compilerPath.isEmpty) compilerPath = Some(new Path(getProject()))
- compilerPath.get.createPath()
- }
+ def createCompilerPath: Path = createNewPath(compilerPath _, compilerPath = _)
+
/** Sets the <code>compilerpathref</code> attribute. Used by Ant.
* @param input The value of <code>compilerpathref</code>. */
def setCompilerPathRef(input: Reference) {
@@ -216,10 +232,7 @@ class Scalac extends MatchingTask {
/** Sets the <code>classpath</code> as a nested classpath Ant parameter.
* @return A class path to be configured. */
- def createClasspath(): Path = {
- if (classpath.isEmpty) classpath = Some(new Path(getProject()))
- classpath.get.createPath()
- }
+ def createClasspath(): Path = createNewPath(classpath _, classpath = _)
/** Sets the <code>classpath</code> as an external reference Ant parameter.
* @param input A reference to a class path. */
@@ -230,16 +243,12 @@ class Scalac extends MatchingTask {
/** Sets the <code>sourcepath</code> attribute. Used by Ant.
* @param input The value of <code>sourcepath</code>. */
def setSourcepath(input: Path) {
- if (sourcepath.isEmpty) sourcepath = Some(input)
- else sourcepath.get.append(input)
+ sourcepath = setOrAppend(sourcepath, input)
}
/** Sets the <code>sourcepath</code> as a nested sourcepath Ant parameter.
* @return A source path to be configured. */
- def createSourcepath(): Path = {
- if (sourcepath.isEmpty) sourcepath = Some(new Path(getProject()))
- sourcepath.get.createPath()
- }
+ def createSourcepath(): Path = createNewPath(sourcepath _, sourcepath = _)
/** Sets the <code>sourcepath</code> as an external reference Ant parameter.
* @param input A reference to a source path. */
@@ -251,17 +260,13 @@ class Scalac extends MatchingTask {
*
* @param input The value of <code>bootclasspath</code>. */
def setBootclasspath(input: Path) {
- if (bootclasspath.isEmpty) bootclasspath = Some(input)
- else bootclasspath.get.append(input)
+ bootclasspath = setOrAppend(bootclasspath, input)
}
/** Sets the <code>bootclasspath</code> as a nested sourcepath Ant
* parameter.
* @return A source path to be configured. */
- def createBootclasspath(): Path = {
- if (bootclasspath.isEmpty) bootclasspath = Some(new Path(getProject()))
- bootclasspath.get.createPath()
- }
+ def createBootclasspath(): Path = createNewPath(bootclasspath _, bootclasspath = _)
/** Sets the <code>bootclasspath</code> as an external reference Ant
* parameter.
@@ -272,15 +277,11 @@ class Scalac extends MatchingTask {
/** Sets the external extensions path attribute. Used by Ant.
* @param input The value of <code>extdirs</code>. */
def setExtdirs(input: Path) =
- if (extdirs.isEmpty) extdirs = Some(input)
- else extdirs.get.append(input)
+ extdirs = setOrAppend(extdirs, input)
/** Sets the <code>extdirs</code> as a nested sourcepath Ant parameter.
* @return An extensions path to be configured. */
- def createExtdirs(): Path = {
- if (extdirs.isEmpty) extdirs = Some(new Path(getProject()))
- extdirs.get.createPath()
- }
+ def createExtdirs(): Path = createNewPath(extdirs _, extdirs = _)
/** Sets the <code>extdirs</code> as an external reference Ant parameter.
* @param input A reference to an extensions path. */
@@ -345,28 +346,19 @@ class Scalac extends MatchingTask {
/** Set the <code>deprecation</code> info attribute.
* @param input One of the flags <code>yes/no</code> or <code>on/off</code>. */
def setDeprecation(input: String) {
- if (Flag.isPermissible(input))
- deprecation = Some("yes" == input || "on" == input)
- else
- error("Unknown deprecation flag '" + input + "'")
+ deprecation = Flag toBoolean input orElse error("Unknown deprecation flag '" + input + "'")
}
/** Set the <code>optimise</code> info attribute.
* @param input One of the flags <code>yes/no</code> or <code>on/off</code>. */
def setOptimise(input: String) {
- if (Flag.isPermissible(input))
- optimise = Some("yes" == input || "on" == input)
- else
- error("Unknown optimisation flag '" + input + "'")
+ optimise = Flag toBoolean input orElse error("Unknown optimisation flag '" + input + "'")
}
/** Set the <code>unchecked</code> info attribute.
* @param input One of the flags <code>yes/no</code> or <code>on/off</code>. */
def setUnchecked(input: String) {
- if (Flag.isPermissible(input))
- unchecked = Some("yes" == input || "on" == input)
- else
- error("Unknown unchecked flag '" + input + "'")
+ unchecked = Flag toBoolean input orElse error("Unknown unchecked flag '" + input + "'")
}
/** Sets the <code>force</code> attribute. Used by Ant.
@@ -380,7 +372,6 @@ class Scalac extends MatchingTask {
def setScalacdebugging(input: Boolean) { scalacDebugging = input }
def setAssemname(input: String) { assemname = Some(input) }
-
def setAssemrefs(input: String) { assemrefs = Some(input) }
/*============================================================================*\
@@ -390,16 +381,12 @@ class Scalac extends MatchingTask {
/** Gets the value of the <code>classpath</code> attribute in a
* Scala-friendly form.
* @return The class path as a list of files. */
- protected def getClasspath: List[File] =
- if (classpath.isEmpty) error("Member 'classpath' is empty.")
- else List.fromArray(classpath.get.list()).map(nameToFile)
+ protected def getClasspath: List[File] = pathAsList(classpath, "classpath")
/** Gets the value of the <code>origin</code> attribute in a
* Scala-friendly form.
* @return The origin path as a list of files. */
- protected def getOrigin: List[File] =
- if (origin.isEmpty) error("Member 'origin' is empty.")
- else List.fromArray(origin.get.list()).map(nameToFile)
+ protected def getOrigin: List[File] = pathAsList(origin, "origin")
/** Gets the value of the <code>destination</code> attribute in a
* Scala-friendly form.
@@ -411,33 +398,22 @@ class Scalac extends MatchingTask {
/** Gets the value of the <code>sourcepath</code> attribute in a
* Scala-friendly form.
* @return The source path as a list of files. */
- protected def getSourcepath: List[File] =
- if (sourcepath.isEmpty) error("Member 'sourcepath' is empty.")
- else List.fromArray(sourcepath.get.list()).map(nameToFile)
+ protected def getSourcepath: List[File] = pathAsList(sourcepath, "sourcepath")
/** Gets the value of the <code>bootclasspath</code> attribute in a
* Scala-friendly form.
* @return The boot class path as a list of files. */
- protected def getBootclasspath: List[File] =
- if (bootclasspath.isEmpty) error("Member 'bootclasspath' is empty.")
- else List.fromArray(bootclasspath.get.list()).map(nameToFile)
+ protected def getBootclasspath: List[File] = pathAsList(bootclasspath, "bootclasspath")
/** Gets the value of the <code>extdirs</code> attribute in a
* Scala-friendly form.
* @return The extensions path as a list of files. */
- protected def getExtdirs: List[File] =
- if (extdirs.isEmpty) error("Member 'extdirs' is empty.")
- else List.fromArray(extdirs.get.list()).map(nameToFile)
+ protected def getExtdirs: List[File] = pathAsList(extdirs, "extdirs")
/*============================================================================*\
** Compilation and support methods **
\*============================================================================*/
- /** This is forwarding method to circumvent bug #281 in Scala 2. Remove when
- * bug has been corrected. */
- override protected def getDirectoryScanner(baseDir: File) =
- super.getDirectoryScanner(baseDir)
-
/** Transforms a string name into a file relative to the provided base
* directory.
* @param base A file pointing to the location relative to which the name
@@ -503,59 +479,52 @@ class Scalac extends MatchingTask {
protected def initialize: (Settings, List[File], Boolean) = {
// Tests if all mandatory attributes are set and valid.
if (origin.isEmpty) error("Attribute 'srcdir' is not set.")
- if (getOrigin.isEmpty) error("Attribute 'srcdir' is not set.")
if (!destination.isEmpty && !destination.get.isDirectory())
error("Attribute 'destdir' does not refer to an existing directory.")
if (destination.isEmpty) destination = Some(getOrigin.head)
val mapper = new GlobPatternMapper()
- mapper.setTo("*.class")
- mapper.setFrom("*.scala")
+ mapper setTo "*.class"
+ mapper setFrom "*.scala"
var javaOnly = true
+ def getOriginFiles(originDir: File) = {
+ val includedFiles = getDirectoryScanner(originDir).getIncludedFiles()
+ val javaFiles = includedFiles filter (_ endsWith ".java")
+ val scalaFiles = {
+ val xs = includedFiles filter (_ endsWith ".scala")
+ if (force) xs
+ else new SourceFileScanner(this).restrict(xs, originDir, destination.get, mapper)
+ }
+
+ javaOnly = javaOnly && (scalaFiles.length == 0)
+ val list = (scalaFiles ++ javaFiles).toList
+
+ if (scalacDebugging && !list.isEmpty)
+ log("Compiling source file%s: %s to %s".format(
+ plural(list),
+ list.mkString(", "),
+ getDestination.toString
+ ))
+ else if (!list.isEmpty) {
+ val str =
+ if (javaFiles.isEmpty) "%d source file%s".format(list.length, plural(list))
+ else "%d scala and %d java source files".format(scalaFiles.length, javaFiles.length)
+ log("Compiling %s to %s".format(str, getDestination.toString))
+ }
+ else log("No files selected for compilation", Project.MSG_VERBOSE)
+
+ list
+ }
+
// Scans source directories to build up a compile lists.
// If force is false, only files were the .class file in destination is
// older than the .scala file will be used.
val sourceFiles: List[File] =
- for {
- val originDir <- getOrigin
- val originFiles <- {
- val includedFiles = getDirectoryScanner(originDir).getIncludedFiles()
- var scalaFiles = includedFiles.filter(_.endsWith(".scala"))
- val javaFiles = includedFiles.filter(_.endsWith(".java"))
- if (!force) {
- scalaFiles = new SourceFileScanner(this).
- restrict(scalaFiles, originDir, destination.get, mapper)
- }
- javaOnly = javaOnly && (scalaFiles.length == 0)
- val list = scalaFiles.toList ::: javaFiles.toList
- if (scalacDebugging && list.length > 0)
- log(
- list.mkString(
- "Compiling source file" +
- (if (list.length > 1) "s: " else ": "),
- ", ",
- " "
- ) + "to " + getDestination.toString
- )
- else if (list.length > 0)
- log(
- "Compiling " + (
- if (javaFiles.length > 0)
- (scalaFiles.length +" scala and "+ javaFiles.length +" java source files")
- else
- (list.length +" source file"+ (if (list.length > 1) "s" else ""))
- ) +" to "+ getDestination.toString
- )
- else
- log("No files selected for compilation", Project.MSG_VERBOSE)
- list
- }
- }
- yield {
- log(originFiles, Project.MSG_DEBUG)
- nameToFile(originDir)(originFiles)
+ for (originDir <- getOrigin ; originFile <- getOriginFiles(originDir)) yield {
+ log(originFile, Project.MSG_DEBUG)
+ nameToFile(originDir)(originFile)
}
// Builds-up the compilation settings for Scalac with the existing Ant
@@ -597,115 +566,82 @@ class Scalac extends MatchingTask {
override def execute() {
val (settings, sourceFiles, javaOnly) = initialize
- if (sourceFiles.isEmpty || javaOnly) {
+ if (sourceFiles.isEmpty || javaOnly)
return
- }
- if(fork) {
- //TODO - Error
- executeFork(settings, sourceFiles)
- } else {
- executeInternal(settings, sourceFiles)
- }
+
+ if (fork) executeFork(settings, sourceFiles) // TODO - Error
+ else executeInternal(settings, sourceFiles)
}
- protected def executeFork(settings: Settings, sourceFiles : List[File]) {
- val java = new Java(this) // set this as owner
- java.setFork(true)
- // using 'setLine' creates multiple arguments out of a space-separated string
- for(args <- jvmArgs) {
- java.createJvmarg().setLine(args)
- }
+ protected def executeFork(settings: Settings, sourceFiles: List[File]) {
+ val java = new Java(this)
+ java setFork true
+ // using 'setLine' creates multiple arguments out of a space-separated string
+ jvmArgs foreach { java.createJvmarg() setLine _ }
- //Determine the path for scalac!
- val scalacPath = {
+ // use user-provided path or retrieve from classloader
+ // TODO - Allow user to override the compiler classpath
+ val scalacPath: Path = {
val path = new Path(getProject)
- compilerPath match {
- case Some(p) =>
- //Use the user provided path
- path.add(p)
- case None =>
- //Pull classpath off our classloader
- //TODO - Allow user to override the compiler classpath
- import _root_.org.apache.tools.ant.AntClassLoader
- val classLoader = getClass.getClassLoader
- if(classLoader.isInstanceOf[AntClassLoader]) {
- path.add(new Path(getProject, classLoader.asInstanceOf[AntClassLoader].getClasspath))
- } else {
- throw new BuildException("Cannot determine default classpath for sclac, please specify one!")
- }
+ if (compilerPath.isDefined) path add compilerPath.get
+ else getClass.getClassLoader match {
+ case cl: AntClassLoader => path add new Path(getProject, cl.getClasspath)
+ case _ => error("Cannot determine default classpath for sclac, please specify one!")
}
path
}
- java.setClasspath(scalacPath)
-
- java.setClassname("scala.tools.nsc.Main")
- //if (!timeout.isEmpty) java.setTimeout(timeout.get)
+ java setClasspath scalacPath
+ java setClassname "scala.tools.nsc.Main"
- //Write all settings to a temporary file
+ // Write all settings to a temporary file
def writeSettings() : File = {
def escapeArgument(arg : String) = if(arg.matches(".*\\s.*")) ('"' + arg + '"') else arg
val file = File.createTempFile("scalac-ant-",".args")
file.deleteOnExit()
val out = new PrintWriter(new BufferedWriter(new FileWriter(file)))
+
try {
- for ( setting <- settings.allSettings;
- arg <- setting.unparse){
- out.println(escapeArgument(arg))
- }
- for (file <- sourceFiles) {
- out.println(file.getAbsolutePath)
- }
- } finally {
- out.close();
+ for (setting <- settings.allSettings ; arg <- setting.unparse)
+ out println escapeArgument(arg)
+ for (file <- sourceFiles)
+ out println file.getAbsolutePath
}
+ finally out.close()
+
file
}
- java.createArg().setValue("@" + writeSettings.getCanonicalPath)
- log(java.getCommandLine.getCommandline.mkString("", " ", ""), Project.MSG_VERBOSE)
+ java.createArg() setValue ("@" + writeSettings.getCanonicalPath)
+ log(java.getCommandLine.getCommandline.mkString(" "), Project.MSG_VERBOSE)
+
val res = java.executeJava()
if (failonerror && res != 0)
error("Compilation failed because of an internal compiler error;"+
" see the error output for details.")
-
}
+
/** Performs the compilation. */
protected def executeInternal(settings: Settings, sourceFiles : List[File]) {
-
-
val reporter = new ConsoleReporter(settings)
-
- // Compiles the actual code
- val compiler = newGlobal(settings, reporter)
- try {
- (new compiler.Run).compile(sourceFiles.map (_.toString))
- }
- catch {
- case exception: Throwable if (exception.getMessage ne null) =>
- exception.printStackTrace()
- error("Compile failed because of an internal compiler error (" +
- exception.getMessage + "); see the error output for details.")
- case exception =>
- exception.printStackTrace()
- error("Compile failed because of an internal compiler error " +
- "(no error message provided); see the error output for details.")
+ val compiler = newGlobal(settings, reporter) // compiles the actual code
+
+ try new compiler.Run compile (sourceFiles map (_.toString))
+ catch {
+ case ex: Throwable =>
+ ex.printStackTrace()
+ val msg = if (ex.getMessage == null) "no error message provided" else ex.getMessage
+ error("Compile failed because of an internal compiler error (" + msg + "); see the error output for details.")
}
+
reporter.printSummary()
if (reporter.hasErrors) {
- val msg =
- "Compile failed with " +
- reporter.ERROR.count + " error" +
- (if (reporter.ERROR.count > 1) "s" else "") +
- "; see the compiler error output for details."
+ val msg = "Compile failed with %d error%s; see the compiler error output for details.".format(
+ reporter.ERROR.count, plural(reporter.ERROR.count))
if (failonerror) error(msg) else log(msg)
}
else if (reporter.WARNING.count > 0)
- log(
- "Compile suceeded with " +
- reporter.WARNING.count + " warning" +
- (if (reporter.WARNING.count > 1) "s" else "") +
- "; see the compiler output for details.")
+ log("Compile succeeded with %d warning%s; see the compiler output for details.".format(
+ reporter.WARNING.count, plural(reporter.WARNING.count)))
}
-
}
diff --git a/src/compiler/scala/tools/ant/sabbus/Compiler.scala b/src/compiler/scala/tools/ant/sabbus/Compiler.scala
index cd5b4a88aa..787c6af870 100644
--- a/src/compiler/scala/tools/ant/sabbus/Compiler.scala
+++ b/src/compiler/scala/tools/ant/sabbus/Compiler.scala
@@ -13,25 +13,19 @@ package scala.tools.ant.sabbus
import java.io.File
import java.net.URL
import java.lang.reflect.InvocationTargetException
+import scala.util.ScalaClassLoader
-class Compiler(classpath: Array[URL], val settings: Settings) {
-
- private lazy val classLoader: ClassLoader =
- new java.net.URLClassLoader(classpath, null)
-
- private lazy val foreignCompilerName: String =
- "scala.tools.ant.sabbus.ForeignCompiler"
- private lazy val foreignCompiler: AnyRef =
- classLoader.loadClass(foreignCompilerName).newInstance.asInstanceOf[AnyRef]
+class Compiler(classpath: Array[URL], val settings: Settings)
+{
+ val foreignCompilerName: String = "scala.tools.ant.sabbus.ForeignCompiler"
+ private lazy val classLoader = ScalaClassLoader fromURLs classpath
+ private lazy val foreignCompiler: AnyRef = classLoader create foreignCompilerName
private def settingsArray: Array[String] = settings.toArgs.toArray
-
foreignInvoke("args_$eq", Array(classOf[Array[String]]), Array(settingsArray))
- private def foreignInvoke(method: String, types: Array[Class[T] forSome { type T }] , args: Array[AnyRef]) =
- try {
- foreignCompiler.getClass.getMethod(method, types : _*).invoke(foreignCompiler, args : _*)
- }
+ private def foreignInvoke(method: String, types: Array[Class[_]], args: Array[AnyRef]) =
+ try foreignCompiler.getClass.getMethod(method, types: _*).invoke(foreignCompiler, args: _*)
catch {
case e: InvocationTargetException => throw e.getCause
}
@@ -44,8 +38,6 @@ class Compiler(classpath: Array[URL], val settings: Settings) {
(result >> 16, result & 0x00FF)
}
catch {
- case ex: Exception =>
- throw CompilationFailure(ex.getMessage, ex)
+ case ex: Exception => throw CompilationFailure(ex.getMessage, ex)
}
-
}
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 0fbd115f4d..453f96120e 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -8,13 +8,15 @@ package scala.tools.nsc
import java.io.{ File, PrintWriter, StringWriter, Writer }
import java.lang.{ Class, ClassLoader }
-import java.net.{ MalformedURLException, URL, URLClassLoader }
+import java.net.{ MalformedURLException, URL }
import java.lang.reflect
import reflect.InvocationTargetException
import scala.collection.immutable.ListSet
import scala.collection.mutable
import scala.collection.mutable.{ ListBuffer, HashSet, ArrayBuffer }
+import scala.util.{ ScalaClassLoader, URLClassLoader }
+import scala.util.control.Exception.reflectionUnwrapper
import io.{ PlainFile, VirtualDirectory }
import reporters.{ ConsoleReporter, Reporter }
@@ -70,7 +72,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
val virtualDirectory = new VirtualDirectory("(memory)", None)
/** the compiler to compile expressions with */
- val compiler: nsc.Global = newCompiler(settings, reporter)
+ val compiler: Global = newCompiler(settings, reporter)
import compiler.{ Traverser, CompilationUnit, Symbol, Name, Type }
import compiler.{
@@ -112,18 +114,15 @@ class Interpreter(val settings: Settings, out: PrintWriter)
/** Instantiate a compiler. Subclasses can override this to
* change the compiler class used by this interpreter. */
protected def newCompiler(settings: Settings, reporter: Reporter) = {
- settings.outputDirs.setSingleOutput(virtualDirectory)
- val comp = new nsc.Global(settings, reporter)
- comp
+ settings.outputDirs setSingleOutput virtualDirectory
+ new Global(settings, reporter)
}
/** the compiler's classpath, as URL's */
val compilerClasspath: List[URL] = {
+ import net.Utility.parseURL
val classpathPart =
ClassPath.expandPath(compiler.settings.classpath.value).map(s => new File(s).toURL)
- def parseURL(s: String): Option[URL] =
- try { Some(new URL(s)) }
- catch { case _: MalformedURLException => None }
val codebasePart = (compiler.settings.Xcodebase.value.split(" ")).toList flatMap parseURL
classpathPart ::: codebasePart
@@ -142,58 +141,49 @@ class Interpreter(val settings: Settings, out: PrintWriter)
shadow the old ones, and old code objects refer to the old
definitions.
*/
- private var classLoader = makeClassLoader()
- private def makeClassLoader(): ClassLoader = {
- val cp = compilerClasspath.toArray
+ private var classLoader: ScalaClassLoader = makeClassLoader()
+ private def makeClassLoader(): ScalaClassLoader = {
val parent =
- if (parentClassLoader == null) new URLClassLoader(cp)
- else new URLClassLoader(cp, parentClassLoader)
+ if (parentClassLoader == null) ScalaClassLoader fromURLs compilerClasspath
+ else new URLClassLoader(compilerClasspath, parentClassLoader)
new AbstractFileClassLoader(virtualDirectory, parent)
}
+ private def loadByName(s: String): Class[_] = (classLoader tryToInitializeClass s).get
+ private def methodByName(c: Class[_], name: String): reflect.Method =
+ c.getMethod(name, classOf[Object])
- private def loadByName(s: String): Class[_] = Class.forName(s, true, classLoader)
- // XXX how does this differ from getMethod("set") ?
- private def methodByName(c: Class[_], name: String): Option[reflect.Method] =
- c.getDeclaredMethods.toList.find(_.getName == name)
+ protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader()
// Set the current Java "context" class loader to this interpreter's class loader
- def setContextClassLoader() = Thread.currentThread.setContextClassLoader(classLoader)
-
- protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader()
+ def setContextClassLoader() = classLoader.setAsContext()
/** the previous requests this interpreter has processed */
private val prevRequests = new ArrayBuffer[Request]()
private def allUsedNames = prevRequests.toList.flatMap(_.usedNames).removeDuplicates
private def allBoundNames = prevRequests.toList.flatMap(_.boundNames).removeDuplicates
- /** counter creator */
- def mkNameCreator(s: String) = new Function0[String] with Function1[String,String] {
+ /** Generates names pre0, pre1, etc. via calls to apply method */
+ class NameCreator(pre: String) {
private var x = -1
- def apply(): String = { x += 1 ; s + x.toString }
- // second apply method temp for newInternalVarName's bug compatibility
- def apply(pre: String) = { x += 1 ; pre + x.toString }
+ def apply(): String = { x += 1 ; pre + x.toString }
def reset(): Unit = x = -1
+ def didGenerate(name: String) =
+ (name startsWith pre) && ((name drop pre.length) forall (_.isDigit))
}
/** allocate a fresh line name */
- private val newLineName = mkNameCreator(INTERPRETER_LINE_PREFIX)
+ private val lineNameCreator = new NameCreator(INTERPRETER_LINE_PREFIX)
/** allocate a fresh var name */
- private val newVarName = mkNameCreator(INTERPRETER_VAR_PREFIX)
+ private val varNameCreator = new NameCreator(INTERPRETER_VAR_PREFIX)
/** allocate a fresh internal variable name */
- /** XXX temporarily shares newVarName's creator to be bug-compatible with
- * test case interpreter.scala */
- private def newInternalVarName = () => newVarName(INTERPRETER_SYNTHVAR_PREFIX)
- // private val newInternalVarName = mkNameCreator(INTERPRETER_SYNTHVAR_PREFIX)
+ private def synthVarNameCreator = new NameCreator(INTERPRETER_SYNTHVAR_PREFIX)
- private def isGenerated(pre: String, name: String) =
- (name startsWith pre) && (name drop pre.length).forall(_.isDigit)
-
- /** Check if a name looks like it was generated by newVarName */
- private def isGeneratedVarName(name: String): Boolean = isGenerated(INTERPRETER_VAR_PREFIX, name)
- private def isSynthVarName(name: String): Boolean = isGenerated(INTERPRETER_SYNTHVAR_PREFIX, name)
+ /** Check if a name looks like it was generated by varNameCreator */
+ private def isGeneratedVarName(name: String): Boolean = varNameCreator didGenerate name
+ private def isSynthVarName(name: String): Boolean = synthVarNameCreator didGenerate name
/** generate a string using a routine that wants to write on a stream */
private def stringFrom(writer: PrintWriter => Unit): String = {
@@ -424,12 +414,12 @@ class Interpreter(val settings: Settings, out: PrintWriter)
if (trees.size == 1) trees.head match {
case _:Assign => // we don't want to include assignments
case _:TermTree | _:Ident | _:Select =>
- return interpret("val %s =\n%s".format(newVarName(), line))
+ return interpret("val %s =\n%s".format(varNameCreator(), line))
case _ =>
}
// figure out what kind of request
- val req = buildRequest(trees, line, newLineName())
+ val req = buildRequest(trees, line, lineNameCreator())
// null is a disallowed statement type; otherwise compile and fail if false (implying e.g. a type error)
if (req == null || !req.compile)
return IR.Error
@@ -446,7 +436,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
}
/** A name creator used for objects created by <code>bind()</code>. */
- private val newBinder = mkNameCreator("binder")
+ private val newBinder = new NameCreator("binder")
/** Bind a specified name to a specified value. The name may
* later be used by expressions passed to interpret.
@@ -467,7 +457,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
""".stripMargin.format(binderName, boundType, boundType))
val binderObject = loadByName(binderName)
- val setterMethod = methodByName(binderObject, "set").get
+ val setterMethod = methodByName(binderObject, "set")
// this roundabout approach is to ensure the value is boxed
var argsHolder: Array[Any] = null
@@ -480,8 +470,8 @@ class Interpreter(val settings: Settings, out: PrintWriter)
def reset() {
virtualDirectory.clear
classLoader = makeClassLoader
- newLineName.reset()
- newVarName.reset()
+ lineNameCreator.reset()
+ varNameCreator.reset()
prevRequests.clear
}
@@ -572,7 +562,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
private class AssignHandler(member: Assign) extends MemberHandler(member) {
val lhs = member.lhs.asInstanceOf[Ident] // an unfortunate limitation
- val helperName = newTermName(newInternalVarName())
+ val helperName = newTermName(synthVarNameCreator())
override val valAndVarNames = List(helperName)
override def extraCodeToEvaluate(req: Request, code: PrintWriter) =
@@ -773,16 +763,11 @@ class Interpreter(val settings: Settings, out: PrintWriter)
def loadAndRun: (String, Boolean) = {
val resultObject: Class[_] = loadByName(resultObjectName)
val resultValMethod: reflect.Method = resultObject getMethod "result"
+ lazy val pair = (resultValMethod.invoke(resultObject).toString, true)
- try { (resultValMethod.invoke(resultObject).toString, true) }
- catch { case e =>
- // unwrap unhelpful nested exceptions so the most interesting one is reported
- def unwrap(e: Throwable): Throwable = e match {
- case (_: InvocationTargetException | _: ExceptionInInitializerError) if e.getCause ne null =>
- unwrap(e.getCause)
- case _ => e
- }
- (stringFrom(unwrap(e).printStackTrace(_)), false)
+ (reflectionUnwrapper either pair) match {
+ case Left(e) => (stringFrom(e.printStackTrace(_)), false)
+ case Right((res, success)) => (res, success)
}
}
}
@@ -870,11 +855,11 @@ class Interpreter(val settings: Settings, out: PrintWriter)
val res = beQuietDuring {
for (name <- nameOfIdent(line) ; req <- requestForName(name)) yield {
- if (interpret("val " + newInternalVarName() + " = " + name + methodsCode) != IR.Success) Nil
+ if (interpret("val " + synthVarNameCreator() + " = " + name + methodsCode) != IR.Success) Nil
else {
val result = prevRequests.last.resultObjectName
- val resultObj = Class.forName(result, true, classLoader)
- val valMethod = resultObj.getMethod("result")
+ val resultObj = (classLoader tryToInitializeClass result).get
+ val valMethod = resultObj getMethod "result"
val str = valMethod.invoke(resultObj).toString
str.substring(str.indexOf('=') + 1).trim .
@@ -896,10 +881,7 @@ class Interpreter(val settings: Settings, out: PrintWriter)
filter(!isSynthVarName(_))
/** For static/object method completion */
- def tryToLoadClass(path: String): Option[Class[_]] = {
- try { Some(Class.forName(path, false, classLoader)) }
- catch { case _: ClassNotFoundException | _: NoClassDefFoundError => None }
- }
+ def getClassObject(path: String): Option[Class[_]] = classLoader tryToLoadClass path
// debugging
private var debuggingOutput = false
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index 15a57729fc..2beeec28e4 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -8,7 +8,6 @@ package scala.tools.nsc
import java.io.{BufferedReader, File, FileReader, PrintWriter}
import java.io.IOException
-import java.lang.{ClassLoader, System}
import scala.tools.nsc.{InterpreterResults => IR}
import scala.tools.nsc.interpreter._
@@ -84,6 +83,9 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) {
var interpreter: Interpreter = _ // set by createInterpreter()
def isettings = interpreter.isettings
+ // XXX
+ var addedClasspath: List[String] = Nil
+
/** A reverse list of commands to replay if the user requests a :replay */
var replayCommandsRev: List[String] = Nil
@@ -104,6 +106,9 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) {
/** Create a new interpreter. */
def createInterpreter() {
+ if (!addedClasspath.isEmpty)
+ settings.classpath.value += addedClasspath.map(File.pathSeparator + _).mkString
+
interpreter = new Interpreter(settings, out) {
override protected def parentClassLoader = classOf[InterpreterLoop].getClassLoader
}
@@ -155,6 +160,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) {
import CommandImplicits._
List(
NoArgs("help", "prints this help message", printHelp),
+ OneArg("jar", "add a jar to the classpath", addJar),
OneArg("load", "followed by a filename loads a Scala file", load),
NoArgs("power", "enable power user mode", power),
NoArgs("quit", "exits the interpreter", () => Result(false, None)),
@@ -262,6 +268,18 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) {
Result(true, shouldReplay)
}
+
+ def addJar(arg: String): Unit = {
+ val f = new java.io.File(arg)
+ if (!f.exists) {
+ out.println("The file '" + f + "' doesn't seem to exist.")
+ return
+ }
+ addedClasspath = addedClasspath ::: List(f.getCanonicalPath)
+ println("Added " + f.getCanonicalPath + " to your classpath.")
+ replay()
+ }
+
def power() = {
powerUserOn = true
interpreter.powerUser()
diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala
index 3d7b5ac7ee..55967222c1 100644
--- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala
+++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala
@@ -10,7 +10,8 @@ package scala.tools.nsc
import java.io.{File, IOException}
import java.lang.{ClassNotFoundException, NoSuchMethodException}
import java.lang.reflect.InvocationTargetException
-import java.net.URL
+import java.net.{ URL, MalformedURLException }
+import scala.util.ScalaClassLoader
import util.ClassPath
import File.pathSeparator
@@ -25,40 +26,23 @@ object MainGenericRunner {
* input classpath is empty; otherwise do not.
*
* @param classpath
- * @return ...
+ * @return the new classpath
*/
private def addClasspathExtras(classpath: String): String = {
val scalaHome = Properties.scalaHome
- val extraClassPath =
- if (scalaHome eq null)
- ""
- else {
- def listDir(name:String):Array[File] = {
- val libdir = new File(new File(scalaHome), name)
- if (!libdir.exists || libdir.isFile)
- Array()
- else
- libdir.listFiles
- }
- {
- val filesInLib = listDir("lib")
- val jarsInLib =
- filesInLib.filter(f =>
- f.isFile && f.getName.endsWith(".jar"))
- jarsInLib.toList
- } ::: {
- val filesInClasses = listDir("classes")
- val dirsInClasses =
- filesInClasses.filter(f => f.isDirectory)
- dirsInClasses.toList
- }
- }.mkString("", pathSeparator, "")
-
- if (classpath == "")
- extraClassPath + pathSeparator + "."
- else
- classpath + pathSeparator + extraClassPath
+ def listDir(name: String): List[File] = {
+ val libdir = new File(new File(scalaHome), name)
+ if (!libdir.exists || libdir.isFile) Nil else libdir.listFiles.toList
+ }
+ lazy val jarsInLib = listDir("lib") filter (_.getName endsWith ".jar")
+ lazy val dirsInClasses = listDir("classes") filter (_.isDirectory)
+ val cpScala =
+ if (scalaHome == null) Nil
+ else (jarsInLib ::: dirsInClasses) map (_.toString)
+
+ // either prepend existing classpath or append "."
+ (if (classpath == "") cpScala ::: List(".") else classpath :: cpScala) mkString pathSeparator
}
def main(args: Array[String]) {
@@ -114,8 +98,8 @@ object MainGenericRunner {
) yield url.get
def specToURL(spec: String): Option[URL] =
- try { Some(new URL(spec)) }
- catch { case e => Console.println(e); None }
+ try { Some(new URL(spec)) }
+ catch { case e: MalformedURLException => Console.println(e); None }
def urls(specs: String): List[URL] =
if (specs == null || specs.length == 0) Nil
@@ -146,8 +130,7 @@ object MainGenericRunner {
settings.howtorun.value match {
case "object" => true
case "script" => false
- case "guess" =>
- ObjectRunner.classExists(classpath, thingToRun)
+ case "guess" => ScalaClassLoader.classExists(classpath, thingToRun)
}
if (isObjectName) {
diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala
index 58da7b16eb..e4e0826d32 100644
--- a/src/compiler/scala/tools/nsc/ObjectRunner.scala
+++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala
@@ -7,9 +7,8 @@
package scala.tools.nsc
-import java.lang.{Class, ClassNotFoundException, NoSuchMethodException}
-import java.lang.reflect.{Method, Modifier}
-import java.net.{URL, URLClassLoader}
+import java.net.URL
+import scala.util.ScalaClassLoader
/** An object that runs another object specified by name.
*
@@ -18,57 +17,10 @@ import java.net.{URL, URLClassLoader}
*/
object ObjectRunner
{
- // we cannot use the app classloader here or we get what looks to
- // be classloader deadlock, but if we pass null we bypass the extension
- // classloader and our extensions, so we search the hierarchy to find
- // the classloader whose parent is null. Resolves bug #857.
- private def findExtClassLoader(): ClassLoader = {
- def search(cl: ClassLoader): ClassLoader = {
- if (cl == null) null
- else if (cl.getParent == null) cl
- else search(cl.getParent)
- }
-
- search(Thread.currentThread.getContextClassLoader)
- }
-
- /** Create a class loader for the specified class path */
- private def makeClassLoader(classpath: List[URL]): URLClassLoader =
- makeClassLoader(classpath, findExtClassLoader())
- private def makeClassLoader(classpath: List[URL], parent: ClassLoader): URLClassLoader =
- new URLClassLoader(classpath.toArray, parent)
-
- /** Look up a class with a given class path. */
- private def findClass(loader: ClassLoader, objectName: String)
- : Option[Class[T] forSome { type T }] =
- {
- try {
- Some(Class.forName(objectName, true, loader))
- } catch {
- case e: SecurityException =>
- Console.println(e.getMessage)
- None
- case _: ClassNotFoundException =>
- None
- }
- }
-
/** Check whether a class with the specified name
* exists on the specified class path. */
- def classExists(classpath: List[URL], objectName: String): Boolean =
- !findClass(makeClassLoader(classpath), objectName).isEmpty
-
- /** Set the Java context class loader while executing an action */
- def withContextClassLoader[T](loader: ClassLoader)(action: =>T): T = {
- val oldLoader = Thread.currentThread.getContextClassLoader
- try {
- Thread.currentThread.setContextClassLoader(loader)
- action
- } finally {
- Thread.currentThread.setContextClassLoader(oldLoader)
- }
- }
-
+ def classExists(urls: List[URL], objectName: String): Boolean =
+ ScalaClassLoader.classExists(urls, objectName)
/** Run a given object, specified by name, using a
* specified classpath and argument list.
@@ -77,19 +29,7 @@ object ObjectRunner
* @throws NoSuchMethodError
* @throws InvocationTargetException
*/
- def run(classpath: List[URL], objectName: String, arguments: Seq[String]) {
- val loader = makeClassLoader(classpath)
- val clsToRun = findClass(loader, objectName) match {
- case Some(cls) => cls
- case None => throw new ClassNotFoundException(objectName)
- }
-
- val method = clsToRun.getMethod("main", classOf[Array[String]])
- if ((method.getModifiers & Modifier.STATIC) == 0)
- throw new NoSuchMethodException(objectName + ".main is not static")
-
- withContextClassLoader(loader) {
- method.invoke(null, List(arguments.toArray).toArray: _*)
- }
+ def run(urls: List[URL], objectName: String, arguments: Seq[String]) {
+ (ScalaClassLoader fromURLs urls).run(objectName, arguments)
}
}
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index cefbecee81..5d96a54f64 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -753,7 +753,6 @@ trait ScalacSettings
val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL")
val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
val debug = BooleanSetting ("-Ydebug", "Output debugging messages")
- val debugger = BooleanSetting ("-Ydebugger", "Enable interactive debugger")
val Xdetach = BooleanSetting ("-Ydetach", "Perform detaching of remote closures")
// val doc = BooleanSetting ("-Ydoc", "Generate documentation")
val inline = BooleanSetting ("-Yinline", "Perform inlining when possible")
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
index bb1d049677..964fd3f377 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
@@ -6,6 +6,7 @@
package scala.tools.nsc.interpreter
import scala.tools.nsc.io.AbstractFile
+import scala.util.ScalaClassLoader
/**
* A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}.
@@ -13,21 +14,18 @@ import scala.tools.nsc.io.AbstractFile
* @author Lex Spoon
*/
class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
-extends ClassLoader(parent)
+ extends ClassLoader(parent)
+ with ScalaClassLoader
{
override def findClass(name: String): Class[_] = {
+ def onull[T](x: T): T = if (x == null) throw new ClassNotFoundException(name) else x
var file: AbstractFile = root
val pathParts = name.split("[./]").toList
- for (dirPart <- pathParts.init) {
- file = file.lookupName(dirPart, true)
- if (file == null) {
- throw new ClassNotFoundException(name)
- }
- }
- file = file.lookupName(pathParts.last+".class", false)
- if (file == null) {
- throw new ClassNotFoundException(name)
- }
+
+ for (dirPart <- pathParts.init)
+ file = onull(file.lookupName(dirPart, true))
+
+ file = onull(file.lookupName(pathParts.last+".class", false))
val bytes = file.toByteArray
defineClass(name, bytes, 0, bytes.length)
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 2a6362568a..27259e0d2e 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -136,9 +136,9 @@ class Completion(val interpreter: Interpreter) extends Completor {
filter (isValidCompletion)
// java style, static methods
- val js = interpreter.tryToLoadClass(path).map(getMembers(_, true)) getOrElse Nil
+ val js = (interpreter getClassObject path).map(getMembers(_, true)) getOrElse Nil
// scala style, methods on companion object
- val ss = interpreter.tryToLoadClass(path + "$").map(getMembers(_, false)) getOrElse Nil
+ val ss = (interpreter getClassObject (path + "$")).map(getMembers(_, false)) getOrElse Nil
js ::: ss
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 3559b1f5b1..9fd93ab6ff 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -108,9 +108,9 @@ abstract class SymbolTable extends Names
}
}
- /** Break into repl debugger if assertion is true and debugging enabled */
+ /** Break into repl debugger if assertion is true */
def breakIf(assertion: => Boolean, args: Any*): Unit =
- if (settings.debugger.value && assertion)
+ if (assertion)
Interpreter.break(args.toList)
/** The set of all installed infotransformers */