как получить дерево тела метода в макросах scala - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь преобразовать объект 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()
     """
  }
}

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Вы можете получить Symbol от Tree, но не наоборот.И тело метода находится в Tree этого метода, а не в Symbol этого метода.Таким образом, вы должны работать с оригинальным Tree in, а не с символами s.Обход Tree s описан в учебнике .

Попробуйте

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()
   """
}
0 голосов
/ 04 июня 2018

Один из способов получить доступ к телу метода - использовать следующий квазицитат :

q"..$mods def $ename[..$tparams](...$paramss): $tpeopt = $expr"

Тело метода содержится в 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)
}
...