Прокси-макрос scala, выдача аргументов метода преобразования в значения

Я пытаюсь написать прокси-макрос, используя макросы scala. Я хочу иметь возможность прокси черты X и возвращать экземпляры X, которые вызывают функцию для всех методов X.

Вот что я сделал до сих пор. Скажем, мы хотим проксировать черту TheTrait (которая определена ниже), мы можем запустить ProxyMacro.proxy, передав функцию, которая будет вызываться для всех вызовов методов прокси.

    trait TheTrait
    {
        def myMethod(x: String)(y: Int): String
    }

    val proxy = ProxyMacro.proxy[TheTrait] {
        case ("myMethod", args) =>
            "ok"
    }
    println(proxy.myMethod("hello")(5))

Реализация пока такова:

package macrotests

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

object ProxyMacro
{
type Implementor = (String, Any) => Any

def proxy[T](implementor: Implementor): T = macro impl[T]

def impl[T: c.WeakTypeTag](c: Context)(implementor: c.Expr[Implementor]): c.Expr[T] = {
    import c.universe._

    val tpe = weakTypeOf[T]

    val decls = tpe.decls.map { decl =>
        val termName = decl.name.toTermName
        val method = decl.asMethod
        val params = method.paramLists.map(_.map(s => internal.valDef(s)))
        val paramVars = method.paramLists.flatMap(_.map { s =>
            internal.captureVariable(s)
            internal.referenceCapturedVariable(s)
        })

        q""" def $termName (...$params) = {
            $implementor (${termName.toString}, List(..${paramVars}) ).asInstanceOf[${method.returnType}]
           }"""
    }

    c.Expr[T] {
        q"""
      new $tpe {
        ..$decls
      }
  """
    }
}

}

Но есть проблема. Это не компилируется из-за List(..${paramVars}). Это должно просто создать список со всеми значениями аргументов метода. Но я получаю проблему компиляции (не стоит вставлять ее) в этой строке.

Как я могу преобразовать список аргументов метода в их значения?

1 ответ

Решение

showInfo полезна, когда вы отлаживаете макрос

def showInfo(s: String) = c.info(c.enclosingPosition, s.split("\n").mkString("\n |---macro info---\n |", "\n |", ""), true)

менять

val paramVars = method.paramLists.flatMap(_.map { s => internal.captureVariable(s) internal.referenceCapturedVariable(s) })(этот результат List(x0$1, x1$1))

в

val paramVars = method.paramLists.flatMap(_.map { s => s.name })(этот результат List(x, y))

Другие вопросы по тегам