避免使用quasiquotes进行重新编译

gba*_*ler 3 macros scala

在Scala中编写宏时,Quasiquotes简化了许多操作.但是我注意到,每次触发SBT中的编译时都可以重新编译包含quasiquotes的宏,即使宏实现和任何调用站点都没有更改并且需要重新编译.

这似乎不会发生,如果quasiquotes中的代码相当简单,它似乎只有在依赖于另一个类时才会发生.我注意到用"reify"重写所有内容似乎解决了重新编译的问题,但我没有设法在没有quasiquotes的情况下重写最后一部分...

我的宏通过在编译期间创建包装函数来避免启动时的反射.

我有以下课程:

object ExportedFunction {
  def apply[R: Manifest](f: Function0[R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction0[R] {
    def apply: R = f()
    val functionDescription = fd
  }

  def apply[T1: Manifest, R: Manifest](f: Function1[T1, R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction1[T1, R] {
    def apply(t1: T1): R = f(t1)
    val functionDescription = fd
  }

  ... and so on... until Function17...
}
Run Code Online (Sandbox Code Playgroud)

然后,我object使用所描述的接口分析和导出任何成员函数,如下所示:

def export(registrar: FunctionRegistrar,
           root: Object,
           <...more args...>) = macro exportImpl

def exportImpl(c: Context)(registrar: c.Expr[FunctionRegistrar],
                           root: c.Expr[Object],
                           <...>): c.Expr[Any] = {             

  import c.universe._   

  <... the following is simplified ...>
  root.typeSignature.members.flatMap {
    case x if x.isMethod =>
      val method = x.asMethod     

      val callee = c.Expr(method))

      val desc = q"""FunctionDescription(<...result from reflective lookup...>)"""
      val export = q"ExportedFunction($callee _, $desc)"
      q"$registrar.+=({$export})"
Run Code Online (Sandbox Code Playgroud)

我可以使用reify重写第一行和最后一行,但我无法重写第二行,我的最佳镜头是quasiquotes:

val export = reify {
  ...
     ExportedFunction(c.Expr(q"""$callee _"""), desc)
  ...
}.tree
Run Code Online (Sandbox Code Playgroud)

但这会导致:

overloaded method value apply with alternatives... cannot be applied to (c.Expr[Nothing], c.universe.Expr[FunctionDescription])
Run Code Online (Sandbox Code Playgroud)

我认为编译器缺少implicits,或者这个代码只适用于具有固定数量参数的函数,因为它需要在宏编译时知道该方法有多少参数?但是,如果所有内容都是使用quasiquotes编写的,那么它是有效

Eug*_*ako 6

根据SBT问题的描述,我可以假设您正在使用2.10.x的宏天堂,并且正面临https://github.com/scalamacros/paradise/issues/11.我打算本周解决这个问题,所以修复工作很快就会到来.同时,您可以使用问题页面上描述的解决方法.

至于reify问题,并非所有quasiquotes都可以使用reify重写.像你在这里遇到的限制是一个非常强大的动力,我们将注意力转移到Scala 2.11中的quasiquotes.