【问题标题】:how to get method body tree in scala macros如何在scala宏中获取方法体树
【发布时间】:2018-06-04 10:47:07
【问题描述】:

我正在尝试将 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()
     """
  }
}

【问题讨论】:

    标签: scala macros scala-macros


    【解决方案1】:

    我能够访问方法主体的一种方法是使用以下quasiquote

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

    方法体包含在expr 中。请注意在以下代码中如何通过模式匹配访问 sn-p 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)
    }
    

    【讨论】:

      【解决方案2】:

      您可以从Tree 获得Symbol,但反之则不行。并且方法主体在这个方法的Tree 中,而不是在这个TreeSymbol 中。所以你应该使用原始的Treein,而不是符号s。遍历Trees 在tutorial 中有描述。

      试试

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多