I am sure there is a more elegant way of writing the following macro which prints the name and value of a variable:
def mprintx(c: Context)(linecode: c.Expr[Any]): c.Expr[Unit] = {
import c.universe._
val namez = (c.enclosingImpl match {
case ClassDef(mods, name, tparams, impl) =>
c.universe.reify(c.literal(name.toString).splice)
case ModuleDef(mods, name, impl) =>
c.universe.reify(c.literal(name.toString).splice)
case _ => c.abort(c.enclosingPosition, "NoEnclosingClass")
}).toString match {
case r_name(n) => n
case _ => "Unknown?"
}
val msg = linecode.tree.productIterator.toList.last.toString.replaceAll("scala.*\\]", "").replaceAll(namez+"\\.this\\.", "").replaceAll("List", "")
reify(myPrintDln(c.Expr[String](Literal(Constant(msg))).splice+" ---> "+linecode.splice))
}
def myPrintIt(linecode: Any) = macro mprintx
called by the following program:
object Zabi2 extends App {
val l = "zab"
val kol = 345
var zub = List("2", 89)
val zubi = List(zub,l,kol)
printIt(l)
printIt(l, kol, (l, zub),zubi)
}
which prints:
l ---> zab
(l, kol, (l, zub), zubi) ---> (zab,345,(zab,List(2, 89)),List(List(2, 89), zab, 345))
Thanks in advance for your help.
Here is a macro to print expressions and their values:
package mymacro
import scala.annotation.compileTimeOnly
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
@compileTimeOnly("DebugPrint is available only during compile-time")
class DebugPrint(val c: whitebox.Context) {
import c.universe._
def impl(args: c.Expr[Any]*): c.Tree = {
val sep = ", "
val colon = "="
val trees = args.map(expr => expr.tree).toList
val ctxInfo = s"${c.internal.enclosingOwner.fullName}:${c.enclosingPosition.line}: "
val treeLits = trees.zipWithIndex.map {
case (tree, i) => Literal(Constant((if (i != 0) sep else ctxInfo) + tree + colon))
}
q"""
System.err.println(StringContext(..$treeLits, "").s(..$trees))
"""
}
}
@compileTimeOnly("DebugPrint is available only during compile-time")
object DebugPrint {
def apply(args: Any*): Any = macro DebugPrint.impl
}
Example:
package myapp
import mymacro.DebugPrint
case class Person(name: String, age: Int)
object Main extends App {
val x = 5
val y = "example"
val person = Person("Derp", 20)
DebugPrint(x, y, person, person.name, person.age)
def func() = {
val x = 5
val y = "example"
val person = Person("Derp", 20)
DebugPrint(x, y, person, person.name, person.age)
}
func()
}
Output:
myapp.Main.<local Main>:12: Main.this.x=5, Main.this.y=example, Main.this.person=Person(Derp,20), Main.this.person.name=Derp, Main.this.person.age=20
myapp.Main.func:18: x=5, y=example, person=Person(Derp,20), person.name=Derp, person.age=20
Works well with scala 2.12.12.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With