I have an ostensibly simple macro problem that I’ve been banging my head against for a few hours, with no luck. Perhaps someone with more experience can help.
I have the following macro:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object MacroObject {
def run(s: String): Unit =
macro runImpl
def runImpl(c: Context)(s: c.Tree): c.Tree = {
import c.universe._
println(s) // <-- I need the macro to know the value of s at compile time
q"()"
}
}
The problem is this: I’d like the macro to know the value s
that is passed to it — not an AST of s
, but the value of s
itself. Specifically, I’d like it to have this behavior:
def runTheMacro(str: String): Unit = MacroObject.run(str)
final val HardCodedString1 = "Hello, world!"
runTheMacro(HardCodedString1) // the macro should print "Hello, world!"
// to the console during macro expansion
final val HardCodedString2 = "So long!"
runTheMacro(HardCodedString2) // the macro should print "So long!"
// to the console during macro expansion
It is guaranteed that the only strings that will be passed to runTheMacro
are hard-coded constant values (i.e., known at compile-time).
Is this possible, and how does one do this?
--
Edit: There are also the following constraints:
- It must be a blackbox macro.
- The macro signature must use
c.Tree
s, notc.Expr[_]
s (legacy code; can’t change that part) - I do have a
toolbox
within the macro at my disposal if needed:
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
private val toolbox = currentMirror.mkToolBox()
/** Evaluate the given code fragment at compile time. */
private def eval[A](code: String): A = {
import scala.reflect.runtime.{universe => u}
val uTree: u.Tree = toolbox.parse(code)
toolbox.eval(uTree).asInstanceOf[A]
}
java.lang.IllegalArgumentException: Could not find proxy for str: String in List(value str, method run, object cmd2, package $sess, package ammonite, package <root>) (currentOwner= method wrapper )
– Ripleys
to beLiteral(Constant(s: String))
, and if it doesn't match, just callc.abort
– Gyrostabilizer