看来 的输入Context.eval只能引用来自不同编译单元的值:
// project 1
object Z {
val foo = "WOOF"
def impl(c: Context)(x: c.Expr[String]) = {
val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate))
println(s"compile-time value is: ${c.eval(x1)}")
x
}
def test(x: String) = macro impl
}
// project 2
object Y {
val foo = "GOOF"
val boo = Z.test(Z.foo)
}
println(Y.boo)
Run Code Online (Sandbox Code Playgroud)
打印出"WOOF",但如果我将 boo 替换为val boo = Z.test(Y.foo),则会出现以下编译错误:
Error:(32, 29) exception during macro expansion:
java.lang.ClassNotFoundException: Y$
at scala.reflect.internal.util.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:72)
...
Run Code Online (Sandbox Code Playgroud)
有什么办法可以解决这个问题吗?我知道用 quill.io 定义的查询可以引用同一范围的方法,但我无法找到他们用来允许它的技巧。
我有一个工作宏,即:
object Main extends App {
println("Testing assert macro...")
val result = Asserts.assert(false, "abc")
}
Run Code Online (Sandbox Code Playgroud)
和
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
object Asserts {
val assertionsEnabled: Boolean = true
def assert(cond: Boolean, msg: String): Unit = macro assertImpl
def assertImpl(c: Context)(cond: c.Expr[Boolean], msg: c.Expr[String]) : c.Expr[Unit] = {
import c.universe._
cond.tree match {
case Literal(Constant(cond: Boolean)) =>
if (!cond) c.abort(c.enclosingPosition, "Fix the code, whatever.") else c.Expr(q"()")
}
}
}
Run Code Online (Sandbox Code Playgroud)
但问题是:我怎样才能做到这一点?:
val cond: Boolean = false
val result = Asserts.assert(cond, "abc")
Run Code Online (Sandbox Code Playgroud)
现在我有一个错误: …