Sunday, October 25, 2009

The True and False of Groovy's AST Builder

Last week saw three(!) conference sessions on Groovy AST Transformations. At SpringOne2gx I started with an AST Transform deep dive, Venkat followed up with a more gentle, and better performed, overview of Transforms, and I finished out with a video taped AST talk at StrangeLoop (watch infoQ for the video).

At the sessions there was some confusion about the API of the new AstBuilder in Groovy 1.7 (currently in RC1). Hopefully this post can clear that up.

The AstBuilder helps you create abstract syntax trees, and the User Guide is the best place to start learning about it. It lets you create the AST for code by simply passing the code into a method:

List<ASTNode> x = new AstBuilder().buildFromCode { " a constant " }
The big question everyone has is, "What's in the List of ASTNodes?"

The question is mostly easily answered by looking at GroovyConsole's AST Browser. Just type in "a constant" into GroovyConsole and press Ctrl+T/Cmd+T to view the AST:


Do you see that there are two root nodes? A BlockStatement and a ClassNode? The reason for this is that all Groovy scripts are compiled into classes of type Script by the compiler. Remember, to the JVM there are no scripts, only classes. If you expand out the AST, you can see that the script (in this case, the ConstantExpression) is in two places in the AST: within the BlockStatement and within the Script#run method:


So this is why the AstBuilder returns a List of ASTNodes. You'll be returned both the script BlockStatement and the Script ClassNode. For the most part, you're probably only interested in the script and not the ClassNode. The boolean parameter on the buildFromCode and buildFromString methods exist so that you don't have to see that ClassNode. The default value of this 'statementsOnly' parameter is true, so be default you'll only be given the script BlockStatements.
List<ASTNode> x = new AstBuilder().buildFromCode { " a constant " }

assert x[0].class == BlockStatement
assert x[1] == null
But when you need it, you can specify 'false', meaning you want the ClassNode as well as the BlockNode:

List<ASTNode> x = new AstBuilder().buildFromCode(
CompilePhase.CONVERSION,
false, // get the ClassNode
{ " a constant " })

assert x[0].class == BlockStatement
assert x[1].class == ClassNode
For a fun, educational exercise, create multiple classes in GroovyConsole and see what the AST looks like. Hopefully you won't be surprised. But please don't enter an anonymous class because then you'll break the AST Browser! (It's a defect in 1.7 RC1 that I promise to fix soon).

Enjoy!

2 comments:

Alex Miller said...

Actually, that's watch "DZone" for Strange Loop video, not InfoQ.

Unknown said...

I am still looking for more information about the topic!
- J.
Web Solutions