我是Scala宏的新手,我正在尝试编写一个非常基本的DSL。
我有以下Scala类:
abstract class SpecialFunction {
def apply(): Unit
}
和以下Scala宏:
def mImpl(c: Context)(bodyBlock: c.Expr[Unit]): c.Expr[X] =
c.universe.reify {
new X(new SpecialFunction {
override def apply() {
bodyBlock.splice
}
})
}
def m(bodyBlock: Unit): X = macro mImpl
到目前为止一切顺利。例如,它允许我写:
def example = m {
println("Hello, world")
}
这归结为:
def example = new X(new SpecialFunction {
override def apply() {
println("Hello, world")
}
})
但是这个公式不允许我在这样的“m块”中有局部变量。例如,我无法写:
def example = m {
val x = 7
println(x.toString)
}
在编译时我收到错误:
symbol value x does not exist in example
但是,我想要达到的目的是:
def example = new X(new SpecialFunction {
override def apply() {
val x = 7
println(x.toString)
}
})
(我想我理解为什么会这样:子表达式在传递给宏之前被评估,因此对x的引用是无效的。)
所以我的问题是:我怎样才能使上述工作成功? (我只是希望宏中定义的额外代码在“m块”中的代码周围“复制粘贴”,就像在C ++宏中一样。)
非常感谢任何帮助: - )
答案 0 :(得分:1)
您的输出表达式保留对旧x
符号的引用,但它应该是对新符号的引用。因此,您可以通过应用Context中的resetLocalAttrs
来重置您要重复使用的树中的所有垃圾参考。
怎么样......?
def mImpl(c: Context)(bodyBlock: c.Expr[Unit]): c.Expr[X] =
c.universe.reify {
new X(new SpecialFunction {
override def apply() {
c.Expr[Unit](c.resetLocalAttrs(bodyBlock.tree)).splice
}
})
}
在这个question中,你可以阅读Scala Macros的一个很好的解释。