summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-02-01 00:13:53 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 23:51:24 +0100
commit8c29132055845181a34ed9077d30fac87c284574 (patch)
tree29c5bb2ca8be67e324ee3e0f9d78bc62bf00d8b3
parent73adf2d9de441e151a117a5b33ae707ad79a9f36 (diff)
downloadscala-8c29132055845181a34ed9077d30fac87c284574.tar.gz
scala-8c29132055845181a34ed9077d30fac87c284574.tar.bz2
scala-8c29132055845181a34ed9077d30fac87c284574.zip
adds internal.typingTransform
As per Jason’s request, this commit introduces a facility to perform tree transformations that know how to track current lexical context and how to typecheck trees in that lexical context. Interestingly enough, we can’t get away with the traditional “subclass the Transformer” approach, because the required base transformer class is declared in scala-compiler.jar, and our API is defined in scala-reflect.jar. This forced me to play with an idea that we’ve discussed with Denys today (actually, it’s already yesterday) - lightweight transformers that take contextful HOFs. This commit is a sketch in that direction. Turning `transform` and `typingTransform` into macros would make the API more elegant (see the comments), but I didn’t have time to experiment. I’m running short on time, so I haven’t had a chance to actually test this API, but I’m still submitting the pull request to ignite a discussion.
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Internals.scala32
-rw-r--r--src/reflect/scala/reflect/macros/Internals.scala47
2 files changed, 78 insertions, 1 deletions
diff --git a/src/compiler/scala/reflect/macros/contexts/Internals.scala b/src/compiler/scala/reflect/macros/contexts/Internals.scala
index e0f7824cf3..e35a8ae034 100644
--- a/src/compiler/scala/reflect/macros/contexts/Internals.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Internals.scala
@@ -1,9 +1,39 @@
package scala.reflect.macros
package contexts
-trait Internals {
+trait Internals extends scala.tools.nsc.transform.TypingTransformers {
self: Context =>
+ import global._
+
lazy val internal: ContextInternalApi = new global.SymbolTableInternal with ContextInternalApi {
+ class HofTransformer(hof: (Tree, TransformApi) => Tree) extends Transformer {
+ val api = new TransformApi {
+ def recur(tree: Tree): Tree = hof(tree, this)
+ def default(tree: Tree): Tree = superTransform(tree)
+ }
+ def superTransform(tree: Tree) = super.transform(tree)
+ override def transform(tree: Tree): Tree = hof(tree, api)
+ }
+
+ def transform(tree: Tree)(transformer: (Tree, TransformApi) => Tree): Tree = new HofTransformer(transformer).transform(tree)
+
+ class HofTypingTransformer(hof: (Tree, TypingTransformApi) => Tree) extends TypingTransformer(callsiteTyper.context.unit) { self =>
+ currentOwner = callsiteTyper.context.owner
+ curTree = EmptyTree
+ localTyper = global.analyzer.newTyper(callsiteTyper.context.make(unit = callsiteTyper.context.unit))
+
+ val api = new TypingTransformApi {
+ def recur(tree: Tree): Tree = hof(tree, this)
+ def default(tree: Tree): Tree = superTransform(tree)
+ def atOwner[T](owner: Symbol)(op: => T): T = self.atOwner(owner)(op)
+ def currentOwner: Symbol = self.currentOwner
+ def typecheck(tree: Tree): Tree = localTyper.typed(tree)
+ }
+ def superTransform(tree: Tree) = super.transform(tree)
+ override def transform(tree: Tree): Tree = hof(tree, api)
+ }
+
+ def typingTransform(tree: Tree)(transformer: (Tree, TypingTransformApi) => Tree): Tree = new HofTypingTransformer(transformer).transform(tree)
}
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/macros/Internals.scala b/src/reflect/scala/reflect/macros/Internals.scala
index f74f120470..415e70c36e 100644
--- a/src/reflect/scala/reflect/macros/Internals.scala
+++ b/src/reflect/scala/reflect/macros/Internals.scala
@@ -14,5 +14,52 @@ trait Internals {
/** @see [[scala.reflect.api.Internals]] */
trait ContextInternalApi extends universe.MacroInternalApi {
+ /** Functions that are available during [[transform]].
+ * @see [[transform]]
+ */
+ trait TransformApi {
+ /** Calls the current transformer on the given tree.
+ * Current transformer = argument to the `transform` call.
+ */
+ def recur(tree: Tree): Tree
+
+ /** Calls the default transformer on the given tree.
+ * Default transformer = recur into tree's children and assemble the results.
+ */
+ def default(tree: Tree): Tree
+ }
+
+ /** Transforms a given tree using the provided function.
+ * @see [[TransformApi]]
+ */
+ // TODO: explore a more concise notation that Denys and I discussed today
+ // when transformer is PartialFunction[Tree, Tree]] and TransformApi is passed magically
+ // also cf. https://github.com/dsl-paradise/dsl-paradise
+ def transform(tree: Tree)(transformer: (Tree, TransformApi) => Tree): Tree
+
+ /** Functions that are available during [[typingTransform]].
+ * @see [[typingTransform]]
+ */
+ trait TypingTransformApi extends TransformApi {
+ /** Temporarily pushes the given symbol onto the owner stack, creating a new local typer,
+ * invoke the given operation and then rollback the changes to the owner stack.
+ */
+ def atOwner[T](owner: Symbol)(op: => T): T
+
+ /** Returns the symbol currently on the top of the owner stack.
+ * If we're not inside any `atOwner` call, then macro application's context owner will be used.
+ */
+ def currentOwner: Symbol
+
+ /** Typechecks the given tree using the local typer currently on the top of the owner stack.
+ * If we're not inside any `atOwner` call, then macro application's callsite typer will be used.
+ */
+ def typecheck(tree: Tree): Tree
+ }
+
+ /** Transforms a given tree using the provided function.
+ * @see [[TypingTransformApi]]
+ */
+ def typingTransform(tree: Tree)(transformer: (Tree, TypingTransformApi) => Tree): Tree
}
}