如何在scala宏中获取方法体树

如何在scala宏中获取方法体树,scala,macros,scala-macros,Scala,Macros,Scala Macros,我正在尝试将scala对象转换为js对象 object SObject { def foo(in:String):String = s"scalajs-$in" } val o = ScalaObjectToJSObjectMacro(SObject) // js.Dynamical.literal(foo = (in:String) => s"scalajs-$in") 在宏中,我能够获取对象的所有方法(in.tpe.decls.toList),然后对于每个方法名、retur

我正在尝试将scala对象转换为js对象

object SObject {
  def foo(in:String):String =  s"scalajs-$in" 
}

val o = ScalaObjectToJSObjectMacro(SObject) // js.Dynamical.literal(foo = (in:String) => s"scalajs-$in")
在宏中,我能够获取对象的所有方法(in.tpe.decls.toList),然后对于每个方法名、returnType,MethodSymbolApi中提供了参数,但没有主体树:s

object ScalaObjectToJSObjectMacro {

  def apply[T](in: T): js.Object = macro macroImpl

  def macroImpl(c: blackbox.Context)(in: c.Tree): c.Tree = {
    import c.universe._
    val methods = in.tpe.decls.toList
      .filter(s => {
        s.isMethod && s.asMethod.isPublic && !s.asMethod.isConstructor
      })
      .map(m => {
        val mt = m.asMethod
        val name = mt.name
        val returnType = mt.returnType
        val params = mt.paramLists
        val body = ??? //TODO
      })

    println(s"methods: ${methods}")

    q"""
        scala.scalajs.js.Dynamic.literal()
     """
  }
}

我能够访问方法体的一种方法是使用以下内容:

方法主体包含在
expr
中。请注意如何通过模式匹配访问以下代码段
expr

def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
  import c.universe._
  val result = {
    annottees.map(_.tree).toList match {
      case q"def $ename[..$tparams](...$paramss): $tpeopt = $expr" :: Nil =>
        // do something with $expr
        ...
    }
  }
  c.Expr[Any](result)
}

您可以从
中获取
符号
,但反之亦然。方法主体在该方法的
树中
而不是在该
树中
符号中
。因此,您应该使用中的原始
,而不是符号
s
。遍历
s如中所述

试一试

def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
  import c.universe._
  val result = {
    annottees.map(_.tree).toList match {
      case q"def $ename[..$tparams](...$paramss): $tpeopt = $expr" :: Nil =>
        // do something with $expr
        ...
    }
  }
  c.Expr[Any](result)
}
def apply[T](in: T): js.Object = macro macroImpl

def macroImpl(c: blackbox.Context)(in: c.Tree): c.Tree = {
  import c.universe._

  object traverser extends Traverser {
    var methods = List[Symbol]()

    override def traverse(tree: Tree): Unit = tree match {
      case t@DefDef(modifiers, name, typeParams, paramss, returnType, body) if name != termNames.CONSTRUCTOR && !modifiers.hasFlag(Flag.PRIVATE) =>
        methods = t.symbol :: methods
        // your logic with t, t.symbol, name, paramss, returnType, body etc.
        super.traverseTrees(typeParams)
        super.traverseTreess(paramss)
        super.traverse(returnType)
        super.traverse(body)
      case _ => super.traverse(tree)
    }
  }

  traverser.traverse(in)

  println(s"methods: ${traverser.methods}")

  q"""
      scala.scalajs.js.Dynamic.literal()
   """
}