Scala 使用def宏捕获源代码 (太长了,读不下去了,去大胆的脸)< /P>

Scala 使用def宏捕获源代码 (太长了,读不下去了,去大胆的脸)< /P>,scala,macros,reify,Scala,Macros,Reify,我有一个干净的带序列化的封闭类型类系统(与POJO序列化问题分离)。例如: trait Expr case class Const(i: Int) extends Expr case class BinOp(a: Expr, b: Expr, op: Int) extends Expr case class Map(a: Expr, fun: Expr => Expr) extends Expr 但在这种情况下,我需要捕捉一个结束。例如: trait Expr case class C

我有一个干净的带序列化的封闭类型类系统(与POJO序列化问题分离)。例如:

trait Expr
case class Const(i: Int) extends Expr
case class BinOp(a: Expr, b: Expr, op: Int) extends Expr
case class Map(a: Expr, fun: Expr => Expr) extends Expr
但在这种情况下,我需要捕捉一个结束。例如:

trait Expr
case class Const(i: Int) extends Expr
case class BinOp(a: Expr, b: Expr, op: Int) extends Expr
case class Map(a: Expr, fun: Expr => Expr) extends Expr
现在,我曾经用POJO序列化(
ObjectOutputStream
等)解决了这个问题,以获得
fun
。我的脚被咬得很厉害,因为我无法在Scala2.10中阅读我在2.9中连载的内容。在这种情况下,我真的需要确保我可以独立于Scala版本取回我的东西

所以。。。我一直在想,我可以使用宏对源代码进行“备份”,这样,如果POJO反序列化失败,我就可以从源代码中重新生成函数(使用就地编译器/解释器)

我的想法是

object Map {
  def apply(a: Expr, fun: Expr => Expr): Map = macro applyImpl
  private def applyImpl = ???

  def unapply(m: Map): Option[(Expr, Expr => Expr)] = Some(m.a -> m.fun)
}
trait Map extends Expr {
  def a: Expr
  def fun: Expr => Expr
}

implicit class ExprOps(val ex: Expr) extends AnyVal {
  def map(fun: Expr => Expr) = Map(ex, fun)
}
是否可以轻松捕获呼叫源,如

//           |------------- source of this -------------|
someExpr.map { case Const(i) => Const(i*i); case x => x }

(我猜def宏应该已经在
ExprOps
map
功能中了。)

文本替换宏在这方面非常棒。斯卡拉不跟他们一起去,但是考虑写你自己的!转变

{# case Const(i) => Const(i*i); case x => x #}

应该很容易;然后你只需要在编译之前进行预处理。如果希望IDE不会被不同的行长度所混淆,可以将字符串存储在单独的对象中,例如

{# _+7 #}/*STORE*/

({_+7}, Store.aW4)

...

object Store {
   val aW4 = """_+7"""
}
//(EOF)

(为了获得最佳结果,base-64对捕获的文本进行编码。只要您递归工作并意识到嵌套可能发生,嵌套就可以正常工作。)

我认为您无法获得源代码,但您可以获得
def applyImpl(c:Context)(a:c.Expr[Expr],fun:c.Expr[Expr=>Expr]):c.Expr[Map]={val source=c.universe.show(fun.tree);…}
@senia感谢您的链接和评论。我不需要原始源代码,因为它(可能)不会显示给用户,我只想要一个可以重新编译到同一棵树的源代码,即使say
tree
的序列化版本发生了变化(因此我不想直接序列化树)。因此,我将看看这个
宇宙。show
,这可能确实足够了。我需要能够在运行时使用嵌入式解释器完成这项工作。在我的编译项目/IDE中,我已经可以访问源代码:)我当然可以从解释器中捕获文本(我以前也做过),但接下来我需要费劲地查找源位置(当然,除非我添加转义字符,就像您在
#
中所做的那样)。