在 Xtend 循环中使用唯一的变量名称(代码生成)

Using unique variable names in Xtend loop (Code Generation)

我用 Xtext 创建了一个自定义 DSL,这对描述层次结构很有用(在本例中固定高度为 2)。我现在要做的是生成一个简单的 Java Swing App,它可以使用 JTree 显示这样的层次结构。我通过使用 Xtend 从 Xtext 扩展代码生成示例来做到这一点。一切正常,但可以做得更好。

到目前为止我的模板中非常难看的部分:

def compile(Level a) '''
    DefaultMutableTreeNode «a.name» = new DefaultMutableTreeNode("«a.name»");
    «FOR b:a.sublevels»
      DefaultMutableTreeNode «b.name» = new DefaultMutableTreeNode("«b.name»");
      «a.name».add(«b.name»);
    «ENDFOR»
'''

如您所见,我使用 DSL 用户定义的实体名称作为代码生成的变量名称,这是不好的。如果用户选择的名称不是 Java 中的有效变量名称,应用程序将不会在以后编译。

我这样做的原因是因为在创建 JTree 及其节点时,我需要唯一的变量名。生成的代码如下所示:

DefaultMutableTreeNode a = new DefaultMutableTreeNode("a");
DefaultMutableTreeNode a1 = new DefaultMutableTreeNode("a1");
a.add(a1);
DefaultMutableTreeNode a2 = new DefaultMutableTreeNode("a2");
a.add(a2);
DefaultMutableTreeNode a3 = new DefaultMutableTreeNode("a2");
a.add(a3);
...

由于所有内容都在同一范围内,因此变量名称需要不同 - 在本例中为 a、a1、a2 和 a3。但是我如何创建有效的唯一变量名称而不是使用用户的输入(这可能是无效的)?感谢您的帮助,谢谢。

您需要节点的人工变量名和计数器变量。最简单的方法是将它作为一个字段添加到生成器中,并在调用编译方法之前重置它。

int count

def compile(Level a) {
    count = 0
    return compile(a, -1)
}   

def compile(Level a, int parentCount) {
  var aCount = count++
  return '''
    DefaultMutableTreeNode node«aCount» = new DefaultMutableTreeNode("«a.name»");
    «IF parentCount > -1»
      node«parentCount».add(node«aCount»);
    «ENDIF»
    «FOR b:a.sublevels»
      «compile(b, aCount)»
    «ENDFOR»
  '''
}

如果您可以节省变量名,我更愿意使用 Java 鲜为人知的非静态初始化器生成代码,因为它们反映了 Java 代码中树的结构,例如

new DefaultMutableTreeNode("a") {{
  add(new DefaultMutableTreeNode("a1") {{
    add(new DefaultMutableTreeNode("b1"))
  }})
  add(new DefaultMutableTreeNode("a2"))
  add(new DefaultMutableTreeNode("a2"))
}}

通过非常简单的生成器

def CharSequence compile(Level a) '''
  new DefaultMutableTreeNode("«a.name»")«IF !a.sublevels.empty» {{
    «FOR b:a.sublevels»
      add(«compile(b)»);
    «ENDFOR»
  }}«ENDIF»'''