How can I use Scala macros to create an object?

869 views Asked by At

I am trying to create a Scala macro that will generate an object - something like

object SomeEnum {
  sealed abstract class Enum(name: String)
  case object Option1 extends Enum("option1")
  case object Option2 extends Enum("option2")
  private val elements: Seq[Enum] = Seq(Option1, Option2)
  def apply(code: String): Enum = {
    ...
  }
} 

I thought I might be able to create a macro createEnum, so I could just put createEnum("SomeEnum", "Option1", "Option2") into my code and have it generate. Seems like it's calling out for a macro.

But I must not be understanding macros. I am using Scala 2.11.6, and just to try to get something working, I created the following:

object createEnumObj {
  def createEnumImpl(c: scala.reflect.macros.whitebox.Context)(ename: c.Expr[String]): c.universe.ModuleDef = {
    import c.universe._

    val Literal(Constant(s_ename: String)) = ename.tree
    val oname = TermName(s_ename)

    val barLine = q"val bar: Int = 5"
    q"object $oname { $barLine }"
  }

  def createEnum(ename: String): Unit = macro createEnumImpl
}

This is in a separate project - everything seems to be compiling for it OK.

If I stick a call to createEnumObj.createEnum into some source and try to compile that, I get a billion lines (give or take a few) of exception output, which seems to repeat something like this:

[error] (main/compile:compile) java.lang.AssertionError: assertion failed:
[error]   object foo extends scala.AnyRef {
[error]   def <init>() = {
[error]     super.<init>();
[error]     ()
[error]   };
[error]   val bar: Int = 5
[error] }
[error]      while compiling: /Users/bob/ICL/ironcore-id/src/main/scala/package.scala
[error]         during phase: typer
[error]      library version: version 2.11.6
[error]     compiler version: version 2.11.6
[error]   reconstructed args: -Xfuture ...
error]
[error]   last tree to typer: term foo
[error]        tree position: line 8 of /Users/bob/ICL/ironcore-id/src/main/scala/package.scala
[error]               symbol: <none>
[error]    symbol definition: <none> (a NoSymbol)
[error]       symbol package: <none>
[error]        symbol owners:
[error]            call site: <none> in <none>
[error]
[error] == Source file context for tree position ==
[error]
[error]      5   type DateTime = Int
[error]      6
[error]      7   createEnumObj.createEnum("foo")
[error]      8
[error]      9 }
[error] Total time: 2 s, completed Jun 18, 2015 2:46:05 PM

What I am trying to do doesn't seem too dissimilar to this question, but I'm obviously missing something. Any ideas about how to accomplish this would be gratefully accepted.

Thanks, Bob

0

There are 0 answers