From ba3a9e05a6276fec976f4e53923e70b58b9f647b Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 14 Sep 2012 16:40:46 +0200 Subject: SI-6342 cleans up toolbox API 1) parseExpr => parse 2) runExpr => eval 3) Introduces compile(Tree): () => Any, since it has frequent uses --- .../scala/reflect/macros/runtime/Evals.scala | 2 +- .../scala/reflect/macros/runtime/Parsers.scala | 2 +- .../scala/reflect/reify/utils/NodePrinters.scala | 2 +- src/compiler/scala/tools/reflect/ToolBox.scala | 13 ++++-- .../scala/tools/reflect/ToolBoxFactory.scala | 47 +++++++++++----------- src/compiler/scala/tools/reflect/package.scala | 2 +- .../scala/reflect/macros/Infrastructure.scala | 2 +- src/reflect/scala/reflect/macros/Parsers.scala | 2 +- 8 files changed, 38 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/macros/runtime/Evals.scala b/src/compiler/scala/reflect/macros/runtime/Evals.scala index 348e29cdd7..acafeb5b02 100644 --- a/src/compiler/scala/reflect/macros/runtime/Evals.scala +++ b/src/compiler/scala/reflect/macros/runtime/Evals.scala @@ -13,6 +13,6 @@ trait Evals { def eval[T](expr: Expr[T]): T = { val imported = evalImporter.importTree(expr.tree) - evalToolBox.runExpr(imported).asInstanceOf[T] + evalToolBox.eval(imported).asInstanceOf[T] } } \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/Parsers.scala b/src/compiler/scala/reflect/macros/runtime/Parsers.scala index e4acf104e3..5096526fdb 100644 --- a/src/compiler/scala/reflect/macros/runtime/Parsers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Parsers.scala @@ -12,7 +12,7 @@ trait Parsers { // todo. provide decent implementation try { import scala.reflect.runtime.{universe => ru} - val parsed = ru.rootMirror.mkToolBox().parseExpr(code) + val parsed = ru.rootMirror.mkToolBox().parse(code) val importer = universe.mkImporter(ru) importer.importTree(parsed) } catch { diff --git a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala index ec1f132c1b..c023be1a50 100644 --- a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala +++ b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala @@ -94,7 +94,7 @@ trait NodePrinters { if (isExpr) { if (mirror contains ".getClassLoader") { printout += "import scala.tools.reflect.ToolBox" - printout += s"println(${nme.MIRROR_SHORT}.mkToolBox().runExpr(tree))" + printout += s"println(${nme.MIRROR_SHORT}.mkToolBox().eval(tree))" } else { printout += "println(tree)" } diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 85e2b6543f..9e7d230a6a 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -80,18 +80,23 @@ trait ToolBox[U <: Universe] { def resetLocalAttrs(tree: u.Tree): u.Tree /** .. */ - def parseExpr(code: String): u.Tree + def parse(code: String): u.Tree - /** Compiles and runs a tree using this ToolBox. + /** Compiles a tree using this ToolBox. * * If the tree has unresolved type variables (represented as instances of `FreeTypeSymbol` symbols), * then they all have to be resolved first using `Tree.substituteTypes`, or an error occurs. * * This spawns the compiler at the Namer phase, and pipelines the tree through that compiler. - * Currently `runExpr` does not accept trees that already typechecked, because typechecking isn't idempotent. + * Currently `compile` does not accept trees that already typechecked, because typechecking isn't idempotent. * For more info, take a look at https://issues.scala-lang.org/browse/SI-5464. */ - def runExpr(tree: u.Tree): Any + def compile(tree: u.Tree): () => Any + + /** Compiles and runs a tree using this ToolBox. + * Is equivalent to `compile(tree)()`. + */ + def eval(tree: u.Tree): Any } /** Represents an error during toolboxing diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index b658491294..b671a2eb48 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -47,7 +47,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => newTermName("__wrapper$" + wrapCount + "$" + java.util.UUID.randomUUID.toString.replace("-", "")) } - def verifyExpr(expr: Tree): Unit = { + 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, // then ran it, which typechecked it again, and only then launched the @@ -97,7 +97,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } def transformDuringTyper(expr0: Tree, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean)(transform: (analyzer.Typer, Tree) => Tree): Tree = { - verifyExpr(expr0) + verify(expr0) // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars var (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = false) @@ -140,7 +140,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => unwrapped } - def typeCheckExpr(expr: Tree, pt: Type, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree = + def typeCheck(expr: Tree, pt: Type, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree = transformDuringTyper(expr, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)( (currentTyper, expr) => { trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymkinds.value)) @@ -170,10 +170,12 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } }) - def compileExpr(expr: Tree): (Object, java.lang.reflect.Method) = { - verifyExpr(expr) + def compile(expr: Tree): () => Any = { + val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased + val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order + verify(expr) - def wrapExpr(expr0: Tree): Tree = { + def wrap(expr0: Tree): Tree = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) val (obj, mclazz) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( @@ -214,7 +216,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => cleanedUp } - val mdef = wrapExpr(expr) + val mdef = wrap(expr) val pdef = PackageDef(Ident(nme.EMPTY_PACKAGE_NAME), List(mdef)) val unit = new CompilationUnit(NoSourceFile) unit.body = pdef @@ -231,12 +233,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val jmeth = jclazz.getDeclaredMethods.find(_.getName == wrapperMethodName).get val jfield = jclazz.getDeclaredFields.find(_.getName == NameTransformer.MODULE_INSTANCE_NAME).get val singleton = jfield.get(null) - (singleton, jmeth) - } - - def runExpr(expr: Tree): Any = { - val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased - val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order // @odersky writes: Not sure we will be able to drop this. I forgot the reason why we dereference () functions, // but there must have been one. So I propose to leave old version in comments to be resurrected if the problem resurfaces. @@ -250,13 +246,14 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => // val applyMeth = result.getClass.getMethod("apply") // applyMeth.invoke(result) // } - val (singleton, jmeth) = compileExpr(expr) - val result = jmeth.invoke(singleton, thunks map (_.asInstanceOf[AnyRef]): _*) - if (jmeth.getReturnType == java.lang.Void.TYPE) () - else result + () => { + val result = jmeth.invoke(singleton, thunks map (_.asInstanceOf[AnyRef]): _*) + if (jmeth.getReturnType == java.lang.Void.TYPE) () + else result + } } - def parseExpr(code: String): Tree = { + def parse(code: String): Tree = { val run = new Run reporter.reset() val wrappedCode = "object wrapper {" + EOL + code + EOL + "}" @@ -336,7 +333,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => var cexpectedType: compiler.Type = importer.importType(expectedType) if (compiler.settings.verbose.value) println("typing "+ctree+", expectedType = "+expectedType) - val ttree: compiler.Tree = compiler.typeCheckExpr(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled) + val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled) val uttree = exporter.importTree(ttree) uttree } @@ -379,20 +376,22 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def showAttributed(tree: u.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = compiler.showAttributed(importer.importTree(tree), printTypes, printIds, printKinds) - def parseExpr(code: String): u.Tree = { + def parse(code: String): u.Tree = { if (compiler.settings.verbose.value) println("parsing "+code) - val ctree: compiler.Tree = compiler.parseExpr(code) + val ctree: compiler.Tree = compiler.parse(code) val utree = exporter.importTree(ctree) utree } - def runExpr(tree: u.Tree): Any = { + def compile(tree: u.Tree): () => Any = { if (compiler.settings.verbose.value) println("importing "+tree) var ctree: compiler.Tree = importer.importTree(tree) - if (compiler.settings.verbose.value) println("running "+ctree) - compiler.runExpr(ctree) + if (compiler.settings.verbose.value) println("compiling "+ctree) + compiler.compile(ctree) } + + def eval(tree: u.Tree): Any = compile(tree)() } } diff --git a/src/compiler/scala/tools/reflect/package.scala b/src/compiler/scala/tools/reflect/package.scala index d5569e448d..901071d91a 100644 --- a/src/compiler/scala/tools/reflect/package.scala +++ b/src/compiler/scala/tools/reflect/package.scala @@ -27,7 +27,7 @@ package reflect { def eval: T = { val factory = new ToolBoxFactory[JavaUniverse](expr.mirror.universe) { val mirror = expr.mirror.asInstanceOf[this.u.Mirror] } val toolBox = factory.mkToolBox() - toolBox.runExpr(expr.tree.asInstanceOf[toolBox.u.Tree]).asInstanceOf[T] + toolBox.eval(expr.tree.asInstanceOf[toolBox.u.Tree]).asInstanceOf[T] } } } diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala index f01725cd1d..c195692832 100644 --- a/src/reflect/scala/reflect/macros/Infrastructure.scala +++ b/src/reflect/scala/reflect/macros/Infrastructure.scala @@ -43,7 +43,7 @@ trait Infrastructure { * val importer = ru.mkImporter(c.universe).asInstanceOf[ru.Importer { val from: c.universe.type }] * val tree = c.resetAllAttrs(x.tree.duplicate) * val imported = importer.importTree(tree) - * val valueOfX = toolBox.runExpr(imported).asInstanceOf[T] + * val valueOfX = toolBox.eval(imported).asInstanceOf[T] * ... * } */ diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala index ea87c5842e..1742d07b60 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -5,7 +5,7 @@ trait Parsers { self: Context => /** .. */ - // todo. distinguish between `parseExpr` and `parse` + // todo. distinguish between `parse` and `parse` def parse(code: String): Tree /** Represents an error during parsing -- cgit v1.2.3