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/dotc/core/PluggableTransformers.scala | |
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/dotc/core/PluggableTransformers.scala')
-rw-r--r-- | src/dotty/tools/dotc/core/PluggableTransformers.scala | 102 |
1 files changed, 102 insertions, 0 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 |