Saturday, April 18, 2009

Testing Groovy AST Transformations

There's been a lot of work recently on Groovy AST Transformations, both in the language and on this blog. This post describes two tips for testing your transforms: use the AST Viewer in the GroovyConsole 1.7 snapshot and use a simple test harness with your IDE's debugger.

The AST Viewer in the 1.7 version of GroovyConsole shows you the AST generated from your script. It is an easy way to explore the AST generated by the language and your transformation. Just write your script as normal, and open the viewer with the Inspect AST option under the Script menu. You don't need to run the script even. Here is a sample script:

And here is the AST viewer:
The instance field synthesized by the @Singleton annotation is highlighted in the grid. The tree view shows all the ClassNode and ScriptNodes that were generated and you can expand the tree to see all the descendents.

As you can see, you can select the CompilePhase you compile to, and since the window is non modal you can make script edits and click the Refresh button to redisplay the results. As you click nodes in the AST viewer, the code that generated that node is highlighted back in the main console window. It's literally minutes of entertainment to write a script and click the nodes, watching how the source code contributes to the result. Fun stuff!

This feature is in 1.7 which right now is still in beta. That's OK, it's easy to get 1.7 Just go to the continuous integration website: http://build.canoo.com/groovy/. Just click "Build Artifacts" then "Deliverables". You'll want to download the groovy-all jar file.

My other tip is to use a small test harness to debug your transformation within the IDE. The following code gives you a small function to compile code in process, so any breakpoints in your transformation will be triggered. Just pass the function a File object of your sample script and the CompilePhase you're targeting. Any dependencies in your target script will still be valid during this test execution.

import org.codehaus.groovy.control.CompilationUnit
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.CompilerConfiguration

private void compile(String script, CompilePhase compilePhase) {
def scriptName = "script" + System.currentTimeMillis() + ".groovy"
GroovyClassLoader classLoader = new GroovyClassLoader()
GroovyCodeSource codeSource = new GroovyCodeSource(script, scriptName, "/groovy/script")
CompilationUnit cu = new CompilationUnit(CompilerConfiguration.DEFAULT, codeSource.codeSource, classLoader)
cu.addSource(codeSource.getName(), codeSource.getInputStream());
cu.compile(compilePhase.getPhaseNumber())
}

def file = new File("/path/to/Tester.groovy")
compile(file.text, CompilePhase.SEMANTIC_ANALYSIS)
There are definitely more tools coming, like the AstBuilder objects designed for 1.7. The builders are still in development and I'd love to hear your feedback on the GEP. Email me or the dev list with feedback.

Also, I'll be presenting on "Groovy Compile Time Metaprogramming" at the June CapJUG group in Madison, Wisconsin. It'd be great to see you!

1 comment:

Mazhar Hussain Shah said...

Hi,

Thanks for the info,you have such a nice blog.According to my reading it is really helpful,allthouh it may sound like a good idea to extend the syntax of Groovy to implement new features.

Thanks for sharing.
Web Design Quote.