3

我对 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++ 宏中一样。)

任何帮助将不胜感激 :-)

4

1 回答 1

1

您的输出表达式保留对旧x符号的引用,但它应该是对新符号的引用。resetLocalAttrs因此,您可以通过从Context应用来重置您打算重用的树中的所有垃圾引用。

怎么样...?

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
      }
    })
  }

在这个问题中,您可以阅读 Scala Macros 专家的精彩解释。

于 2013-04-18T07:24:34.933 回答