在Scala宏中使用LabelDef(2.10) [英] Using LabelDef in scala macros (2.10)

查看:97
本文介绍了在Scala宏中使用LabelDef(2.10)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm experimenting with the scala 2.10 macro features. I have trouble using LabelDef in some cases, though. To some extent I peeked in the compiler's code, read excerpts of Miguel Garcia's papers but I'm still stuck.

如果我的理解是正确的,则伪定义为:
LabelDef(labelName, listOfParameters, stmsAndApply)其中3个参数是Trees和:
-labelName是要定义的标签 $ L 的标识符
-listOfParameters对应于出现label- apply 时传递的参数,例如 $ L(a1,...,an),并且可以为空
-stmsAndApply对应于声明的块(可能没有)和最终的 apply -expression
label-apply或多或少地指向标签

If my understanding is correct, a pseudo-definition would be:
LabelDef(labelName, listOfParameters, stmsAndApply) where the 3 arguments are Trees and:
- labelNameis the identifier of the label $L being defined
- listOfParameters correspond to the arguments passed when label-apply occurs, as in $L(a1,...,an), and can be empty
- stmsAndApplycorresponds to the block of statements (possibly none) and final apply-expression
label-apply meaning more-or-less a GOTO to a label

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

For instance, in the case of a simple loop, a LabelDef can eventually apply itself:
LabelDef($L, (), {...; $L()})

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

Now, if I want to define 2 LabelDef that jump to each other:

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

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

The 2nd LabelDef is fine, but the compiler outputs an error on the 1st, "not found: value $L2". I guess that is because $L2 isn't yet defined while there is an attempt to apply it. This is a tree being constructed so that would make sense to me. Is my understanding correct so far? Because if no error is expected, that means my macro implementation is probably buggy.

无论如何,我相信必须有一种方法可以从$ L1中应用$ L2(即,跳转到$ L2),以某种方式,但是我只是不知道如何去做吧.有人有这样做的例子或任何指针吗?

Anyway, I believe there must be a way to apply $L2 (i.e. Jumping to $L2) from $L1, somehow, but I just have no clue how to do it. Does someone have an example of doing that, or any pointer?


关于在宏中使用LabelDef的其他不清楚的地方(但现在很少关注)是:
-第二个参数具体是什么,非空时如何使用?换句话说,带有参数的标签应用的机制是什么?
-在第3个自变量的最终表达式中加上除标签以外的其他内容是否有效? (不是我不能尝试,但宏仍处于实验阶段)
-是否可以在LabelDef外部执行转发标签应用? (也许这是一个多余的问题)


Other unclear points (but less of a concern right now) about using LabelDef in macros are:
-what the 2nd argument is, concretely, how is it used when non-empty? In other words, what are the mechanisms of a label-apply with parameters?
-is it valid to put in the 3rd argument's final expression anything else than a label-apply? (not that I can't try, but macros are still experimental)
-is it possible to perform a forwarding label-apply outside a LabelDef? (maybe this is a redundant question)

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

Any macro implementation example in the answer is, of course, very welcome!
Cheers,

推荐答案

因为如果没有错误,那意味着我的宏实现可能有问题.
是的,这似乎是一个错误(^^;尽管我不确定是否故意存在Block/LabelDef组合的限制.

Because if no error is expected, that means my macro implementation is probably buggy.
Yes, it seems that was a bug (^^; Although I'm not sure whether or not the limitation with the Block/LabelDef combination exists on purpose.

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被解析为 {语句;表达式} ,因此最后一个参数是 expression .如果LabelDef落入" 表达式,例如EVIL_LABELS_MACRO模式,其扩展在语句中不可见;因此出现错误找不到:值 $ L2 ".

I think a Block is parsed into { statements; expression } thus the last argument is the expression. If a LabelDef "falls in" expression, e.g. the EVIL_LABELS_MACRO pattern, its expansion won't be visible in statements; hence error "not found: value $L2".

因此,最好确保所有LabelDef都属于"声明" . FINE_LABELS_MACRO会这样做,并扩展为:

So it's better to make sure all LabelDef "fall in" statements. FINE_LABELS_MACRO does that and expands to:

{
  $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")
}

这篇关于在Scala宏中使用LabelDef(2.10)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆