From ce67870e64afabf75363679bcee597812ad223e9 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 6 Jun 2012 14:29:05 +0200 Subject: 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. --- src/library/scala/reflect/makro/Aliases.scala | 34 ++++++++++------------ src/library/scala/reflect/makro/Context.scala | 9 ++++-- src/library/scala/reflect/makro/Evals.scala | 8 +++++ src/library/scala/reflect/makro/FrontEnds.scala | 2 +- .../scala/reflect/makro/Infrastructure.scala | 29 ++++++++++++++++++ src/library/scala/reflect/makro/Names.scala | 2 +- src/library/scala/reflect/makro/Parsers.scala | 17 +++++++++++ src/library/scala/reflect/makro/Typers.scala | 2 +- src/library/scala/reflect/makro/package.scala | 6 ++++ 9 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 src/library/scala/reflect/makro/Evals.scala create mode 100644 src/library/scala/reflect/makro/Parsers.scala create mode 100644 src/library/scala/reflect/makro/package.scala (limited to 'src/library') diff --git a/src/library/scala/reflect/makro/Aliases.scala b/src/library/scala/reflect/makro/Aliases.scala index d7dd111f22..5e9ebdb263 100644 --- a/src/library/scala/reflect/makro/Aliases.scala +++ b/src/library/scala/reflect/makro/Aliases.scala @@ -3,26 +3,24 @@ package scala.reflect.makro trait Aliases { self: Context => - /** Aliases of mirror types */ - type Symbol = mirror.Symbol - type Type = mirror.Type - type Name = mirror.Name - type Tree = mirror.Tree - // type Position = mirror.Position - type Scope = mirror.Scope - type Modifiers = mirror.Modifiers - type Expr[+T] = mirror.Expr[T] - type TypeTag[T] = mirror.TypeTag[T] - type ConcreteTypeTag[T] = mirror.ConcreteTypeTag[T] + type Symbol = universe.Symbol + type Type = universe.Type + type Name = universe.Name + type TermName = universe.TermName + type TypeName = universe.TypeName + type Tree = universe.Tree + // type Position = universe.Position + type Scope = universe.Scope + type Modifiers = universe.Modifiers - /** Creator/extractor objects for Expr and TypeTag values */ - val TypeTag = mirror.TypeTag - val ConcreteTypeTag = mirror.ConcreteTypeTag - val Expr = mirror.Expr + type Expr[+T] = universe.Expr[T] + val Expr = universe.Expr - /** incantations for summoning tags */ - def tag[T](implicit ttag: TypeTag[T]) = ttag + type TypeTag[T] = universe.TypeTag[T] + type ConcreteTypeTag[T] = universe.ConcreteTypeTag[T] + val TypeTag = universe.TypeTag + val ConcreteTypeTag = universe.ConcreteTypeTag def typeTag[T](implicit ttag: TypeTag[T]) = ttag - def concreteTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag + def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe } diff --git a/src/library/scala/reflect/makro/Context.scala b/src/library/scala/reflect/makro/Context.scala index fb77405d37..58fd0d3df3 100644 --- a/src/library/scala/reflect/makro/Context.scala +++ b/src/library/scala/reflect/makro/Context.scala @@ -15,12 +15,17 @@ trait Context extends Aliases with FrontEnds with Settings with Typers + with Parsers with Exprs with TypeTags + with Evals with Util { - /** The mirror that corresponds to the compile-time universe */ - val mirror: Universe + /** The compile-time universe */ + val universe: Universe + + /** The mirror of the compile-time universe */ + val mirror: MirrorOf[universe.type] /** The type of the prefix tree from which the macro is selected */ type PrefixType diff --git a/src/library/scala/reflect/makro/Evals.scala b/src/library/scala/reflect/makro/Evals.scala new file mode 100644 index 0000000000..e34f74ca1b --- /dev/null +++ b/src/library/scala/reflect/makro/Evals.scala @@ -0,0 +1,8 @@ +package scala.reflect.makro + +trait Evals { + self: Context => + + /** .. */ + def eval[T](expr: Expr[T]): T +} \ No newline at end of file diff --git a/src/library/scala/reflect/makro/FrontEnds.scala b/src/library/scala/reflect/makro/FrontEnds.scala index d76907cdc8..7e47701ffa 100644 --- a/src/library/scala/reflect/makro/FrontEnds.scala +++ b/src/library/scala/reflect/makro/FrontEnds.scala @@ -5,7 +5,7 @@ trait FrontEnds extends scala.reflect.api.FrontEnds { import mirror._ - type Position = mirror.Position + type Position = universe.Position /** Exposes means to control the compiler UI */ def frontEnd: FrontEnd diff --git a/src/library/scala/reflect/makro/Infrastructure.scala b/src/library/scala/reflect/makro/Infrastructure.scala index 2bf49dca77..69394a27ea 100644 --- a/src/library/scala/reflect/makro/Infrastructure.scala +++ b/src/library/scala/reflect/makro/Infrastructure.scala @@ -23,6 +23,35 @@ trait Infrastructure { */ val currentRun: Run + /** Exposes library classpath. + */ + val libraryClassPath: List[java.net.URL] + + /** Exposes a classloader that corresponds to the library classpath. + * + * With this classloader you can perform on-the-fly evaluation of macro arguments. + * For example, consider this code snippet: + * + * def staticEval[T](x: T) = macro staticEval[T] + * + * def staticEval[T: c.TypeTag](c: Context)(x: c.Expr[T]) = { + * import scala.reflect.runtime.{universe => ru} + * val mirror = ru.runtimeMirror(c.libraryClassLoader) + * import scala.tools.reflect.ToolBox + * val toolBox = mirror.mkToolBox() + * 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] + * ... + * } + * + * // [Eugene++] using this guy will tremendously slow down the compilation + * // https://twitter.com/xeno_by/status/201248317831774208 + * // todo. we need to address this somehow + */ + def libraryClassLoader: ClassLoader + /** As seen by macro API, compilation run is an opaque type that can be deconstructed into: * 1) Current compilation unit * 2) List of all compilation units that comprise the run diff --git a/src/library/scala/reflect/makro/Names.scala b/src/library/scala/reflect/makro/Names.scala index 8a823d19cb..c842c48e52 100644 --- a/src/library/scala/reflect/makro/Names.scala +++ b/src/library/scala/reflect/makro/Names.scala @@ -10,5 +10,5 @@ trait Names { def fresh(name: String): String /** Creates a fresh name from the provided name */ - def fresh(name: Name): Name + def fresh[NameType <: Name](name: NameType): NameType } diff --git a/src/library/scala/reflect/makro/Parsers.scala b/src/library/scala/reflect/makro/Parsers.scala new file mode 100644 index 0000000000..737d387434 --- /dev/null +++ b/src/library/scala/reflect/makro/Parsers.scala @@ -0,0 +1,17 @@ +package scala.reflect.makro + +trait Parsers { + self: Context => + + /** .. */ + // todo. distinguish between `parseExpr` and `parse` + def parse(code: String): Tree + + /** Represents an error during parsing + */ + type ParseError <: Throwable + val ParseError: ParseErrorExtractor + abstract class ParseErrorExtractor { + def unapply(error: ParseError): Option[(Position, String)] + } +} \ No newline at end of file diff --git a/src/library/scala/reflect/makro/Typers.scala b/src/library/scala/reflect/makro/Typers.scala index 90024a4f7a..2087309520 100644 --- a/src/library/scala/reflect/makro/Typers.scala +++ b/src/library/scala/reflect/makro/Typers.scala @@ -3,7 +3,7 @@ package scala.reflect.makro trait Typers { self: Context => - import mirror._ + import universe._ /** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only. * Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion. diff --git a/src/library/scala/reflect/makro/package.scala b/src/library/scala/reflect/makro/package.scala new file mode 100644 index 0000000000..3c0e51030e --- /dev/null +++ b/src/library/scala/reflect/makro/package.scala @@ -0,0 +1,6 @@ +package scala.reflect + +package object makro { + + type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U] +} -- cgit v1.2.3