Greg
Greg

Reputation: 11512

How can I use macros for code substitution in Scala?

I have repetitive blocks of code I want to copy, like old C-style macros. I'm trying quasiquotes:

import scala.language.experimental.macros

object CodeBlock {
  val quasi = q"""def foo() = {"bar"}"""
}

case class A() {
// ??? want quasi here
}

case class B() {
// ??? want quasi here
}

Upvotes: 1

Views: 153

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51658

Try macro annotation

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

@compileTimeOnly("enable macro paradise")
class codeBlock extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro CodeBlockMacro.impl
}

object CodeBlockMacro {
  def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._
    annottees match {
      case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" :: tail =>
        q"""
          $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self =>
            def foo() = {"bar"}
            ..$stats
          }

          ..$tail
        """
    }
  }
}

@codeBlock
case class A()

@codeBlock
case class B()

//Warning:scalac: {
//  case class A extends scala.Product with scala.Serializable {
//    def <init>() = {
//      super.<init>();
//      ()
//    };
//    def foo() = "bar"
//  };
//  ()
//}
//Warning:scalac: {
//  case class B extends scala.Product with scala.Serializable {
//    def <init>() = {
//      super.<init>();
//      ()
//    };
//    def foo() = "bar"
//  };
//  ()
//}

Upvotes: 1

Related Questions