'How to access parent class params literals?

Using Scala 2.x macros, how to access literals passed to parent classes when defining subclasses, typically with ADTs such as the following:

sealed abstract class Base(val s: String, val i: Int)
object Base {
  case object A extends Base("a", 1)
  case object B extends Base("b", 2)
  case class C(override val s: String) extends Base(s, 3)
}

For object A, I would like to know parameter values are literals "a" and 1.
For object B, I would like to know parameter values are literals "b" and 2.
For case class C, I would like to know the second parameter is literal 3.

How can I accomplish this with Scala 2.x macros?



Solution 1:[1]

After much investigation and getting inspiration from bwmcadams / supreme-macro-adventure, it looks like one solution is based on the combination of Macro Paradise and the creation of an @ADT annotation.

Macro paradise provides a mechanism to expand annotations on ADTs to rewrite them, thanks to the macroTransform function.

import scala.annotation.{compileTimeOnly, StaticAnnotation}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

@compileTimeOnly("enable macro paradise to expand macro annotations")
class ADT extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ADT.impl
}

object ADT {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    val trees = annottees.map(_.tree)
    val rewritten = trees match {
      case (cd: ClassDef) :: q"object $name { ..$body }" :: Nil =>
        $body match {
          case q"case object $name extends $_($literal, $_)" :: tail =>
            [...]
        }
      case _ =>
        trees
    }

    c.Expr[Any](q"{..$rewritten}")
  }
}

With the help of quasiquotes, one can navigate $body and pattern match the different cases to access the arguments passed to the parent class (here $literal). Finally, one returns the rewritten ADT.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pgrandjean