Groovy AST Transformations


Published on

Introduction to Groovy AST Transformations for Detroit JUG January 2013

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Grails – MVC framework with controllers and service classes in Groovy Griffon – Grails-like application framework for developing rich desktop applications Gaelyk – lightweight Groovy toolkit for building and deploying applications on Google App Engine Easyb – test specifications written in Groovy
  • Gant – tool for scripting Ant tasks using Groovy instead of XML to specify logic Gradle – enterprise-grade build system - Groovy build scripts - Dependency management - Used by hibernate, Grails, Groovy
  • This AST is a rooted tree made up of nodes that describes the various constructs within source code in a form that can be easily processed using the Visitor design pattern ( ). The Visitor design pattern essentially constructs a visitor object that traverses the tree and performs some action on each node in the tree.
  • Focus on automating repetative task of writing common methods likequals, hashCode and constructors
  • Verify using javap on OwnerClass
  • - Shorthand notation for every ASTNode type - API simplified - Helps eliminates some verbosity and complexity - Returns script class node as well - desired AST in first entry
  • Groovy AST Transformations

    1. 1. Groovy AST Transformations
    2. 2. What is Groovy?● A dynamic programming language that runs on the JVM● Language is essentially a superset of Java, in fact grammar to parse Groovy is constructed from Java grammar● Groovy source code is translated into Java bytecode by the Groovy compiler for execution on the JVM
    3. 3. Where is Groovy?● Groovy as a scripting language● Frameworks for application development ● Grails – Web framework ● Griffon – Swing applications ● Gaelyk – Google App Engine● Testing ● Easyb – Behavior Driven Development ● Spock – BDD and mocking ● Gmock - Mocking
    4. 4. Where is Groovy? (cont...)● Building projects ● Gradle ● Gant
    5. 5. How does Groovy code become bytcode?
    6. 6. What is an Abstract Syntax Tree?● Rooted tree of nodes● Composed of nodes that correspond to Groovy language constructs● We are interested in Groovys AST syntax tree● Composed of ASTNodes from the org.codehaus.groovy.ast package and subpackages● Tree structure lends itself to processing using Visitor design pattern
    7. 7. What is an AST Transformation?● Compiler hook Groovy provides into compilation process● Means of extending language without grammar changes● Allows manipulation of AST during compilation prior to bytecode generation● Two types ● Local ● Global
    8. 8. Local AST Transformations● More common● Applied to specific declarations whose AST is to be modified by the transformation● Annotation indicates AST transformation should be applied to declaration● AST is walked and AST transformation applied to nodes that are annotated with transformation annotation (Visitor design pattern)● Many supplied with Groovy distribution
    9. 9. Global AST Transformations● Less common● Applied to every source unit in compilation● Uses jar file service provider mechanism to identify global AST transformations● Jar file added to classpath of compiler that contains service locator file identifying name of class that implements AST transformation
    10. 10. Groovys Built-in AST Transformations● Code generation● Design pattern implementation● Simplified logging● Concurrency support● Cloning and externalization● JavaBeans support● Script safety● Static typing● Miscellaneous
    11. 11. Code Generation● @ToString● @EqualsAndHashCode● @TupleConstructor● @Canonical● @Lazy● @InheritConstructors
    12. 12. Example - @ToString@groovy.transform.ToStringclass Person { String first, last}def person = new Person(first:"Hamlet", last:"DArcy")println "${person.toString()}"Result with @ToString transformation:Person(Hamlet, DArcy)Result without @ToString transformation:Person@175078b
    13. 13. Design Pattern Implementation● @Delgate● @Singleton● @Immutable● @Mixin● @Category
    14. 14. Example - @Delegateclass Delegate1Class { public void method1() {} public void method2(String p) {}}public class OwnerClass { @Delegate Delegate1Class delegate1 = new Delegate1Class()}The @Delegate AST transformation implements delegation byadding all of the public methods from the delegate class to theowner class.
    15. 15. Simplified Logging● @Log● @Log4j● @Slf4j● @Commons
    16. 16. Concurrency Support● @Synchronized● @WithReadLock● @WithWriteLock
    17. 17. Cloning and Externalization● @AutoClone● @AutoExternalize
    18. 18. JavaBeans Support● @Bindable● @Vetoable● @ListenerList
    19. 19. Scripting Safety● @TimedInterrupt● @ThreadInterrupt● @ConditionalInterrupt
    20. 20. Static Typing● @TypeChecked● @CompileStatic
    21. 21. Example - @TypeChecked@groovy.transform.TypeCheckedNumber test() { // Cannot find matching method MyMethod() // Variable is undelcared println myField // Cannot assign String to int int object = "myString" // Cannot return value of type String on method returning type Number return "myString"}
    22. 22. Miscellaneous● @Field● @PackageScope● @Newify
    23. 23. Location of Built-in AST Transformations● Annotation definition usually found in groovy.transform or groovy.lang● Implementation class usually found in org.codehaus.groovy.transform
    24. 24. Custom AST Transformations● Defined in exactly same manner as built-in AST transformations● Steps 1. Create AST transformation implementation class that implements the ASTTransformation interface 2. Create AST transformation annotation declaration and link it to the implementation class with the @GroovyASTTransformationClass annotation
    25. 25. The Implementation Class● Implements the ASTTransformation interface ● Single method void visit(ASTNode nodes[], SourceUnit source)● Compiler invokes this method on AST of annotated element● nodes array contains AnnotationNode for AST transformation annotation and AnnotatedNode corresponding to annotated declaration
    26. 26. HelloWorldASTTransformation@GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)public class HelloWorldASTTransformation implements ASTTransformation { public void visit(ASTNode[] nodes, SourceUnit source) { MethodNode methodNode = (MethodNode)nodes[1] Statement methodCode = methodNode.getCode() // // Add greeting to beginning of code block. // methodCode.getStatements().add(0, createPrintlnStatement()) }
    27. 27. The Annotation Type Declaration● Indicate declaration types to which AST transformation is applicable with @Target annotation● Indicate implementation class with @GroovyASTTransformationClass annotation
    28. 28. HelloWorld@Target([ElementType.METHOD])@GroovyASTTransformationClass("HelloWorldASTTransformation")public @interface HelloWorld {}
    29. 29. HelloWorldExample@HelloWorldvoid myMethod() {}myMethod()
    30. 30. The Hard Part – Creating AST objects● Tools to help ● AST Browser ● ASTBuilder● Ways to create AST objects ● Manually using ASTNode subclass constructors (leveraging AST Browser) ● Using ASTBuilder.buildFromSpec ● Using ASTBuilder.buildFromString ● Using ASTBuilder.buildFromCode
    31. 31. Implementing createPrintlnStatement Manuallyprivate Statement createPrintlnStatement() { Statement printlnStatement = new ExpressionStatement( new MethodCallExpression( new VariableExpression("this"), new ConstantExpression("println"), new ArgumentListExpression( new ConstantExpression("Hello World!!!!")) )) return printlnStatement}
    32. 32. Implementing createPrintlnStatement using buildFromSpec private Statement createPrintlnStatement() { List<ASTNode> results = new AstBuilder().buildFromSpec { expression { methodCall { variable "this" constant "println" argumentList { constant "Hello World!!!!" } } } } return results[0] }
    33. 33. Implementing createPrintlnStatement using buildFromStringprivate Statement createPrintlnStatement() { List<ASTNode> result = new AstBuilder().buildFromString("println Hello World!!!!; return") return result[0]}
    34. 34. Implementing createPrintlnStatement using buildFromCodeprivate Statement createPrintlnStatement() { List<ASTNode> result = new AstBuilder().buildFromCode { println "Hello World!!!!" return } return result[0]}
    35. 35. Resources● Groovy code itself provides excellent examples● AST Browser is invaluable for seeing what code is generated by a transformation● Groovy in Action (2nd edition) in MEAP – Chapter 9 written by Hamlet DArcy● Unit tests for ASTBuilder● Shameless plug: Groovy Under the Hood in GroovyMag