4

As the title suggests, I am trying to create a Scala macro that generates a class definition. Basically I want to eventually do the following:

classify("StandardEvent", Map("name" -> String, "id" -> Int))
// should at compile-time expand to
case class StandardEvent(name: String, id: Int) extends Event

Is that even possible? And if so, could anyone point me into the right direction on how to do so? Actually, I cannot even get the following simple macro to work:

// Macro definition:
def classify(): Unit =
  macro classifyImpl

def classifyImpl(c: Context)(): c.Tree = {
  import c.universe._
  q"class SomeClass"
}

// Macro usage in seperate compilation unit
classify()
val s = new SomeClass

This gets me the following error message:

[error] ClassifyTest.scala:6: not found: type SomeClass
[error]   val s = new SomeClass
[error]               ^
[trace] Stack trace suppressed: run last app/compile:compileIncremental for the full output.
[error] (app/compile:compileIncremental) java.lang.AssertionError: assertion failed: 
[error]   class SomeClass extends scala.AnyRef {
[error]   def <init>() = {
[error]     super.<init>();
[error]     ()
[error]   }
[error] }
[error]      while compiling: ClassifyTest.scala
[error]         during phase: typer
[error]      library version: version 2.11.8
[error]     compiler version: version 2.11.8
[error]   reconstructed args: -bootclasspath // ...
[error] 
[error]   last tree to typer: type SomeClass
[error]        tree position: line 5 of ClassifyTest.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]      2 object ClassifyTest extends App {
[error]      3 
[error]      4   classify()
[error]      5   val s = new SomeClass
[error]      6 
[error]      7 }

Can anyone make sense of this? Help is much appreciated.

typeduke
  • 6,494
  • 6
  • 25
  • 34
  • 2
    It's not possible to introduce top-level class definitions with a def macro, but if you're willing to change the usage syntax a bit, macro annotations might work, and there are some tricks that allow you to accomplish something similar even with def macros. Eugene Burmako and I have an example project [here](https://github.com/travisbrown/type-provider-examples) that illustrates both approaches. – Travis Brown Jun 27 '16 at 19:28
  • If the intent is to auto-generate a bunch of classes in this manner, you might want to go with [sbt's sourceGenerators](http://www.scala-sbt.org/1.0/docs/Howto-Generating-Files.html) – Dylan Jun 27 '16 at 20:10

0 Answers0