I am building a DSL in Scala, and for that, I need to store \"instances\" of a class (Parent
in this case), except these \"instances\" must be re-created several ti
Unfortunately macros will not help.
Macro annotations (which expand before type checking) can't annotate code blocks:
@constructMacro {
func(1)
func(userVar)
}
is illegal.
Def macros (which expand during type checking) have their arguments type checked before macros are expanded. So
constructMacro {
func(1)
func(userVar)
}
doesn't compile:
Error: not found: value func
func(1)
Error: not found: value func
func(userVar)
That's the reason why macro shapeless.test.illTyped accepts a string rather than code block:
illTyped("""
val x: Int = "a"
""")
rather than
illTyped {
val x: Int = "a"
}
So the closest you can implement is
constructMacro("""
func(1)
func(userVar)
""")
def constructMacro(block: String): ParentWrapper = macro constructMacroImpl
def constructMacroImpl(c: blackbox.Context)(block: c.Tree): c.Tree = {
import c.universe._
val q"${blockStr: String}" = block
val block1 = c.parse(blockStr)
q"""construct(new Parent {
..$block1
})"""
}
You can annotate a variable
@constructMacro val x = {
func(1)
func(userVar)
}
// becomes
// val x: ParentWrapper = construct(new Parent {
// func(1)
// func(userVar)
// })
@compileTimeOnly("enable macro paradise to expand macro annotations")
class constructMacro extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro constructMacroImpl.impl
}
object constructMacroImpl {
def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
annottees match {
case q"$mods val $tname: $tpt = { ..$stats }" :: Nil =>
q"$mods val $tname: ParentWrapper = construct(new Parent { ..$stats })"
case _ =>
c.abort(c.enclosingPosition, "Not a val")
}
}
}
If I understood correctly, you just need to change object
to def
in the ObjectA
block:
class User {
var userVar = 13
def makeParent = new Parent {
func(1)
func(userVar)
}
construct(makeParent)
}
and it'll do what you want.