Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a class or object in Scala Macros?

Tags:

macros

scala

I'm attempting to generate a companion object from a case class using Macros but I'm having a very hard time finding any examples of how to accomplish this.

For example:

case class Person(name: String, age: Int, id: Option[Int] = None)

If I do:

object PersonTable extends TypedTable[Person]

I want it to generate:

object PersonTable extends Table("PERSON") {
  val name = column[String]("NAME")
  val age = column[Int]("AGE")
  val id = column[Option[Int]]("ID")
}

Further, I want to be able to extend it and add additional fields as well:

object PersonTable extends TypedTable[Person] {
  val created = column[Timestamp]("TIMESTAMP")
}

And it would generate:

object PersonTable extends Table("PERSON") {
  val name = column[String]("NAME")
  val age = column[Int]("AGE")
  val id = column[Option[Int]]("ID")
  val created = column[Timestamp]("TIMESTAMP")
}

Edit

After reading about macro annotations (thanks Eugene and Mario) I created the following code:

class table[T] extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro TableGenerator.impl
}

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

    def modifiedObject(objectDef: ModuleDef): c.Expr[Any] = {
      val ModuleDef(_, objectName, template) = objectDef
      val ret = q"""
object $objectName {
  def test() = println("Wahoo!")
}
      """
      c.Expr[Any](ret)
    }

    annottees.map(_.tree) match {
      case (objectDecl: ModuleDef) :: _ => modifiedObject(objectDecl)
      case x => c.abort(c.enclosingPosition, s"@table can only be applied to an object, not to $x")
    }
  }
}

And then attempted to use it like this:

@table[String] object MyCoolObject
MyCoolObject.test()

The first line works fine but the second line says it can't find the test method. How do I make it so that the test method is visible?

like image 738
darkfrog Avatar asked Jul 15 '15 01:07

darkfrog


1 Answers

It's unfortunately very difficult to find good examples of Macros online - especially for 2.11. I was finally able to get everything working so I wanted to provide a link to the code for anyone struggling with the same problems later.

https://github.com/outr/scalarelational/blob/master/mapper/src/main/scala/org/scalarelational/mapper/typedTable.scala

Thanks again Eugene and Mario for your great answers that led me to finding my answer.

like image 51
darkfrog Avatar answered Sep 19 '22 10:09

darkfrog