diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-03-04 15:38:53 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-03-06 13:29:57 +0100 |
commit | b97c4613566820b68c8def483690225087020034 (patch) | |
tree | ed5a984558adb82d1b8b8435900b5d7de24242a5 /test/test/transform | |
parent | 092456b806a132a64b7a4a98d0d2d30ca8114bbd (diff) | |
download | dotty-b97c4613566820b68c8def483690225087020034.tar.gz dotty-b97c4613566820b68c8def483690225087020034.tar.bz2 dotty-b97c4613566820b68c8def483690225087020034.zip |
Tree Transformer&TreeTransform:
1) using fast tracks in case node type isn't altered by Transformation;
2) using pre-computed hints(nxTransformXXX arrays) to quickly jump to next transformation interested in transforming particular Tree type;
3) using pre-computed hints(nxPrepareXXX arrays) to know which transformations are going to 'prepare' for transforming particular Tree type;
4) recomputing those hints in case some transformation changed implementation class during 'prepare';
5) TreeTransform is now responsible of calling transformFollowing on nodes created by it.
Diffstat (limited to 'test/test/transform')
-rw-r--r-- | test/test/transform/TreeTransformerTest.scala | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/test/test/transform/TreeTransformerTest.scala b/test/test/transform/TreeTransformerTest.scala new file mode 100644 index 000000000..5d4a6fa06 --- /dev/null +++ b/test/test/transform/TreeTransformerTest.scala @@ -0,0 +1,179 @@ +package test.transform + + +import org.junit.{Assert, Test} +import test.DottyTest +import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer} +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.core.Constants.Constant +import dotty.tools.dotc.core.Contexts.Context + + +class TreeTransformerTest extends DottyTest { + + @Test + def shouldReturnSameTreeIfUnchanged = checkCompile("frontend", "class A{ val d = 1}") { + (tree, context) => + implicit val ctx = context + class EmptyTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {} + val transformer = new TreeTransformer { + override def transformations = Array(new EmptyTransform(_, _)) + + override def name: String = "test" + } + val transformed = transformer.transform(tree) + + Assert.assertTrue("returns same tree if unmodified", + tree eq transformed + ) + } + + @Test + def canReplaceConstant = checkCompile("frontend", "class A{ val d = 1}") { + (tree, context) => + implicit val ctx = context + class ConstantTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) { + + override def transformLiteral(tree: tpd.Literal)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = tpd.Literal(Constant(2)) + } + val transformer = new TreeTransformer { + override def transformations = Array(new ConstantTransform(_, _)) + + override def name: String = "test" + } + val transformed = transformer.transform(tree) + + Assert.assertTrue("returns same tree if unmodified", + transformed.toString.contains("List(ValDef(Modifiers(,,List()),d,TypeTree[TypeRef(ThisType(module class scala),Int)],Literal(Constant(2)))") + ) + } + + @Test + def canOverwrite = checkCompile("frontend", "class A{ val d = 1}") { + (tree, context) => + implicit val ctx = context + class Transformation(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) { + + override def transformLiteral(tree: tpd.Literal)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = tpd.Literal(Constant(-1)) + + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.ValDef = { + Assert.assertTrue("transformation of children succeeded", + tree.rhs.toString == "Literal(Constant(-1))" + ) + tpd.cpy.ValDef(tree, tree.mods, tree.name, tree.tpt, tpd.Literal(Constant(2))) + } + } + val transformer = new TreeTransformer { + override def transformations = Array(new Transformation(_, _)) + + override def name: String = "test" + } + val tr = transformer.transform(tree).toString + + Assert.assertTrue("node can rewrite children", + tr.contains("Literal(Constant(2))") && !tr.contains("Literal(Constant(-1))") + ) + } + + @Test + def transformationOrder = checkCompile("frontend", "class A{ val d = 1}") { + (tree, context) => + implicit val ctx = context + class Transformation1(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) { + + override def transformLiteral(tree: tpd.Literal)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + Assert.assertTrue("correct constant", + tree.const.toString == "Constant(1)" + ) + tpd.cpy.Literal(tree, Constant(-1)) + } + + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.ValDef = { + Assert.assertTrue("transformation of children succeeded", + tree.rhs.toString == "Literal(Constant(-1))" + ) + tpd.cpy.ValDef(tree, tree.mods, tree.name, tree.tpt, tpd.Literal(Constant(2))) + } + } + class Transformation2(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) { + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.ValDef = { + Assert.assertTrue("transformation of children succeeded", + tree.rhs.toString == "Literal(Constant(2))" + ) + tpd.cpy.ValDef(tree, tree.mods, tree.name, tree.tpt, tpd.Literal(Constant(3))) + } + } + val transformer = new TreeTransformer { + override def transformations = Array(new Transformation1(_, _), new Transformation2(_, _)) + + override def name: String = "test" + } + val tr = transformer.transform(tree).toString + + Assert.assertTrue("node can rewrite children", + tr.contains("Literal(Constant(3))") + ) + } + + @Test + def invocationCount = checkCompile("frontend", "class A{ val d = 1}") { + (tree, context) => + implicit val ctx = context + var transformed1 = 0 + class Transformation1(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) { + override def transformLiteral(tree: tpd.Literal)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + transformed1 += 1 + Assert.assertTrue("correct constant", + tree.const.toString == "Constant(1)" + ) + tpd.cpy.Literal(tree, Constant(-1)) + } + + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo) = { + transformed1 += 1 + Assert.assertTrue("transformation of children succeeded", + tree.rhs.toString == "Literal(Constant(-3))" + ) + tpd.cpy.ValDef(tree, tree.mods, tree.name, tree.tpt, transformFollowing(tpd.Literal(Constant(2)))) + } + } + var transformed2 = 0 + class Transformation2(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) { + var constantsSeen = 0 + + override def transformLiteral(tree: tpd.Literal)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + transformed2 += 1 + constantsSeen match { + case 0 => + Assert.assertTrue("correct constant", + tree.const.toString == "Constant(-1)" + ) + case 1 => + Assert.assertTrue("correct constant", + tree.const.toString == "Constant(2)" + ) + case _ => Assert.fail("to many constants seen") + } + constantsSeen += 1 + tpd.cpy.Literal(tree, Constant(-3)) + } + + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo) = { + transformed2 += 1 + Assert.assertTrue("transformation of children succeeded", + tree.rhs.toString == "Literal(Constant(-3))" + ) + transformFollowing(tpd.cpy.ValDef(tree, tree.mods, tree.name, tree.tpt, tpd.Literal(Constant(3)))) + } + } + val transformer = new TreeTransformer { + override def transformations = Array(new Transformation1(_, _), new Transformation2(_, _)) + + override def name: String = "test" + } + val tr = transformer.transform(tree).toString + Assert.assertTrue("transformations aren't invoked multiple times", + transformed1 == 2 && transformed2 == 3 + ) + } +} |