Как написать макрос Scala, который оценивает дерево, подобное reify

Я хочу написать макрос, который захватывает фрагмент программы и делает его доступным как Tree во время выполнения. По сути, мне нужна функциональность reify, но встроить ее в другой синтаксис. Я хочу вызвать apply для объекта-компаньона Workload, предоставить некоторый код и сохранить Tree предоставленного кода в члене вновь созданного объекта Workload.

val wl = Workload {
  // some code ...
}

wl.tree // Tree of 'some code'

К сожалению, я не могу просто перенаправить на reify, потому что это макрос. Я думаю, мне нужно написать свой собственный макрос, похожий на reify. Но я понятия не имею, как вернуть Tree из макроса, а источник reify просто упоминает какую-то аппаратную реализацию.

Как это можно сделать?

Обновлять

Я написал небольшой пример, чтобы подчеркнуть свою точку зрения

import scala.reflect.runtime.universe._

object MacroFun {
  import scala.reflect.macros.blackbox.Context
  import scala.language.experimental.macros

  def getSomeTree: Expr[Unit] = macro getTreeImpl

  def getTreeImpl(c: Context): c.Expr[Expr[Unit]] = {
    import c.universe._

    val expr = reify {
      println("Hello World!")
    }

    ???
  }
}

Единственное, чего не хватает, так это способа превратить expr в c.Expr[Expr[Unit]].


person Johannes Luong    schedule 10.11.2016    source источник


Ответы (1)


Вот как я это сделал в итоге. Просто не забудьте вызвать reify во вселенной выполнения, чтобы получить Expr, который не зависит от Context.

class ErplMacro(val c: Context) {
  def lift[T:c.WeakTypeTag](exp: c.Expr[T]) = {
    import c.universe._
    q"""ErplRuntime.compile(scala.reflect.runtime.universe.reify($exp))"""
  }
}

object ErplRuntime {
  def compile[T](ctxElems: (scala.Symbol,Any)*)(exp: Expr[T]): Unit = // ...
}

trait ErplApi {
  def compile[T](exp: T): Unit = macro ErplMacro.lift[T]
}
person Johannes Luong    schedule 14.02.2017