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

时间:2015-01-06 12:41:29

标签: java code-generation dsl xtext xtend

我已经使用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。但是,如何创建有效的唯一变量名而不是使用用户的输入(可能无效)?任何帮助表示赞赏,谢谢。

1 个答案:

答案 0 :(得分:1)

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

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»'''