diff --git a/compiler/src/dotty/tools/dotc/tasty/TastyImpl.scala b/compiler/src/dotty/tools/dotc/tasty/TastyImpl.scala index 5b52b37ab2cd..db74e2d077bf 100644 --- a/compiler/src/dotty/tools/dotc/tasty/TastyImpl.scala +++ b/compiler/src/dotty/tools/dotc/tasty/TastyImpl.scala @@ -11,6 +11,7 @@ import dotty.tools.dotc.util.SourcePosition import scala.quoted import scala.reflect.ClassTag +import scala.tasty.util.{Show, ShowExtractors} object TastyImpl extends scala.tasty.Tasty { @@ -24,6 +25,15 @@ object TastyImpl extends scala.tasty.Tasty { def toTasty(implicit ctx: Context): TypeTree = PickledQuotes.quotedTypeToTree(x) } + // ===== Show ===================================================== + + def defaultShow: Show[this.type] = showExtractors + + def showExtractors: Show[this.type] = new ShowExtractors(this) + + // TODO + // def showSourceCode: Show[this.type] = ??? + // ===== Contexts ================================================= type Context = Contexts.Context @@ -53,8 +63,9 @@ object TastyImpl extends scala.tasty.Tasty { type Tree = tpd.Tree - def TreeDeco(t: Tree): AbstractTree = new AbstractTree { - def pos(implicit ctx: Context): Position = t.pos + def TreeDeco(tree: Tree): AbstractTree = new AbstractTree { + def show(implicit ctx: Context, s: Show[TastyImpl.this.type]): String = s.showTree(tree) + def pos(implicit ctx: Context): Position = tree.pos } type PackageClause = tpd.PackageDef @@ -449,8 +460,9 @@ object TastyImpl extends scala.tasty.Tasty { type TypeOrBoundsTree = tpd.Tree - def TypeOrBoundsTreeDeco(x: TypeOrBoundsTree): AbstractTypeOrBoundsTree = new AbstractTypeOrBoundsTree { - def tpe(implicit ctx: Context): Type = x.tpe.stripTypeVar + def TypeOrBoundsTreeDeco(tpt: TypeOrBoundsTree): AbstractTypeOrBoundsTree = new AbstractTypeOrBoundsTree { + def show(implicit ctx: Context, s: Show[TastyImpl.this.type]): String = s.showTypeOrBoundsTree(tpt) + def tpe(implicit ctx: Context): Type = tpt.tpe.stripTypeVar } // ----- TypeTrees ------------------------------------------------ @@ -559,6 +571,10 @@ object TastyImpl extends scala.tasty.Tasty { type TypeOrBounds = Types.Type + def TypeOrBoundsDeco(tpe: Types.Type): AbstractTypeOrBounds = new AbstractTypeOrBounds { + def show(implicit ctx: Context, s: Show[TastyImpl.this.type]): String = s.showTypeOrBounds(tpe) + } + // ----- Types ---------------------------------------------------- type Type = Types.Type @@ -756,8 +772,9 @@ object TastyImpl extends scala.tasty.Tasty { type Constant = Constants.Constant - def ConstantDeco(x: Constant): AbstractConstant = new AbstractConstant { - def value: Any = x.value + def ConstantDeco(const: Constant): AbstractConstant = new AbstractConstant { + def show(implicit ctx: Context, s: Show[TastyImpl.this.type]): String = s.showConstant(const) + def value: Any = const.value } def constantClassTag: ClassTag[Constant] = implicitly[ClassTag[Constant]] diff --git a/library/src/scala/tasty/Tasty.scala b/library/src/scala/tasty/Tasty.scala index b08c275533c8..43f379e69c0c 100644 --- a/library/src/scala/tasty/Tasty.scala +++ b/library/src/scala/tasty/Tasty.scala @@ -1,8 +1,9 @@ package scala.tasty import scala.reflect.ClassTag +import scala.tasty.util.Show -abstract class Tasty { +abstract class Tasty { tasty => // ===== Quotes =================================================== @@ -16,6 +17,15 @@ abstract class Tasty { } implicit def QuotedTypeDeco[T](x: quoted.Type[T]): AbstractQuotedType + // ===== Show ===================================================== + + implicit def defaultShow: Show[tasty.type] + + def showExtractors: Show[tasty.type] + + // TODO + // def showSourceCode: Show[tasty.type] + // ===== Contexts ================================================= type Context @@ -23,7 +33,7 @@ abstract class Tasty { trait AbstractContext { def owner: Definition } - implicit def ContextDeco(x: Context): AbstractContext + implicit def ContextDeco(ctx: Context): AbstractContext // ===== Id ======================================================= @@ -43,8 +53,10 @@ abstract class Tasty { type Tree - trait AbstractTree extends Positioned - implicit def TreeDeco(t: Tree): AbstractTree + trait AbstractTree extends Positioned { + def show(implicit ctx: Context, s: Show[tasty.type]): String + } + implicit def TreeDeco(tree: Tree): AbstractTree type PackageClause <: Tree @@ -335,9 +347,10 @@ abstract class Tasty { type TypeOrBoundsTree trait AbstractTypeOrBoundsTree { + def show(implicit ctx: Context, s: Show[tasty.type]): String def tpe(implicit ctx: Context): TypeOrBounds } - implicit def TypeOrBoundsTreeDeco(x: TypeOrBoundsTree): AbstractTypeOrBoundsTree + implicit def TypeOrBoundsTreeDeco(tpt: TypeOrBoundsTree): AbstractTypeOrBoundsTree // ----- TypeTrees ------------------------------------------------ @@ -430,6 +443,11 @@ abstract class Tasty { def tpe(implicit ctx: Context): Type } + trait AbstractTypeOrBounds { + def show(implicit ctx: Context, s: Show[tasty.type]): String + } + implicit def TypeOrBoundsDeco(tpe: TypeOrBounds): AbstractTypeOrBounds + // ----- Types ---------------------------------------------------- type Type <: TypeOrBounds @@ -576,9 +594,10 @@ abstract class Tasty { type Constant trait AbstractConstant { + def show(implicit ctx: Context, s: Show[tasty.type]): String def value: Any } - implicit def ConstantDeco(x: Constant): AbstractConstant + implicit def ConstantDeco(const: Constant): AbstractConstant implicit def constantClassTag: ClassTag[Constant] diff --git a/library/src/scala/tasty/Universe.scala b/library/src/scala/tasty/Universe.scala index 3f2f4fa678f4..cfe11e8949a2 100644 --- a/library/src/scala/tasty/Universe.scala +++ b/library/src/scala/tasty/Universe.scala @@ -1,7 +1,7 @@ package scala.tasty trait Universe { - implicit val tasty: Tasty + val tasty: Tasty implicit val context: tasty.Context } diff --git a/library/src/scala/tasty/util/Show.scala b/library/src/scala/tasty/util/Show.scala new file mode 100644 index 000000000000..80c9444ca673 --- /dev/null +++ b/library/src/scala/tasty/util/Show.scala @@ -0,0 +1,15 @@ +package scala.tasty.util + +import scala.tasty.Tasty + +abstract class Show[T <: Tasty with Singleton](val tasty: T) { + + def showTree(tree: tasty.Tree)(implicit ctx: tasty.Context): String + + def showTypeOrBoundsTree(tpt: tasty.TypeOrBoundsTree)(implicit ctx: tasty.Context): String + + def showTypeOrBounds(tpe: tasty.TypeOrBounds)(implicit ctx: tasty.Context): String + + def showConstant(const: tasty.Constant)(implicit ctx: tasty.Context): String + +} diff --git a/library/src/scala/tasty/util/TastyPrinter.scala b/library/src/scala/tasty/util/ShowExtractors.scala similarity index 95% rename from library/src/scala/tasty/util/TastyPrinter.scala rename to library/src/scala/tasty/util/ShowExtractors.scala index a8191369a9a3..078915c407bd 100644 --- a/library/src/scala/tasty/util/TastyPrinter.scala +++ b/library/src/scala/tasty/util/ShowExtractors.scala @@ -2,22 +2,19 @@ package scala.tasty.util import scala.tasty.Tasty -class TastyPrinter[T <: Tasty with Singleton](val tasty: T) { +class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty0) { import tasty._ - def stringOfTree(tree: Tree)(implicit ctx: Context): String = + def showTree(tree: Tree)(implicit ctx: Context): String = new Buffer().visitTree(tree).result() - def stringOfTypeTree(tree: TypeOrBoundsTree)(implicit ctx: Context): String = - new Buffer().visitTypeTree(tree).result() + def showTypeOrBoundsTree(tpt: TypeOrBoundsTree)(implicit ctx: Context): String = + new Buffer().visitTypeTree(tpt).result() - def stringOfType(tpe: TypeOrBounds)(implicit ctx: Context): String = + def showTypeOrBounds(tpe: TypeOrBounds)(implicit ctx: Context): String = new Buffer().visitType(tpe).result() - def stringOfModifier(mod: Modifier)(implicit ctx: Context): String = - new Buffer().visitModifier(mod).result() - - def stringOfConstant(const: Constant)(implicit ctx: Context): String = + def showConstant(const: Constant)(implicit ctx: Context): String = new Buffer().visitConstant(const).result() private class Buffer(implicit ctx: Context) { self => diff --git a/tests/run/tasty-custom-show.check b/tests/run/tasty-custom-show.check new file mode 100644 index 000000000000..0ac30a92df02 --- /dev/null +++ b/tests/run/tasty-custom-show.check @@ -0,0 +1,27 @@ +foo +Tree + +bar +Tree + +bar2 +Tree + +foo2 +Tree + +baz +Tree + +baz2 +Tree + + +Tree + +b +Tree + +b2 +Tree + diff --git a/tests/run/tasty-custom-show/quoted_1.scala b/tests/run/tasty-custom-show/quoted_1.scala new file mode 100644 index 000000000000..40afd0fd950b --- /dev/null +++ b/tests/run/tasty-custom-show/quoted_1.scala @@ -0,0 +1,54 @@ +import scala.quoted._ +import dotty.tools.dotc.quoted.Toolbox._ + +import scala.tasty.Universe +import scala.tasty.Tasty +import scala.tasty.util.{TreeTraverser, Show} + +object Macros { + + implicit inline def printOwners[T](x: => T): Unit = + ~impl('(x))(Universe.compilationUniverse) // FIXME infer Universe.compilationUniverse within top level ~ + + def impl[T](x: Expr[T])(implicit u: Universe): Expr[Unit] = { + import u._ + import u.tasty._ + + + val buff = new StringBuilder + + val output = new TreeTraverser(u.tasty) { + override def traverseTree(tree: Tree)(implicit ctx: Context): Unit = { + // Use custom Show[_] here + implicit val printer = new DummyShow(tasty) + tree match { + case tree @ DefDef(name, _, _, _, _) => + buff.append(name) + buff.append("\n") + buff.append(tree.owner.show) + buff.append("\n\n") + case tree @ ValDef(name, _, _) => + buff.append(name) + buff.append("\n") + buff.append(tree.owner.show) + buff.append("\n\n") + case _ => + } + traverseTreeChildren(tree) + } + } + + val tree = x.toTasty + output.traverseTree(tree) + '(print(~buff.result().toExpr)) + } + +} + +class DummyShow[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty0) { + import tasty._ + def showTree(tree: Tree)(implicit ctx: Context): String = "Tree" + def showTypeOrBoundsTree(tpt: TypeOrBoundsTree)(implicit ctx: Context): String = "TypeOrBoundsTree" + def showTypeOrBounds(tpe: TypeOrBounds)(implicit ctx: Context): String = "TypeOrBounds" + def showConstant(const: Constant)(implicit ctx: Context): String = "Constant" +} diff --git a/tests/run/tasty-custom-show/quoted_2.scala b/tests/run/tasty-custom-show/quoted_2.scala new file mode 100644 index 000000000000..cc13d81ae03b --- /dev/null +++ b/tests/run/tasty-custom-show/quoted_2.scala @@ -0,0 +1,24 @@ + +import Macros._ + +object Test { + def main(args: Array[String]): Unit = { + printOwners { + def foo = { + def bar = 1 + val bar2 = 2 + bar + } + val foo2 = { + def baz = 3 + val baz2 = 4 + baz + } + class A { + type B = Int + def b = 5 + val b2 = 6 + } + } + } +} diff --git a/tests/run/tasty-eval/quoted_1.scala b/tests/run/tasty-eval/quoted_1.scala index 11617ff8761d..0e2a0a67a605 100644 --- a/tests/run/tasty-eval/quoted_1.scala +++ b/tests/run/tasty-eval/quoted_1.scala @@ -1,7 +1,7 @@ import scala.quoted._ import scala.tasty.Universe -import scala.tasty.util.{TastyPrinter, TreeTraverser} +import scala.tasty.util.TreeTraverser object Macros { diff --git a/tests/run/tasty-extractors-1/quoted_1.scala b/tests/run/tasty-extractors-1/quoted_1.scala index c1055a1dcabe..684efab6bd47 100644 --- a/tests/run/tasty-extractors-1/quoted_1.scala +++ b/tests/run/tasty-extractors-1/quoted_1.scala @@ -2,7 +2,6 @@ import scala.quoted._ import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.Universe -import scala.tasty.util.TastyPrinter object Macros { @@ -13,9 +12,8 @@ object Macros { import u._ import tasty._ val tree = x.toTasty - val printer = new TastyPrinter(tasty) - val treeStr = printer.stringOfTree(tree) - val treeTpeStr = printer.stringOfType(tree.tpe) + val treeStr = tree.show + val treeTpeStr = tree.tpe.show '{ println(~treeStr.toExpr) diff --git a/tests/run/tasty-extractors-2/quoted_1.scala b/tests/run/tasty-extractors-2/quoted_1.scala index c1055a1dcabe..d5625758522d 100644 --- a/tests/run/tasty-extractors-2/quoted_1.scala +++ b/tests/run/tasty-extractors-2/quoted_1.scala @@ -2,7 +2,6 @@ import scala.quoted._ import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.Universe -import scala.tasty.util.TastyPrinter object Macros { @@ -13,9 +12,9 @@ object Macros { import u._ import tasty._ val tree = x.toTasty - val printer = new TastyPrinter(tasty) - val treeStr = printer.stringOfTree(tree) - val treeTpeStr = printer.stringOfType(tree.tpe) + + val treeStr = tree.show + val treeTpeStr = tree.tpe.show '{ println(~treeStr.toExpr) diff --git a/tests/run/tasty-extractors-3/quoted_1.scala b/tests/run/tasty-extractors-3/quoted_1.scala index 7a3b00f08b71..6e561d799eb6 100644 --- a/tests/run/tasty-extractors-3/quoted_1.scala +++ b/tests/run/tasty-extractors-3/quoted_1.scala @@ -2,7 +2,7 @@ import scala.quoted._ import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.Universe -import scala.tasty.util.{TastyPrinter, TreeTraverser} +import scala.tasty.util.TreeTraverser object Macros { @@ -13,12 +13,10 @@ object Macros { import u._ import u.tasty._ - val printer = new TastyPrinter(tasty) - val buff = new StringBuilder val traverser = new TreeTraverser(u.tasty) { override def traverseTypeTree(tree: TypeOrBoundsTree)(implicit ctx: Context): Unit = { - buff.append(printer.stringOfType(tree.tpe)) + buff.append(tree.tpe.show) buff.append("\n\n") traverseTypeTreeChildren(tree) } diff --git a/tests/run/tasty-extractors-owners/quoted_1.scala b/tests/run/tasty-extractors-owners/quoted_1.scala index 10d2260401c8..7ebf3e7e45eb 100644 --- a/tests/run/tasty-extractors-owners/quoted_1.scala +++ b/tests/run/tasty-extractors-owners/quoted_1.scala @@ -3,7 +3,7 @@ import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.Universe import scala.tasty.Tasty -import scala.tasty.util.{TastyPrinter, TreeTraverser} +import scala.tasty.util.TreeTraverser object Macros { @@ -13,23 +13,21 @@ object Macros { def impl[T](x: Expr[T])(implicit u: Universe): Expr[Unit] = { import u._ import u.tasty._ - val printer = new TastyPrinter(tasty) val buff = new StringBuilder val output = new TreeTraverser(u.tasty) { - import tasty._ override def traverseTree(tree: Tree)(implicit ctx: Context): Unit = { tree match { case tree @ DefDef(name, _, _, _, _) => buff.append(name) buff.append("\n") - buff.append(printer.stringOfTree(tree.owner)) + buff.append(tree.owner.show) buff.append("\n\n") case tree @ ValDef(name, _, _) => buff.append(name) buff.append("\n") - buff.append(printer.stringOfTree(tree.owner)) + buff.append(tree.owner.show) buff.append("\n\n") case _ => } diff --git a/tests/run/tasty-extractors-types/quoted_1.scala b/tests/run/tasty-extractors-types/quoted_1.scala index 198e6bc7f604..3bca350a60f4 100644 --- a/tests/run/tasty-extractors-types/quoted_1.scala +++ b/tests/run/tasty-extractors-types/quoted_1.scala @@ -2,7 +2,7 @@ import scala.quoted._ import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.Universe -import scala.tasty.util.{TastyPrinter, TreeTraverser} +import scala.tasty.util.TreeTraverser object Macros { @@ -13,10 +13,9 @@ object Macros { import u._ import u.tasty._ val tree = x.toTasty - val printer = new TastyPrinter(tasty) '{ - println(~printer.stringOfTypeTree(tree).toExpr) - println(~printer.stringOfType(tree.tpe).toExpr) + println(~tree.show.toExpr) + println(~tree.tpe.show.toExpr) println() } } diff --git a/tests/run/tasty-indexed-map/quoted_1.scala b/tests/run/tasty-indexed-map/quoted_1.scala index f41cd00bcccf..8bc2bc56adff 100644 --- a/tests/run/tasty-indexed-map/quoted_1.scala +++ b/tests/run/tasty-indexed-map/quoted_1.scala @@ -2,7 +2,6 @@ import scala.quoted._ import scala.tasty.Universe -import scala.tasty.util.TastyPrinter class MyMap[Keys](private val underlying: Array[Int]) extends AnyVal { def get[K <: String](implicit i: Index[K, Keys]): Int = underlying(i.index) diff --git a/tests/run/tasty-macro-assert/quoted_1.scala b/tests/run/tasty-macro-assert/quoted_1.scala index c74f7bc675f7..72684e9a4862 100644 --- a/tests/run/tasty-macro-assert/quoted_1.scala +++ b/tests/run/tasty-macro-assert/quoted_1.scala @@ -2,7 +2,6 @@ import scala.quoted._ import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.Universe -import scala.tasty.util.TastyPrinter object Asserts { @@ -38,9 +37,8 @@ object Asserts { tree match { case Term.Apply(Term.Select(OpsTree(left), op, _), right :: Nil) => // FIXME splice the threes directly - val printer = new TastyPrinter(tasty) - val lExpr = printer.stringOfTree(left).toExpr - val rExpr = printer.stringOfTree(right).toExpr + val lExpr = left.show.toExpr + val rExpr = right.show.toExpr op match { case "===" => '(assertEquals(~lExpr, ~rExpr)) case "!==" => '(assertNotEquals(~lExpr, ~rExpr))