summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/reflect
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-09-27 10:27:05 +0200
committerEugene Burmako <xeno.by@gmail.com>2013-09-27 12:27:35 +0200
commit4133eb8454fe35ef11aaedc1a9008d052c913930 (patch)
treee0050c90c72d80160b75a84288dcc3d04c14237c /src/compiler/scala/tools/reflect
parent7122560063b4cbe1e8012decbc842bf610e55863 (diff)
downloadscala-4133eb8454fe35ef11aaedc1a9008d052c913930.tar.gz
scala-4133eb8454fe35ef11aaedc1a9008d052c913930.tar.bz2
scala-4133eb8454fe35ef11aaedc1a9008d052c913930.zip
refactors ToolBoxGlobal wrappers
Centralizes wrappers in a single location and makes it impossible to use the compiler without going through that location. Also fixes the option string tokenization bug that was there for ages. This time I figured out that there's already an implementation of the tokenizer in our compiler, so I just used it :)
Diffstat (limited to 'src/compiler/scala/tools/reflect')
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala138
1 files changed, 74 insertions, 64 deletions
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 52b2f0800d..7114568d21 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -2,9 +2,11 @@ package scala
package tools
package reflect
+import scala.tools.cmd.CommandLineParser
+import scala.tools.nsc.Global
import scala.tools.nsc.reporters._
import scala.tools.nsc.CompilerCommand
-import scala.tools.nsc.io.VirtualDirectory
+import scala.tools.nsc.io.{AbstractFile, VirtualDirectory}
import scala.tools.nsc.util.AbstractFileClassLoader
import scala.reflect.internal.Flags._
import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile}
@@ -29,6 +31,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, factorySelf.mirror.classLoader)
lazy val mirror: u.Mirror = u.runtimeMirror(classLoader)
+ lazy val arguments = CommandLineParser.tokenize(options)
+ lazy val virtualDirectory =
+ arguments.iterator.sliding(2).collectFirst{ case Seq("-d", dir) => dir } match {
+ case Some(outDir) => AbstractFile.getDirectory(outDir)
+ case None => new VirtualDirectory("(memory)", None)
+ }
+
class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter0: Reporter)
extends ReflectGlobal(settings, reporter0, toolBoxSelf.classLoader) {
import definitions._
@@ -47,7 +56,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
// should be called after every use of ToolBoxGlobal in order to prevent leaks
- // there's the `withCleanupCaches` method defined below, which provides a convenient interface for that
def cleanupCaches(): Unit = {
perRunCaches.clearAll()
undoLog.clear()
@@ -56,14 +64,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lastSeenContext = null
}
- def withCleanupCaches[T](body: => T): T =
- try body
- finally cleanupCaches()
-
- def wrappingFatalErrors[T](body: => T): T =
- try body
- catch { case ex: FatalError => throw ToolBoxError(s"fatal compiler error", ex) }
-
def verify(expr: Tree): Unit = {
// Previously toolboxes used to typecheck their inputs before compiling.
// Actually, the initial demo by Martin first typechecked the reified tree,
@@ -307,50 +307,56 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
}
- // todo. is not going to work with quoted arguments with embedded whitespaces
- lazy val arguments = options.split(" ")
+ trait CompilerApi {
+ val compiler: ToolBoxGlobal
+ val importer: compiler.Importer { val from: u.type }
+ val exporter: u.Importer { val from: compiler.type }
+ }
- lazy val virtualDirectory =
- (arguments zip arguments.tail).collect{ case ("-d", dir) => dir }.lastOption match {
- case Some(outDir) => scala.tools.nsc.io.AbstractFile.getDirectory(outDir)
- case None => new VirtualDirectory("(memory)", None)
+ object withCompilerApi {
+ private object api extends CompilerApi {
+ lazy val compiler: ToolBoxGlobal = {
+ try {
+ val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR)
+ val command = new CompilerCommand(arguments.toList, errorFn)
+ command.settings.outputDirs setSingleOutput virtualDirectory
+ val instance = new ToolBoxGlobal(command.settings, frontEndToReporter(frontEnd, command.settings))
+ if (frontEnd.hasErrors) {
+ throw ToolBoxError(
+ "reflective compilation has failed: cannot initialize the compiler:" + EOL + EOL +
+ (frontEnd.infos map (_.msg) mkString EOL)
+ )
+ }
+ instance
+ } catch {
+ case ex: Throwable =>
+ throw ToolBoxError(s"reflective compilation has failed: cannot initialize the compiler due to $ex", ex)
+ }
+ }
+
+ lazy val importer = compiler.mkImporter(u)
+ lazy val exporter = importer.reverse
}
- lazy val compiler: ToolBoxGlobal = {
- try {
- val errorFn: String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition, msg, frontEnd.ERROR)
- val command = new CompilerCommand(arguments.toList, errorFn)
- command.settings.outputDirs setSingleOutput virtualDirectory
- val instance = new ToolBoxGlobal(command.settings, frontEndToReporter(frontEnd, command.settings))
- if (frontEnd.hasErrors) {
- throw ToolBoxError(
- "reflective compilation has failed: cannot initialize the compiler:" + EOL + EOL +
- (frontEnd.infos map (_.msg) mkString EOL)
- )
- }
- instance
- } catch {
- case ex: Throwable =>
- throw ToolBoxError(s"reflective compilation has failed: cannot initialize the compiler due to $ex", ex)
+ def apply[T](f: CompilerApi => T): T = {
+ try f(api)
+ catch { case ex: FatalError => throw ToolBoxError(s"fatal compiler error", ex) }
+ finally api.compiler.cleanupCaches()
}
}
- lazy val importer = compiler.mkImporter(u)
- lazy val exporter = importer.reverse
+ def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
- def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree =
- compiler.wrappingFatalErrors {
- compiler.withCleanupCaches {
- if (compiler.settings.verbose) println("importing "+tree+", expectedType = "+expectedType)
- val ctree: compiler.Tree = importer.importTree(tree)
- val cexpectedType: compiler.Type = importer.importType(expectedType)
+ if (compiler.settings.verbose) println("importing "+tree+", expectedType = "+expectedType)
+ val ctree: compiler.Tree = importer.importTree(tree)
+ val cexpectedType: compiler.Type = importer.importType(expectedType)
- if (compiler.settings.verbose) println("typing "+ctree+", expectedType = "+expectedType)
- val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
- val uttree = exporter.importTree(ttree)
- uttree
- }
- }
+ if (compiler.settings.verbose) println("typing "+ctree+", expectedType = "+expectedType)
+ val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
+ val uttree = exporter.importTree(ttree)
+ uttree
+ }
def inferImplicitValue(pt: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree = {
inferImplicit(u.EmptyTree, pt, isView = false, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
@@ -362,43 +368,47 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
inferImplicit(tree, viewTpe, isView = true, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
}
- private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree =
- compiler.wrappingFatalErrors {
- compiler.withCleanupCaches {
- if (compiler.settings.verbose) println(s"importing pt=$pt, tree=$tree, pos=$pos")
- val ctree: compiler.Tree = importer.importTree(tree)
- val cpt: compiler.Type = importer.importType(pt)
- val cpos: compiler.Position = importer.importPosition(pos)
-
- if (compiler.settings.verbose) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled))
- val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos)
- val uitree = exporter.importTree(itree)
- uitree
- }
- }
+ private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
- def resetAllAttrs(tree: u.Tree): u.Tree = compiler.wrappingFatalErrors {
+ if (compiler.settings.verbose) println(s"importing pt=$pt, tree=$tree, pos=$pos")
+ val ctree: compiler.Tree = importer.importTree(tree)
+ val cpt: compiler.Type = importer.importType(pt)
+ val cpos: compiler.Position = importer.importPosition(pos)
+
+ if (compiler.settings.verbose) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled))
+ val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos)
+ val uitree = exporter.importTree(itree)
+ uitree
+ }
+
+ def resetAllAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetAllAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}
- def resetLocalAttrs(tree: u.Tree): u.Tree = compiler.wrappingFatalErrors {
+ def resetLocalAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
val ctree: compiler.Tree = importer.importTree(tree)
val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree)
val uttree = exporter.importTree(ttree)
uttree
}
- def parse(code: String): u.Tree = compiler.wrappingFatalErrors {
+ def parse(code: String): u.Tree = withCompilerApi { compilerApi =>
+ import compilerApi._
if (compiler.settings.verbose) println("parsing "+code)
val ctree: compiler.Tree = compiler.parse(code)
val utree = exporter.importTree(ctree)
utree
}
- def compile(tree: u.Tree): () => Any = compiler.wrappingFatalErrors {
+ def compile(tree: u.Tree): () => Any = withCompilerApi { compilerApi =>
+ import compilerApi._
+
if (compiler.settings.verbose) println("importing "+tree)
val ctree: compiler.Tree = importer.importTree(tree)