Permalink
Browse files

brings macros up to speed

Before reflection refactoring, macro contexts only exposed a mirror.
Now it's time to expose both a universe (the compiler instance) and
a mirror (a macro-specific symbol resolver).

By the way, speaking of mirrors. Macro contexts have their own mirror,
which is different from compiler's rootMirror. This is done because
macros need to be able to resolve stuff from empty package.

Reflection refactoring brought major changes to runtime evaluation,
which got dropped from universes and now requires scala-compiler.jar.
However there are macro users, who would like to do eval inside macros.
To help them we expose `libraryClassLoader` to manually build toolboxes,
and also a simple-to-use `c.eval` method.

I've also sneakily introduced `c.parse`, because it's something that
has also been frequently requested. Moreover, it might help Scaladoc.
So I decided that it might be worth it to add this new functionality.
  • Loading branch information...
1 parent bdff66e commit ce67870e64afabf75363679bcee597812ad223e9 @xeno-by xeno-by committed Jun 6, 2012
Showing with 293 additions and 119 deletions.
  1. +1 −0 src/compiler/scala/reflect/internal/Definitions.scala
  2. +19 −15 src/compiler/scala/reflect/makro/runtime/Aliases.scala
  3. +4 −3 src/compiler/scala/reflect/makro/runtime/CapturedVariables.scala
  4. +8 −3 src/compiler/scala/reflect/makro/runtime/Context.scala
  5. +2 −1 src/compiler/scala/reflect/makro/runtime/Enclosures.scala
  6. +18 −0 src/compiler/scala/reflect/makro/runtime/Evals.scala
  7. +1 −1 src/compiler/scala/reflect/makro/runtime/Exprs.scala
  8. +11 −10 src/compiler/scala/reflect/makro/runtime/FrontEnds.scala
  9. +27 −9 src/compiler/scala/reflect/makro/runtime/Infrastructure.scala
  10. +40 −0 src/compiler/scala/reflect/makro/runtime/Mirrors.scala
  11. +2 −2 src/compiler/scala/reflect/makro/runtime/Names.scala
  12. +25 −0 src/compiler/scala/reflect/makro/runtime/Parsers.scala
  13. +4 −4 src/compiler/scala/reflect/makro/runtime/Reifiers.scala
  14. +3 −3 src/compiler/scala/reflect/makro/runtime/Settings.scala
  15. +1 −1 src/compiler/scala/reflect/makro/runtime/Traces.scala
  16. +2 −2 src/compiler/scala/reflect/makro/runtime/TypeTags.scala
  17. +20 −20 src/compiler/scala/reflect/makro/runtime/Typers.scala
  18. +1 −1 src/compiler/scala/reflect/makro/runtime/Util.scala
  19. +1 −1 src/compiler/scala/reflect/reify/Taggers.scala
  20. +15 −18 src/compiler/scala/tools/nsc/typechecker/Macros.scala
  21. +2 −2 src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
  22. +16 −18 src/library/scala/reflect/makro/Aliases.scala
  23. +7 −2 src/library/scala/reflect/makro/Context.scala
  24. +8 −0 src/library/scala/reflect/makro/Evals.scala
  25. +1 −1 src/library/scala/reflect/makro/FrontEnds.scala
  26. +29 −0 src/library/scala/reflect/makro/Infrastructure.scala
  27. +1 −1 src/library/scala/reflect/makro/Names.scala
  28. +17 −0 src/library/scala/reflect/makro/Parsers.scala
  29. +1 −1 src/library/scala/reflect/makro/Typers.scala
  30. +6 −0 src/library/scala/reflect/makro/package.scala
@@ -477,6 +477,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val MacroContextClass = getClassIfDefined("scala.reflect.makro.Context") // defined in scala-reflect.jar, so we need to be careful
def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol
def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol
+ def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol
def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol
def MacroContextReify = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.reify) else NoSymbol
lazy val MacroImplAnnotation = requiredClass[scala.reflect.makro.internal.macroImpl]
@@ -4,20 +4,24 @@ package runtime
trait Aliases {
self: Context =>
- /** Aliases of mirror types */
- override type Symbol = mirror.Symbol
- override type Type = mirror.Type
- override type Name = mirror.Name
- override type Tree = mirror.Tree
- // override type Position = mirror.Position
- override type Scope = mirror.Scope
- override type Modifiers = mirror.Modifiers
- override type Expr[+T] = mirror.Expr[T]
- override type TypeTag[T] = mirror.TypeTag[T]
- override type ConcreteTypeTag[T] = mirror.ConcreteTypeTag[T]
+ override type Symbol = universe.Symbol
+ override type Type = universe.Type
+ override type Name = universe.Name
+ override type TermName = universe.TermName
+ override type TypeName = universe.TypeName
+ override type Tree = universe.Tree
+ // override type Position = universe.Position
+ override type Scope = universe.Scope
+ override type Modifiers = universe.Modifiers
- /** Creator/extractor objects for Expr and TypeTag values */
- override val TypeTag = mirror.TypeTag
- override val ConcreteTypeTag = mirror.ConcreteTypeTag
- override val Expr = mirror.Expr
+ override type Expr[+T] = universe.Expr[T]
+ override val Expr = universe.Expr
+
+ override type TypeTag[T] = universe.TypeTag[T]
+ override type ConcreteTypeTag[T] = universe.ConcreteTypeTag[T]
+ override val TypeTag = universe.TypeTag
+ override val ConcreteTypeTag = universe.ConcreteTypeTag
+ override def typeTag[T](implicit ttag: TypeTag[T]) = ttag
+ override def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag
+ override def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
}
@@ -5,10 +5,11 @@ trait CapturedVariables {
self: Context =>
import mirror._
+ import universe._
- def captureVariable(vble: Symbol): Unit = mirror.captureVariable(vble)
+ def captureVariable(vble: Symbol): Unit = universe.captureVariable(vble)
- def referenceCapturedVariable(vble: Symbol): Tree = mirror.referenceCapturedVariable(vble)
+ def referenceCapturedVariable(vble: Symbol): Tree = universe.referenceCapturedVariable(vble)
- def capturedVariableType(vble: Symbol): Type = mirror.capturedVariableType(vble)
+ def capturedVariableType(vble: Symbol): Type = universe.capturedVariableType(vble)
}
@@ -8,21 +8,26 @@ abstract class Context extends scala.reflect.makro.Context
with CapturedVariables
with Infrastructure
with Enclosures
+ with Mirrors
with Names
with Reifiers
with FrontEnds
with Settings
with Typers
+ with Parsers
with Exprs
with TypeTags
+ with Evals
with Util
with Traces {
- val mirror: Global
+ val universe: Global
- val callsiteTyper: mirror.analyzer.Typer
+ val mirror: MirrorOf[universe.type] = new ContextMirror
+
+ val callsiteTyper: universe.analyzer.Typer
val prefix: Expr[PrefixType]
val expandee: Tree
-}
+}
@@ -4,6 +4,7 @@ package runtime
trait Enclosures {
self: Context =>
+ import universe._
import mirror._
private def site = callsiteTyper.context
@@ -16,7 +17,7 @@ trait Enclosures {
val enclosingApplication: Tree = enclTrees collectFirst { case t: Apply => t } getOrElse EmptyTree
val enclosingClass: Tree = site.enclClass.tree
val enclosingImplicits: List[(Type, Tree)] = site.openImplicits
- val enclosingMacros: List[Context] = this :: mirror.analyzer.openMacros // include self
+ val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self
val enclosingMethod: Tree = site.enclMethod.tree
val enclosingPosition: Position = if (enclPoses.isEmpty) NoPosition else enclPoses.head.pos
val enclosingUnit: CompilationUnit = currentRun.currentUnit
@@ -0,0 +1,18 @@
+package scala.reflect.makro
+package runtime
+
+import scala.reflect.runtime.{universe => ru}
+import scala.tools.reflect.ToolBox
+
+trait Evals {
+ self: Context =>
+
+ private lazy val evalMirror = ru.runtimeMirror(libraryClassLoader)
+ private lazy val evalToolBox = evalMirror.mkToolBox()
+ private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }]
+
+ def eval[T](expr: Expr[T]): T = {
+ val imported = evalImporter.importTree(expr.tree)
+ evalToolBox.runExpr(imported).asInstanceOf[T]
+ }
+}
@@ -4,5 +4,5 @@ package runtime
trait Exprs {
self: Context =>
- def Expr[T: TypeTag](tree: Tree): Expr[T] = mirror.Expr[T](mirror.rootMirror, mirror.FixedMirrorTreeCreator(mirror.rootMirror, tree))
+ def Expr[T: TypeTag](tree: Tree): Expr[T] = universe.Expr[T](mirror, universe.FixedMirrorTreeCreator(mirror, tree))
}
@@ -4,31 +4,32 @@ package runtime
trait FrontEnds extends scala.tools.reflect.FrontEnds {
self: Context =>
+ import universe._
import mirror._
- override type Position = mirror.Position
+ override type Position = universe.Position
- def frontEnd: FrontEnd = wrapReporter(mirror.reporter)
+ def frontEnd: FrontEnd = wrapReporter(universe.reporter)
def setFrontEnd(frontEnd: FrontEnd): this.type = {
- mirror.reporter = wrapFrontEnd(frontEnd)
+ universe.reporter = wrapFrontEnd(frontEnd)
this
}
def withFrontEnd[T](frontEnd: FrontEnd)(op: => T): T = {
- val old = mirror.reporter
+ val old = universe.reporter
setFrontEnd(frontEnd)
try op
- finally mirror.reporter = old
+ finally universe.reporter = old
}
- def echo(pos: Position, msg: String): Unit = mirror.reporter.echo(pos, msg)
+ def echo(pos: Position, msg: String): Unit = universe.reporter.echo(pos, msg)
- def info(pos: Position, msg: String, force: Boolean): Unit = mirror.reporter.info(pos, msg, force)
+ def info(pos: Position, msg: String, force: Boolean): Unit = universe.reporter.info(pos, msg, force)
- def hasWarnings: Boolean = mirror.reporter.hasErrors
+ def hasWarnings: Boolean = universe.reporter.hasErrors
- def hasErrors: Boolean = mirror.reporter.hasErrors
+ def hasErrors: Boolean = universe.reporter.hasErrors
def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg)
@@ -39,7 +40,7 @@ trait FrontEnds extends scala.tools.reflect.FrontEnds {
throw new AbortMacroException(pos, msg)
}
- def interactive(): Unit = mirror.reporter match {
+ def interactive(): Unit = universe.reporter match {
case reporter: tools.nsc.reporters.AbstractReporter => reporter.displayPrompt()
case _ => ()
}
@@ -1,34 +1,52 @@
package scala.reflect.makro
package runtime
+import scala.tools.nsc.util.ScalaClassLoader
+
trait Infrastructure {
self: Context =>
- val forJVM: Boolean = mirror.forJVM
+ val forJVM: Boolean = universe.forJVM
+
+ val forMSIL: Boolean = universe.forMSIL
+
+ val forInteractive: Boolean = universe.forInteractive
- val forMSIL: Boolean = mirror.forMSIL
+ val forScaladoc: Boolean = universe.forScaladoc
- val forInteractive: Boolean = mirror.forInteractive
+ val currentRun: Run = universe.currentRun
- val forScaladoc: Boolean = mirror.forScaladoc
+ val libraryClassPath: List[java.net.URL] = universe.classPath.asURLs
- val currentRun: Run = mirror.currentRun
+ lazy val libraryClassLoader: ClassLoader = {
+ val classpath = libraryClassPath
+ var loader: ClassLoader = ScalaClassLoader.fromURLs(classpath, self.getClass.getClassLoader)
+
+ // [Eugene] a heuristic to detect REPL
+ if (universe.settings.exposeEmptyPackage.value) {
+ import scala.tools.nsc.interpreter._
+ val virtualDirectory = universe.settings.outputDirs.getSingleOutput.get
+ loader = new AbstractFileClassLoader(virtualDirectory, loader) {}
+ }
+
+ loader
+ }
- type Run = mirror.Run
+ type Run = universe.Run
object Run extends RunExtractor {
def unapply(run: Run): Option[(CompilationUnit, List[CompilationUnit])] = Some(run.currentUnit, run.units.toList)
}
- type CompilationUnit = mirror.CompilationUnit
+ type CompilationUnit = universe.CompilationUnit
object CompilationUnit extends CompilationUnitExtractor {
def unapply(compilationUnit: CompilationUnit): Option[(java.io.File, Array[Char], Tree)] = Some(compilationUnit.source.file.file, compilationUnit.source.content, compilationUnit.body)
}
val currentMacro: Symbol = expandee.symbol
- val globalCache: collection.mutable.Map[Any, Any] = mirror.analyzer.globalMacroCache
+ val globalCache: collection.mutable.Map[Any, Any] = universe.analyzer.globalMacroCache
- val cache: collection.mutable.Map[Any, Any] = mirror.analyzer.perRunMacroCache.getOrElseUpdate(currentMacro, collection.mutable.Map[Any, Any]())
+ val cache: collection.mutable.Map[Any, Any] = universe.analyzer.perRunMacroCache.getOrElseUpdate(currentMacro, collection.mutable.Map[Any, Any]())
}
@@ -0,0 +1,40 @@
+package scala.reflect.makro
+package runtime
+
+import scala.tools.nsc.util.ScalaClassLoader
+
+trait Mirrors {
+ self: Context =>
+
+ import universe._
+ import definitions._
+
+ class ContextMirror extends RootsBase(NoSymbol) {
+ val universe: self.universe.type = self.universe
+ def rootLoader: LazyType = rootMirror.rootLoader
+
+ val RootPackage = rootMirror.RootPackage
+ val RootClass = rootMirror.RootClass
+ val EmptyPackage = rootMirror.EmptyPackage
+ val EmptyPackageClass = rootMirror.EmptyPackageClass
+
+ // [Eugene++] this still doesn't solve the problem of invoking `c.typeCheck` on the code that refers to packageless symbols
+ override protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = {
+ if (owner.isRoot && isJavaClass(name.toString)) EmptyPackageClass.info decl name
+ else NoSymbol
+ }
+
+ private def isJavaClass(path: String): Boolean =
+ try {
+ val classpath = platform.classPath.asURLs
+ var classLoader = ScalaClassLoader.fromURLs(classpath)
+ Class.forName(path, true, classLoader)
+ true
+ } catch {
+ case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
+ false
+ }
+
+ override def toString = "macro context mirror"
+ }
+}
@@ -14,7 +14,7 @@ trait Names {
freshNameCreator.newName(name)
}
- def fresh(name: Name): Name = {
- name.mapName(freshNameCreator.newName(_))
+ def fresh[NameType <: Name](name: NameType): NameType = {
+ name.mapName(freshNameCreator.newName(_)).asInstanceOf[NameType]
}
}
@@ -0,0 +1,25 @@
+package scala.reflect.makro
+package runtime
+
+import language.existentials
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.ToolBoxError
+
+trait Parsers {
+ self: Context =>
+
+ def parse(code: String): Tree =
+ // todo. provide decent implementation
+ try {
+ import scala.reflect.runtime.{universe => ru}
+ val parsed = ru.rootMirror.mkToolBox().parseExpr(code)
+ val importer = universe.mkImporter(ru)
+ importer.importTree(parsed)
+ } catch {
+ case ToolBoxError(msg, cause) =>
+ throw new ParseError(universe.NoPosition, msg)
+ }
+
+ case class ParseError(val pos: Position, val msg: String) extends Throwable(msg)
+ object ParseError extends ParseErrorExtractor
+}
@@ -9,19 +9,19 @@ package runtime
trait Reifiers {
self: Context =>
- import mirror._
+ import universe._
import definitions._
lazy val reflectMirrorPrefix: Tree = ???
def reifyTree(prefix: Tree, tree: Tree): Tree =
- scala.reflect.reify.`package`.reifyTree(mirror)(callsiteTyper, prefix, tree)
+ scala.reflect.reify.`package`.reifyTree(universe)(callsiteTyper, prefix, tree)
def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Tree =
- scala.reflect.reify.`package`.reifyType(mirror)(callsiteTyper, prefix, tpe, dontSpliceAtTopLevel, concrete)
+ scala.reflect.reify.`package`.reifyType(universe)(callsiteTyper, prefix, tpe, dontSpliceAtTopLevel, concrete)
def reifyRuntimeClass(tpe: Type, concrete: Boolean = true): Tree =
- scala.reflect.reify.`package`.reifyRuntimeClass(mirror)(callsiteTyper, tpe, concrete)
+ scala.reflect.reify.`package`.reifyRuntimeClass(universe)(callsiteTyper, tpe, concrete)
def unreifyTree(tree: Tree): Tree =
Select(tree, definitions.ExprSplice)
@@ -5,12 +5,12 @@ trait Settings {
self: Context =>
def settings: List[String] = {
- val optionName = mirror.settings.XmacroSettings.name
+ val optionName = universe.settings.XmacroSettings.name
val settings = compilerSettings.find(opt => opt.startsWith(optionName)).map(opt => opt.substring(optionName.length + 1)).getOrElse("")
settings.split(",").toList
}
- def compilerSettings: List[String] = mirror.settings.recreateArgs
+ def compilerSettings: List[String] = universe.settings.recreateArgs
def setCompilerSettings(options: String): this.type =
// todo. is not going to work with quoted arguments with embedded whitespaces
@@ -19,7 +19,7 @@ trait Settings {
def setCompilerSettings(options: List[String]): this.type = {
val settings = new tools.nsc.Settings(_ => ())
// [Eugene] what settings should we exclude?
- settings.copyInto(mirror.settings)
+ settings.copyInto(universe.settings)
this
}
@@ -4,5 +4,5 @@ package runtime
trait Traces extends util.Traces {
self: Context =>
- def globalSettings = mirror.settings
+ def globalSettings = universe.settings
}
@@ -4,6 +4,6 @@ package runtime
trait TypeTags {
self: Context =>
- def TypeTag[T](tpe: Type): TypeTag[T] = mirror.TypeTag[T](mirror.rootMirror, mirror.FixedMirrorTypeCreator(mirror.rootMirror, tpe))
- def ConcreteTypeTag[T](tpe: Type): ConcreteTypeTag[T] = mirror.ConcreteTypeTag[T](mirror.rootMirror, mirror.FixedMirrorTypeCreator(mirror.rootMirror, tpe))
+ def TypeTag[T](tpe: Type): TypeTag[T] = universe.TypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe))
+ def ConcreteTypeTag[T](tpe: Type): ConcreteTypeTag[T] = universe.ConcreteTypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe))
}
Oops, something went wrong.

0 comments on commit ce67870

Please sign in to comment.