ceran
ceran

Reputation: 1412

Using unique variable names in Xtend loop (Code Generation)

I've created a custom DSL with Xtext which is useful to describe hierarchies (fixed height of 2 in this example). Want I want to do now is to generate a simple Java Swing App that can display such an hierarchy using a JTree. I did this by extending the code generation example from Xtext, using Xtend. Everything works fine, but could be done better.

The part of my template which is quite ugly so far:

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

As you can see, I use the names of the entities defined by users of the DSL as variable names for the code generation, which is bad. If a user chooses a name that is not a valid variable name in Java, the application won't compile later on.

The reason I did this is because when creating the JTree and its Nodes, I need unique variable names. The generated code looks something like this:

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);
...

Since everything is in the same scope, the variable names need to be different - a, a1, a2 and a3 this case. But how could I create valid unique variable names instead of using the input from users (which could be invalid)? Any help is appreciated, thanks.

Upvotes: 0

Views: 347

Answers (1)

Jan Koehnlein
Jan Koehnlein

Reputation: 211

You need artificial variable names for the nodes and a counter variable. The easiest way is to add that as a field to your generator and reset it before calling the compile method.

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

If you can spare the variable names, I'd prefer generating code using Java's lesser known non-static initializers as they reflect the structure of the tree in the Java code, e.g.

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

by the very simple generator

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

Upvotes: 1

Related Questions