Groovy 中如何使用 GOTO 语句?

问题描述 投票:0回答:4

我看到了这篇关于 Scala 延续的精彩博客文章,它“模拟”了 Scala 语言中的

GOTO
语句。 (阅读更多关于这里继续

我希望在编程语言 Groovy 中也能拥有同样的功能。我认为在 Groovy 编译器阶段转换 中这是可能的。

我正在研究领域特定语言 (DSL),并且首选嵌入到 Groovy 中。我想要

GOTO
声明,因为 DSL 是一种非结构化语言(并且是从工作流程图生成的)。我需要一个“带标签”的 goto 语句,而不是行号。

DSL 是一种用于工作流定义的语言,并且由于节点之间的箭头没有限制,因此需要

goto
。 (或带有
while
等不可读的代码)

作为 Groovy 和 Scala 的初学者,我不知道是否可以将 Scala 解决方案翻译为 Groovy,但我认为 Groovy 中有延续。

我正在寻找一种算法/代码来模拟 Groovy 中的标记 goto。我想到的一种算法是重复使用

eval
;当您处于
eval
时,执行
goto
。 DSL 已通过
eval
进行评估。

我不是在寻找“while”循环或其他东西,而是翻译这段代码以使其工作(其他一些语法没有问题)

label1: 
a();
b();
goto label1; 

PS: 我不喜欢讨论我是否应该真正使用/想要 GOTO 语句。 DSL 是一种规范语言,可能无法处理变量、效率等问题。

PS2:可以使用其他关键字

GOTO

groovy dsl transformation goto continuations
4个回答
5
投票

一种方法是使用 Groovy AST 转换。这是一把大锤子,并且可能对您想要构建的语言进行了过度设计。使用 AST 是 Groovy 人们多年来一直在做的事情,它真的很强大。

Spock 框架人员重写了您创建的测试,用标签注释代码。 https://github.com/spockframework/spock

哈姆雷特·达西曾多次就此事发表过演讲。在他的博客上也可以找到一些帖子。 http://hamletdarcy.blogspot.com/

有用的起点:

长话短说,我想说这很有可能。


1
投票

尝试这样做不会有任何结果,因为

goto
是 Groovy 中的 保留字(就像 Java 中一样),因此在 DSL 中使用它会出现问题。

这不是 Scala 中的保留字,所以这不是问题


1
投票

您可以使用

if
循环模拟
goto
while
。它不会很漂亮,它会引入许多不必要的代码块,但它应该适用于任何函数。有一些证据表明,这样重写代码总是可能的,但当然可能并不意味着它很好或很容易。

基本上,您将所有局部变量移至函数的开头并添加一个

bool takeJump
局部变量。然后为任何 goto+label 对添加一个
while(takeJump){
+
}
对,并将 while 之前和 while 结束之前的标志设置为您想要的值。

但说实话我不推荐这种方法。我宁愿使用一个库,它允许我构建带有标签和 goto 的 AST,然后将其直接转换为字节码。

或者使用基于 java vm 构建的支持

goto
的其他语言。我确信有这样一种语言。


1
投票

只要把这个扔出去,也许你可以有一个作用域开关盒

因此,如果您的 DSL 是这样说的:

def foo() {
   def x = x()
   def y
   def z
   label a:
     y = y(x)
   if(y < someConst) goto a
   label b: 
    z = y(z)
    if(z > someConst) goto c
    x = y(y(z+x))
    z = y(x)
   label c:
    return z; 
}

你的“编译器”可以把它变成这样:

def foo() {
    String currentLABEL = "NO_LABEL"
    while(SCOPED_INTO_BLOCK_0143) {
       def x
       def y
       def z
       def retval
       switch(currentLABEL) {
       case "NO_LABEL":
          x = x()
       case "LABEL_A"
          y = y(x)

          if(y < someConst) {
            currentLABEL = "LABEL_A"
           break
          }
       case "LABEL_B"
          z = y(z)

          if(z > someConst) {
            currentLabel = "LABEL_C"
            break
          }
          x = y(y(z+x))
          z = y(x)
       case "LABEL_C"
          SCOPED_INTO_BLOCK_0143 = false
          retval = z
       }
    }
    return retval
}
© www.soinside.com 2019 - 2024. All rights reserved.