diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2013-06-19 16:33:19 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-01-24 09:18:04 +0300 |
commit | 1d53b2ba45cba536c3369e7b8c300666c603d460 (patch) | |
tree | c8d4cc7bb166b776ebc70c7696d82cad9e9f4194 /src/compiler | |
parent | f22ddce265e8622e95f5e9cab4d38168bf2c3bf8 (diff) | |
download | scala-1d53b2ba45cba536c3369e7b8c300666c603d460.tar.gz scala-1d53b2ba45cba536c3369e7b8c300666c603d460.tar.bz2 scala-1d53b2ba45cba536c3369e7b8c300666c603d460.zip |
SI-7570 top-level codegen for toolboxes
Provides a way to inject top-level classes, traits and modules into
toolbox universes.
Previously that was impossible, because compile and eval both wrap their
arguments into an enclosing method of a synthetic module, which makes it
impossible to later on refer to any definitions from the outside.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/reflect/ToolBox.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/ToolBoxFactory.scala | 47 |
2 files changed, 46 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 4c1bc794bc..8b0dd66ac2 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -102,6 +102,16 @@ trait ToolBox[U <: scala.reflect.api.Universe] { */ def compile(tree: u.Tree): () => Any + /** Defines a top-level class, trait or module in this ToolBox, + * putting it into a uniquely-named package and returning a symbol that references the defined entity. + * For a ClassDef, a ClassSymbol is returned, and for a ModuleDef, a ModuleSymbol is returned (not a module class, but a module itself). + * + * This method can be used to generate definitions that will later be re-used by subsequent calls to + * `compile`, `define` or `eval`. To refer to the generated definition, use the resulting symbol + * by wrapping it into an `Ident`. + */ + def define(tree: u.ImplDef): u.Symbol + /** Compiles and runs a tree using this ToolBox. * Is equivalent to `compile(tree)()`. */ diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 4a8c91bd1b..c54f2d06ba 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -193,6 +193,19 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg)) }) + private def wrapInPackageAndCompile(packageName: TermName, tree: ImplDef): Symbol = { + val pdef = PackageDef(Ident(packageName), List(tree)) + val unit = new CompilationUnit(NoSourceFile) + unit.body = pdef + + val run = new Run + reporter.reset() + run.compileUnits(List(unit), run.namerPhase) + throwIfErrors() + + tree.symbol + } + def compile(expr0: Tree): () => Any = { val expr = wrapIntoTerm(expr0) @@ -200,7 +213,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) - def wrap(expr0: Tree): ModuleDef = { + def wrapInModule(expr0: Tree): ModuleDef = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) val (obj, _) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( @@ -241,17 +254,10 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => cleanedUp.asInstanceOf[ModuleDef] } - val mdef = wrap(expr) - val pdef = PackageDef(Ident(mdef.name), List(mdef)) - val unit = new CompilationUnit(NoSourceFile) - unit.body = pdef + val mdef = wrapInModule(expr) + val msym = wrapInPackageAndCompile(mdef.name, mdef) - val run = new Run - reporter.reset() - run.compileUnits(List(unit), run.namerPhase) - throwIfErrors() - - val className = mdef.symbol.fullName + val className = msym.fullName if (settings.debug) println("generated: "+className) def moduleFileName(className: String) = className + "$" val jclazz = jClass.forName(moduleFileName(className), true, classLoader) @@ -278,6 +284,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } } + def define(tree: ImplDef): Symbol = { + val freeTerms = tree.freeTerms + if (freeTerms.nonEmpty) throw ToolBoxError(s"reflective toolbox has failed: cannot have free terms in a top-level definition") + verify(tree) + wrapInPackageAndCompile(nextWrapperModuleName(), tree) + } + def parse(code: String): Tree = { reporter.reset() val tree = gen.mkTreeOrBlock(newUnitParser(code, "<toolbox>").parseStatsOrPackages()) @@ -421,6 +434,18 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => compiler.compile(ctree) } + def define(tree: u.ImplDef): u.Symbol = withCompilerApi { compilerApi => + import compilerApi._ + + if (compiler.settings.verbose) println("importing "+tree) + val ctree: compiler.ImplDef = importer.importTree(tree).asInstanceOf[compiler.ImplDef] + + if (compiler.settings.verbose) println("defining "+ctree) + val csym: compiler.Symbol = compiler.define(ctree) + val usym = exporter.importSymbol(csym) + usym + } + def eval(tree: u.Tree): Any = compile(tree)() } } |