diff options
author | Paul Phillips <paulp@improving.org> | 2011-09-01 02:31:55 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-09-01 02:31:55 +0000 |
commit | 9954de923ef0c87fcffacabe3e18c31bf7f69f5e (patch) | |
tree | 8ab55c2424b823771ee55b43c67581f86310a981 /src | |
parent | 0377cad8c6a26be5b6dd59323dd171634400005a (diff) | |
download | scala-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.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 46 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Main.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ScriptRunner.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/IMain.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 1 |
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" + |