@@ -2,9 +2,11 @@ package scala
22package tools
33package reflect
44
5+ import scala .tools .cmd .CommandLineParser
6+ import scala .tools .nsc .Global
57import scala .tools .nsc .reporters ._
68import scala .tools .nsc .CompilerCommand
7- import scala .tools .nsc .io .VirtualDirectory
9+ import scala .tools .nsc .io .{ AbstractFile , VirtualDirectory }
810import scala .tools .nsc .util .AbstractFileClassLoader
911import scala .reflect .internal .Flags ._
1012import scala .reflect .internal .util .{BatchSourceFile , NoSourceFile , NoFile }
@@ -29,6 +31,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
2931 lazy val classLoader = new AbstractFileClassLoader (virtualDirectory, factorySelf.mirror.classLoader)
3032 lazy val mirror : u.Mirror = u.runtimeMirror(classLoader)
3133
34+ lazy val arguments = CommandLineParser .tokenize(options)
35+ lazy val virtualDirectory =
36+ arguments.iterator.sliding(2 ).collectFirst{ case Seq (" -d" , dir) => dir } match {
37+ case Some (outDir) => AbstractFile .getDirectory(outDir)
38+ case None => new VirtualDirectory (" (memory)" , None )
39+ }
40+
3241 class ToolBoxGlobal (settings : scala.tools.nsc.Settings , reporter0 : Reporter )
3342 extends ReflectGlobal (settings, reporter0, toolBoxSelf.classLoader) {
3443 import definitions ._
@@ -47,7 +56,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
4756 }
4857
4958 // should be called after every use of ToolBoxGlobal in order to prevent leaks
50- // there's the `withCleanupCaches` method defined below, which provides a convenient interface for that
5159 def cleanupCaches (): Unit = {
5260 perRunCaches.clearAll()
5361 undoLog.clear()
@@ -56,14 +64,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
5664 lastSeenContext = null
5765 }
5866
59- def withCleanupCaches [T ](body : => T ): T =
60- try body
61- finally cleanupCaches()
62-
63- def wrappingFatalErrors [T ](body : => T ): T =
64- try body
65- catch { case ex : FatalError => throw ToolBoxError (s " fatal compiler error " , ex) }
66-
6767 def verify (expr : Tree ): Unit = {
6868 // Previously toolboxes used to typecheck their inputs before compiling.
6969 // Actually, the initial demo by Martin first typechecked the reified tree,
@@ -307,50 +307,56 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
307307 }
308308 }
309309
310- // todo. is not going to work with quoted arguments with embedded whitespaces
311- lazy val arguments = options.split(" " )
310+ trait CompilerApi {
311+ val compiler : ToolBoxGlobal
312+ val importer : compiler.Importer { val from : u.type }
313+ val exporter : u.Importer { val from : compiler.type }
314+ }
312315
313- lazy val virtualDirectory =
314- (arguments zip arguments.tail).collect{ case (" -d" , dir) => dir }.lastOption match {
315- case Some (outDir) => scala.tools.nsc.io.AbstractFile .getDirectory(outDir)
316- case None => new VirtualDirectory (" (memory)" , None )
316+ object withCompilerApi {
317+ private object api extends CompilerApi {
318+ lazy val compiler : ToolBoxGlobal = {
319+ try {
320+ val errorFn : String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition , msg, frontEnd.ERROR )
321+ val command = new CompilerCommand (arguments.toList, errorFn)
322+ command.settings.outputDirs setSingleOutput virtualDirectory
323+ val instance = new ToolBoxGlobal (command.settings, frontEndToReporter(frontEnd, command.settings))
324+ if (frontEnd.hasErrors) {
325+ throw ToolBoxError (
326+ " reflective compilation has failed: cannot initialize the compiler:" + EOL + EOL +
327+ (frontEnd.infos map (_.msg) mkString EOL )
328+ )
329+ }
330+ instance
331+ } catch {
332+ case ex : Throwable =>
333+ throw ToolBoxError (s " reflective compilation has failed: cannot initialize the compiler due to $ex" , ex)
334+ }
335+ }
336+
337+ lazy val importer = compiler.mkImporter(u)
338+ lazy val exporter = importer.reverse
317339 }
318340
319- lazy val compiler : ToolBoxGlobal = {
320- try {
321- val errorFn : String => Unit = msg => frontEnd.log(scala.reflect.internal.util.NoPosition , msg, frontEnd.ERROR )
322- val command = new CompilerCommand (arguments.toList, errorFn)
323- command.settings.outputDirs setSingleOutput virtualDirectory
324- val instance = new ToolBoxGlobal (command.settings, frontEndToReporter(frontEnd, command.settings))
325- if (frontEnd.hasErrors) {
326- throw ToolBoxError (
327- " reflective compilation has failed: cannot initialize the compiler:" + EOL + EOL +
328- (frontEnd.infos map (_.msg) mkString EOL )
329- )
330- }
331- instance
332- } catch {
333- case ex : Throwable =>
334- throw ToolBoxError (s " reflective compilation has failed: cannot initialize the compiler due to $ex" , ex)
341+ def apply [T ](f : CompilerApi => T ): T = {
342+ try f(api)
343+ catch { case ex : FatalError => throw ToolBoxError (s " fatal compiler error " , ex) }
344+ finally api.compiler.cleanupCaches()
335345 }
336346 }
337347
338- lazy val importer = compiler.mkImporter(u)
339- lazy val exporter = importer.reverse
348+ def typeCheck ( tree : u. Tree , expectedType : u. Type , silent : Boolean = false , withImplicitViewsDisabled : Boolean = false , withMacrosDisabled : Boolean = false ) : u. Tree = withCompilerApi { compilerApi =>
349+ import compilerApi . _
340350
341- def typeCheck (tree : u.Tree , expectedType : u.Type , silent : Boolean = false , withImplicitViewsDisabled : Boolean = false , withMacrosDisabled : Boolean = false ): u.Tree =
342- compiler.wrappingFatalErrors {
343- compiler.withCleanupCaches {
344- if (compiler.settings.verbose) println(" importing " + tree+ " , expectedType = " + expectedType)
345- val ctree : compiler.Tree = importer.importTree(tree)
346- val cexpectedType : compiler.Type = importer.importType(expectedType)
351+ if (compiler.settings.verbose) println(" importing " + tree+ " , expectedType = " + expectedType)
352+ val ctree : compiler.Tree = importer.importTree(tree)
353+ val cexpectedType : compiler.Type = importer.importType(expectedType)
347354
348- if (compiler.settings.verbose) println(" typing " + ctree+ " , expectedType = " + expectedType)
349- val ttree : compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
350- val uttree = exporter.importTree(ttree)
351- uttree
352- }
353- }
355+ if (compiler.settings.verbose) println(" typing " + ctree+ " , expectedType = " + expectedType)
356+ val ttree : compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
357+ val uttree = exporter.importTree(ttree)
358+ uttree
359+ }
354360
355361 def inferImplicitValue (pt : u.Type , silent : Boolean = true , withMacrosDisabled : Boolean = false , pos : u.Position = u.NoPosition ): u.Tree = {
356362 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 =>
362368 inferImplicit(tree, viewTpe, isView = true , silent = silent, withMacrosDisabled = withMacrosDisabled, pos = pos)
363369 }
364370
365- private def inferImplicit (tree : u.Tree , pt : u.Type , isView : Boolean , silent : Boolean , withMacrosDisabled : Boolean , pos : u.Position ): u.Tree =
366- compiler.wrappingFatalErrors {
367- compiler.withCleanupCaches {
368- if (compiler.settings.verbose) println(s " importing pt= $pt, tree= $tree, pos= $pos" )
369- val ctree : compiler.Tree = importer.importTree(tree)
370- val cpt : compiler.Type = importer.importType(pt)
371- val cpos : compiler.Position = importer.importPosition(pos)
372-
373- if (compiler.settings.verbose) println(" inferring implicit %s of type %s, macros = %s" .format(if (isView) " view" else " value" , pt, ! withMacrosDisabled))
374- val itree : compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos)
375- val uitree = exporter.importTree(itree)
376- uitree
377- }
378- }
371+ private def inferImplicit (tree : u.Tree , pt : u.Type , isView : Boolean , silent : Boolean , withMacrosDisabled : Boolean , pos : u.Position ): u.Tree = withCompilerApi { compilerApi =>
372+ import compilerApi ._
379373
380- def resetAllAttrs (tree : u.Tree ): u.Tree = compiler.wrappingFatalErrors {
374+ if (compiler.settings.verbose) println(s " importing pt= $pt, tree= $tree, pos= $pos" )
375+ val ctree : compiler.Tree = importer.importTree(tree)
376+ val cpt : compiler.Type = importer.importType(pt)
377+ val cpos : compiler.Position = importer.importPosition(pos)
378+
379+ if (compiler.settings.verbose) println(" inferring implicit %s of type %s, macros = %s" .format(if (isView) " view" else " value" , pt, ! withMacrosDisabled))
380+ val itree : compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos)
381+ val uitree = exporter.importTree(itree)
382+ uitree
383+ }
384+
385+ def resetAllAttrs (tree : u.Tree ): u.Tree = withCompilerApi { compilerApi =>
386+ import compilerApi ._
381387 val ctree : compiler.Tree = importer.importTree(tree)
382388 val ttree : compiler.Tree = compiler.resetAllAttrs(ctree)
383389 val uttree = exporter.importTree(ttree)
384390 uttree
385391 }
386392
387- def resetLocalAttrs (tree : u.Tree ): u.Tree = compiler.wrappingFatalErrors {
393+ def resetLocalAttrs (tree : u.Tree ): u.Tree = withCompilerApi { compilerApi =>
394+ import compilerApi ._
388395 val ctree : compiler.Tree = importer.importTree(tree)
389396 val ttree : compiler.Tree = compiler.resetLocalAttrs(ctree)
390397 val uttree = exporter.importTree(ttree)
391398 uttree
392399 }
393400
394- def parse (code : String ): u.Tree = compiler.wrappingFatalErrors {
401+ def parse (code : String ): u.Tree = withCompilerApi { compilerApi =>
402+ import compilerApi ._
395403 if (compiler.settings.verbose) println(" parsing " + code)
396404 val ctree : compiler.Tree = compiler.parse(code)
397405 val utree = exporter.importTree(ctree)
398406 utree
399407 }
400408
401- def compile (tree : u.Tree ): () => Any = compiler.wrappingFatalErrors {
409+ def compile (tree : u.Tree ): () => Any = withCompilerApi { compilerApi =>
410+ import compilerApi ._
411+
402412 if (compiler.settings.verbose) println(" importing " + tree)
403413 val ctree : compiler.Tree = importer.importTree(tree)
404414
0 commit comments