diff options
author | Martin Odersky <odersky@gmail.com> | 2013-02-19 16:23:44 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-02-19 16:23:44 +0100 |
commit | 51f7cf3cc33fc357881c0e413eb55b9253e2c22d (patch) | |
tree | be6ca9b7d376889ca981c092c924c0459063e8f7 /src/dotty/tools | |
parent | b72ee12e9eeffe32ffd752c5aaf9ef1713d77286 (diff) | |
download | dotty-51f7cf3cc33fc357881c0e413eb55b9253e2c22d.tar.gz dotty-51f7cf3cc33fc357881c0e413eb55b9253e2c22d.tar.bz2 dotty-51f7cf3cc33fc357881c0e413eb55b9253e2c22d.zip |
Feasibility study for transformer plugins
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/core/PluggableTransformers.scala | 102 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Trees.scala | 17 |
2 files changed, 114 insertions, 5 deletions
diff --git a/src/dotty/tools/dotc/core/PluggableTransformers.scala b/src/dotty/tools/dotc/core/PluggableTransformers.scala new file mode 100644 index 000000000..b0b2ca134 --- /dev/null +++ b/src/dotty/tools/dotc/core/PluggableTransformers.scala @@ -0,0 +1,102 @@ +package dotty.tools.dotc +package core + + +object PluggableTransformers { + + import Trees._, Contexts._ + + abstract class PluggableTransformer[T] extends TreeTransformer[T, Context] { + type PluginOp[-N <: Tree[T]] = N => Tree[T] + + private[this] var _ctx: Context = _ + private[this] var _oldTree: Tree[T] = _ + + protected implicit def ctx: Context = _ctx + protected def oldTree: Tree[T] = _oldTree + protected def thisTransformer: PluggableTransformer[T] = this + + class PluginOps[-N <: Tree[T]](op: PluginOp[N], val next: Plugins) { + def apply(tree: N, old: Tree[T], c: Context): Tree[T] = { + val savedCtx = _ctx + val savedOld = _oldTree + try { + op(tree) + } finally { + _oldTree = savedOld + _ctx = savedCtx + } + } + } + + val NoOp: PluginOp[Tree[T]] = identity + val NoOps = new PluginOps(NoOp, null) + + class Plugins { + def next: Plugins = null + + def processIdent: PluginOp[Ident[T]] = NoOp + def processSelect: PluginOp[Select[T]] = NoOp + + val IdentOps: PluginOps[Ident[T]] = NoOps + val SelectOps: PluginOps[Select[T]] = NoOps + } + + val EmptyPlugin = new Plugins + + private[this] var _plugins: Plugins = EmptyPlugin + + override def plugins: Plugins = _plugins + + class Plugin extends Plugins { + override val next = _plugins + _plugins = this + + private def push[N <: Tree[T]](op: PluginOp[N], ops: => PluginOps[N]): PluginOps[N] = + if (op == NoOp) ops else new PluginOps(op, next) + + override val IdentOps: PluginOps[Ident[T]] = push(processIdent, next.IdentOps) + override val SelectOps: PluginOps[Select[T]] = push(processSelect, next.SelectOps) + } + + def postIdent(tree: Ident[T], old: Tree[T], c: Context, ops: PluginOps[Ident[T]]) = + if (ops eq NoOps) tree + else finishIdent(ops(tree, old, c), old, c, ops.next) + + override def finishIdent(tree: Tree[T], old: Tree[T], c: Context, plugins: Plugins): Tree[T] = tree match { + case tree: Ident[_] => postIdent(tree, old, c, plugins.IdentOps) + case _ => postProcess(tree, old, c, plugins) + } + + def postSelect(tree: Select[T], old: Tree[T], c: Context, ops: PluginOps[Select[T]]) = + if (ops eq NoOps) tree + else finishSelect(ops(tree, old, c), old, c, ops.next) + + override def finishSelect(tree: Tree[T], old: Tree[T], c: Context, plugins: Plugins): Tree[T] = tree match { + case tree: Select[_] => postSelect(tree, old, c, plugins.SelectOps) + case _ => postProcess(tree, old, c, plugins) + } + + protected def postProcess(tree: Tree[T], old: Tree[T], c: Context, plugins: Plugins): Tree[T] = tree match { + case tree: Ident[_] => finishIdent(tree, old, c, plugins) + case tree: Select[_] => finishSelect(tree, old, c, plugins) + } + } +} + +import PluggableTransformers._, Types._, TypedTrees._ + +class ExampleTransformer extends PluggableTransformer[Type] { + + class ExamplePlugin extends Plugin { + override def processIdent = { + case tree @ Ident(x) if x.isTypeName => tree.derivedSelect(tree, x) + case tree => tree + } + override def processSelect = { tree => + if (tree.isType) tree.derivedIdent(tree.name) + else EmptyTree + } + } + +}
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala index 315e5e221..7d48641ee 100644 --- a/src/dotty/tools/dotc/core/Trees.scala +++ b/src/dotty/tools/dotc/core/Trees.scala @@ -66,7 +66,7 @@ object Trees { val tree = (if (_tpe == null || (_tpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this - else clone).asInstanceOf[TypedTree] + else clone).asInstanceOf[Tree[Type]] tree._tpe = tpe tree.asInstanceOf[ThisTree[Type]] } @@ -501,7 +501,10 @@ object Trees { def apply[T]: EmptyValDef[T] = theEmptyValDef.asInstanceOf } - /** A tree that can be shared without its position polluting containing trees */ + /** A tree that can be shared without its position + * polluting containing trees. Accumulators and tranformers + * memoize results of shared subtrees + */ case class Shared[T](shared: Tree[T]) extends Tree[T] { type ThisTree[T] = Shared[T] val pos = NoPosition @@ -697,11 +700,15 @@ object Trees { abstract class TreeTransformer[T, C] { var sharedMemo: Map[Shared[T], Shared[T]] = Map() + type Plugins >: Null + def plugins: Plugins = null + def finishIdent(tree: Tree[T], old: Tree[T], c: C, plugins: Plugins) = tree + def finishSelect(tree: Tree[T], old: Tree[T], c: C, plugins: Plugins) = tree def transform(tree: Tree[T], c: C): Tree[T] = tree match { case Ident(name) => - tree + finishIdent(tree, tree, c, plugins) case Select(qualifier, name) => - tree.derivedSelect(transform(qualifier, c), name) + finishSelect(tree.derivedSelect(transform(qualifier, c), name), tree, c, plugins) case This(qual) => tree case Super(qual, mix) => @@ -797,7 +804,7 @@ object Trees { (trees mapConserve (transformSub(_, c))).asInstanceOf[List[TT]] } - abstract class TreeAccumulator[T, U] extends ((T, Tree[U]) => T) { + abstract class TreeAccumulator[T, U] extends ((T, Tree[U]) => T) { var sharedMemo: Map[Shared[U], T] = Map() def apply(x: T, tree: Tree[U]): T def apply(x: T, trees: List[Tree[U]]): T = (x /: trees)(apply) |