Прокси-макрос 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)
)