summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-06-19 16:33:19 +0200
committerEugene Burmako <xeno.by@gmail.com>2014-01-24 09:18:04 +0300
commit1d53b2ba45cba536c3369e7b8c300666c603d460 (patch)
treec8d4cc7bb166b776ebc70c7696d82cad9e9f4194 /src/compiler
parentf22ddce265e8622e95f5e9cab4d38168bf2c3bf8 (diff)
downloadscala-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.scala10
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala47
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)()
}
}