summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-09-01 02:31:55 +0000
committerPaul Phillips <paulp@improving.org>2011-09-01 02:31:55 +0000
commit9954de923ef0c87fcffacabe3e18c31bf7f69f5e (patch)
tree8ab55c2424b823771ee55b43c67581f86310a981 /src
parent0377cad8c6a26be5b6dd59323dd171634400005a (diff)
downloadscala-9954de923ef0c87fcffacabe3e18c31bf7f69f5e.tar.gz
scala-9954de923ef0c87fcffacabe3e18c31bf7f69f5e.tar.bz2
scala-9954de923ef0c87fcffacabe3e18c31bf7f69f5e.zip
Made it possible to supply a custom Global to t...
Made it possible to supply a custom Global to the core scala runners. The absence of "Global pluggability", combined with the fact that most of the functionality in Global is unnecessarily rigid due to the phases being implemented as objects, means that it has been close to impossible to do interesting compiler development in a way which doesn't require modifying the scalac source tree. This then leaves you continually subject to punishment by code drift as the various places you were forced to modify change out from under you. This is somewhat less true now, thanks to new option: -Yglobal-class The primary wielders of Global (fsc/scala/scalac) now instantiate the compiler via a (Settings, Reporter) => Global factory method in the Global companion. If -Yglobal-class was given, that class (which must have a (Settings, Reporter) constructor) will be instantiated if possible, falling back on the standard one. See test/files/pos/CustomGlobal.scala for a working example. (It's not in run because I would have to be able to give partest a different set of flags for successive compiles in the same test.) Review by odersky.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala10
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala46
-rw-r--r--src/compiler/scala/tools/nsc/Main.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
6 files changed, 57 insertions, 6 deletions
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index da0ae36ba9..f9ca57fadc 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -117,6 +117,16 @@ trait Trees extends api.Trees { self: SymbolTable =>
def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree
def shortClass: String = tree.getClass.getName split "[.$]" last
+ /** When you want to know a little more than the class, but a lot
+ * less than the whole tree.
+ */
+ def summaryString: String = tree match {
+ case Select(qual, name) => qual.summaryString + "." + name
+ case Ident(name) => name.longString
+ case t: DefTree => t.shortClass + " " + t.name
+ case t: RefTree => t.shortClass + " " + t.name.longString
+ case t => t.shortClass
+ }
}
// ---- values and creators ---------------------------------------
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 275dd3a046..4bc00c5f43 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -9,11 +9,11 @@ import java.io.{ File, FileOutputStream, PrintWriter, IOException, FileNotFoundE
import java.nio.charset.{ Charset, CharsetDecoder, IllegalCharsetNameException, UnsupportedCharsetException }
import compat.Platform.currentTime
-import scala.tools.util.Profiling
+import scala.tools.util.{ Profiling, PathResolver }
import scala.collection.{ mutable, immutable }
import io.{ SourceReader, AbstractFile, Path }
import reporters.{ Reporter, ConsoleReporter }
-import util.{ Exceptional, ClassPath, SourceFile, Statistics, StatisticsInfo, BatchSourceFile, ScriptSourceFile, ShowPickled, returning }
+import util.{ NoPosition, Exceptional, ClassPath, SourceFile, Statistics, StatisticsInfo, BatchSourceFile, ScriptSourceFile, ShowPickled, ScalaClassLoader, returning }
import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat }
import settings.{ AestheticSettings }
@@ -377,8 +377,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
val runsRightAfter = None
} with SyntaxAnalyzer
+ // !!! I think we're overdue for all these phase objects being lazy vals.
+ // There's no way for a Global subclass to provide a custom typer
+ // despite the existence of a "def newTyper(context: Context): Typer"
+ // which is clearly designed for that, because it's defined in
+ // Analyzer and Global's "object analyzer" allows no override. For now
+ // I only changed analyzer.
+ //
// factory for phases: namer, packageobjects, typer
- object analyzer extends {
+ lazy val analyzer = new {
val global: Global.this.type = Global.this
} with Analyzer
@@ -1295,3 +1302,36 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
@deprecated("Use forInteractive or forScaladoc, depending on what you're after", "2.9.0")
def onlyPresentation = false
}
+
+object Global {
+ /** If possible, instantiate the global specified via -Yglobal-class.
+ * This allows the use of a custom Global subclass with the software which
+ * wraps Globals, such as scalac, fsc, and the repl.
+ */
+ def fromSettings(settings: Settings, reporter: Reporter): Global = {
+ // !!! The classpath isn't known until the Global is created, which is too
+ // late, so we have to duplicate it here. Classpath is too tightly coupled,
+ // it is a construct external to the compiler and should be treated as such.
+ val loader = ScalaClassLoader.fromURLs(new PathResolver(settings).result.asURLs)
+ val name = settings.globalClass.value
+ val clazz = Class.forName(name, true, loader)
+ val cons = clazz.getConstructor(classOf[Settings], classOf[Reporter])
+
+ cons.newInstance(settings, reporter).asInstanceOf[Global]
+ }
+
+ /** A global instantiated this way honors -Yglobal-class setting, and
+ * falls back on calling the Global constructor directly.
+ */
+ def apply(settings: Settings, reporter: Reporter): Global = {
+ val g = (
+ if (settings.globalClass.isDefault) null
+ else try fromSettings(settings, reporter) catch { case x =>
+ reporter.warning(NoPosition, "Failed to instantiate " + settings.globalClass.value + ": " + x)
+ null
+ }
+ )
+ if (g != null) g
+ else new Global(settings, reporter)
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala
index 38da47aacc..a8dd434690 100644
--- a/src/compiler/scala/tools/nsc/Main.scala
+++ b/src/compiler/scala/tools/nsc/Main.scala
@@ -73,7 +73,7 @@ object Main extends Driver with EvalLoop {
override def newCompiler(): Global =
if (settings.Yrangepos.value) new interactive.Global(settings, reporter)
- else new Global(settings, reporter)
+ else Global(settings, reporter)
override def doCompile(compiler: Global) {
if (settings.resident.value)
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index 3ec5b2f044..dd9bca4b7b 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -84,7 +84,7 @@ class ScriptRunner extends HasCompileSocket {
}
protected def newGlobal(settings: Settings, reporter: Reporter) =
- new Global(settings, reporter)
+ Global(settings, reporter)
/** Compile a script and then run the specified closure with
* a classpath for the compiled script.
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 920367ce2e..7d0be173e2 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -272,7 +272,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
settings.outputDirs setSingleOutput virtualDirectory
settings.exposeEmptyPackage.value = true
- new Global(settings, reporter)
+ Global(settings, reporter)
}
/** Parent classloader. Overridable. */
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 5ffc2e1aad..56ac3e16ad 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -145,6 +145,7 @@ trait ScalaSettings extends AbsScalaSettings
val refinementMethodDispatch =
ChoiceSetting ("-Ystruct-dispatch", "policy", "structural method dispatch policy",
List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache")
+ val globalClass = StringSetting ("-Yglobal-class", "class", "subclass of scala.tools.nsc.Global to use for compiler", "")
val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
val YrichExes = BooleanSetting ("-Yrich-exceptions",
"Fancier exceptions. Set source search path with -D" +