5

我正在尝试使用 scala 2.10 宏功能。不过,在某些情况下,我无法使用LabelDef 。在某种程度上,我偷看了编译器的代码,阅读了Miguel Garcia 的论文节选,但我仍然卡住了。

如果我的理解是正确的,伪定义将是:
LabelDef(labelName, listOfParameters, stmsAndApply)其中 3 个参数是 Trees,并且:
-是正在定义labelName的标签$L
的标识符 -对应于标签应用listOfParameters发生时传递的参数,如$L(a1 ,...,an),并且可以为空 -对应于语句块(可能没有)和最终的apply -expression label-apply 意味着或多或少的 GOTO 到标签
stmsAndApply

例如,在简单循环的情况下,LabelDef 最终可以应用自己:
LabelDef($L, (), {...; $L()})

现在,如果我想定义 2 个相互跳转的 LabelDef:

...
LabelDef($L1, (), $L2())
...
LabelDef($L2, (), $L1())
...

第二个 LabelDef 很好,但是编译器在第一个输出错误,“未找到:值$L2 ”。我猜这是因为$L2在尝试应用它时尚未定义。这是一棵正在建造的树,因此对我来说很有意义。到目前为止我的理解正确吗?因为如果没有预期的错误,这意味着我的宏实现可能是错误的。

无论如何,我相信一定有一种方法可以以某种方式从 $L1 应用 $L2(即跳转到 $L2),但我不知道该怎么做。有人有这样做的例子或任何指针吗?


关于在宏中使用 LabelDef 的其他不清楚的点(但现在不太关心)是: -
第二个参数是什么,具体来说,它在非空时如何使用?换句话说,带有参数的标签应用机制是什么?
- 将第三个参数的最终表达式放入标签应用之外是否有效?(并不是说我不能尝试,但宏仍然是实验性的)
- 是否可以在 LabelDef 之外执行转发标签应用?(也许这是一个多余的问题)

当然,答案中的任何宏实现示例都非常受欢迎!
干杯,

4

1 回答 1

1

因为如果没有预期的错误,这意味着我的宏实现可能是错误的。
是的,这似乎是一个错误(^^; 虽然我不确定 Block/LabelDef 组合的限制是否是故意存在的。

def EVIL_LABELS_MACRO = macro EVIL_LABELS_MACRO_impl
def EVIL_LABELS_MACRO_impl(c:Context):c.Expr[Unit] = { // fails to expand
  import c.universe._
  val lt1 = newTermName("$L1"); val lt2 = newTermName("$L2")
  val ld1 = LabelDef(lt1, Nil, Block(c.reify{println("$L1")}.tree, Apply(Ident(lt2), Nil)))
  val ld2 = LabelDef(lt2, Nil, Block(c.reify{println("$L2")}.tree, Apply(Ident(lt1), Nil)))
  c.Expr( Block(ld1, c.reify{println("ignored")}.tree, ld2) )
}

def FINE_LABELS_MACRO = macro FINE_LABELS_MACRO_impl
def FINE_LABELS_MACRO_impl(c:Context):c.Expr[Unit] = { // The End isn't near
  import c.universe._
  val lt1 = newTermName("$L1"); val lt2 = newTermName("$L2")
  val ld1 = LabelDef(lt1, Nil, Block(c.reify{println("$L1")}.tree, Apply(Ident(lt2), Nil)))
  val ld2 = LabelDef(lt2, Nil, Block(c.reify{println("$L2")}.tree, Apply(Ident(lt1), Nil)))
  c.Expr( Block(ld1, c.reify{println("ignored")}.tree, ld2, c.reify{println("The End")}.tree) )
}

我认为 Block 被解析为{ 语句;表达式 }因此最后一个参数是表达式。如果一个 LabelDef “落入”表达式,例如 EVIL_LABELS_MACRO 模式,它的扩展在语句中将不可见;因此错误“未找到:值$L2 ”。

所以最好确保所有 LabelDef “落入”语句。FINE_LABELS_MACRO 这样做并扩展为:

{
  $L1(){
    scala.this.Predef.println("$L1");
    $L2()
  };
  scala.this.Predef.println("ignored");
  $L2(){
    scala.this.Predef.println("$L2");
    $L1()
  };
  scala.this.Predef.println("The End")
}
于 2012-07-29T12:02:17.937 回答