kostas.kougios
kostas.kougios

Reputation: 993

scala proxy macro, issue converting method args to values

I am trying to write a proxy macro using scala macros. I want to be able to proxy a trait X and return instances of X that invoke a function for all methods of X.

Here is what I did so far. Say we want to proxy the trait TheTrait (which is defined below), we can run ProxyMacro.proxy passing a function that will be called for all invocations of the proxy methods.

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

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

The implementation so far is this:

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

}

But there is a problem. This doesn't compile due to List(..${paramVars}). This should just create a list with all the values of the method arguments. But I get a compilation issue (not worth pasting it) on that line.

How can I convert the list of method arguments to their values?

Upvotes: 0

Views: 207

Answers (1)

余杰水
余杰水

Reputation: 1384

showInfo is useful when you debug macro

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

change

val paramVars = method.paramLists.flatMap(_.map { s => internal.captureVariable(s) internal.referenceCapturedVariable(s) })(this result is List(x0$1, x1$1))

to

val paramVars = method.paramLists.flatMap(_.map { s => s.name })(this result is List(x, y))

Upvotes: 2

Related Questions