Ast transformation
Upcoming SlideShare
Loading in...5
×
 

Ast transformation

on

  • 1,761 views

Groovy's AST Transformation is a compile time meta-programming technique and allows developer to hook into compilation process and add new fields or methods, or modify existing methods.

Groovy's AST Transformation is a compile time meta-programming technique and allows developer to hook into compilation process and add new fields or methods, or modify existing methods.

Statistics

Views

Total Views
1,761
Views on SlideShare
1,761
Embed Views
0

Actions

Likes
0
Downloads
18
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Ast transformation Ast transformation Presentation Transcript

  • Meta-Programming with ASTTransformations in GroovyGagan AgrawalXebia
  • AgendaMeta-Programming with AST TransformationWhat ?How ?Why ?
  • Metaprogramming View slide
  • What is MetaprogrammingIs the writing of computer programs that write ormanipulate other programsMinimizes the number of lines of code to expressa solutionReduces development timeCould be Run-time or Compile-timeGroovyRun-Time : MetaClassCompile-Time : AST Transformations View slide
  • Concrete Syntax Tree
  • Concrete Syntax TreeIs a representation of grammar in a tree-like form.Is a one-to-one mapping from the grammar to atree-form.
  • Concrete Syntax TreeExample in Creturn a+2;
  • Abstract Syntax Tree
  • Abstract Syntax TreeIs a tree representation of the abstract syntacticstructure of source codeEach node of the tree denotes a construct insource codeAbstract – Does not represent every detail thatappears in the real syntaxE.g.Parentheses are implicitSemicolon ; is discarded
  • Abstract Syntax Treereturn a+2;
  • AST Transformation
  • AST TransformationsCompile-time metaprogrammingAllows developers to hook into the compilationprocessTo modify Abstract Syntax Tree before bytecodegenerationPerformance is better than Run-timemetaprogramming
  • AST TransformationCompiler Phases Initialization : Source files are opened and environment configured Parsing : The grammar is used to produce tree of tokens representing the source code Conversion : An Abstract Syntax Tree(AST) is created from token trees Semantic Analysis : Performs consistency and validity checks that the grammar cant check for and resolves classes
  • AST TransformationCompiler Phases : Canonicalization: Complete the AST Instruction Selection : instruction set is choosen, e.g. Java5 or pre Java5 Class Generation : creates binary output in memory Output : Write the binary output to the file system Finalization : Perform any last cleanup
  • Expressions, Statements and Blocks
  • ExpressionsAn expression is a construct made up of variables,operators and method invocationsEvaluates to a single valueE.g. 2+3 evaluates to 5A variable is an expression because it denotes avalue in memory int var = 0;
  • Expression Compound Expression 1*2*3 x+y/100 (x+y)/100 Other Types Cast Expression - (int c = (int)d) Constant Expression – (null, true, false) Field Expression – (this.foo) Method Call Expression – (object.method()) Boolean Expression - (value1==value2)
  • StatementsRoughly equivalent to sentences in naturallanguages.Forms a complete unit of execution.TypesExpression StatementsDeclaration StatementsControl Flow Statements
  • Expression StatementsCreated by terminating expression withsemicolon (;)Assignment StatementaValue = 8933.234;Increment StatementaValue++;Method Invocation StatementSystem.out.println("Hello World!");Object Creation StatementBicycle myBike = new Bicycle();
  • Declaration and Control flow StatementsDeclaration Statementsdouble aValue = 8933.234;Control flow StatementsIf-then and if-then-else StatementsSwitch StatementsWhile and do-while StatementsFor Statements
  • Block StatementsA block is a group of zero or more statementsbetween balanced bracesCan be used anywhere a single statement isallowed.
  • Block Statementsclass BlockDemo { public static void main(String[] args) { boolean condition = true; if (condition) { // begin block 1 System.out.println("Condition is true."); } // end block one else { // begin block 2 System.out.println("Condition is false."); } // end block 2 } }
  • AST Building Blocks
  • AST Building BlocksAST can be transformed in one of the two waysCore AST APIsASTBuilder
  • Core AST APIs
  • Core AST APIs A S T No d e A n n o ta te d No d e G e n e r ic s T y p e M o d u le N o d e Sta te m e nt E x p r e s s io n
  • Core AST APIsASTNodeBase class for any AST node.This class supports basic information used in all nodes ofthe ASTLine and column number information.Meta data of a nodeA phase operation or transform can use this to transport arbitraryinformation to another phase operation or transform providedtransform runs after the part storing the information.
  • Core AST APIs - ExpressionExpressionBooleanExpressionCastExpressionConstantExpressionConstructorCallExpressionFieldExpressionMethodCallExpressionStaticMethodCallExpressionVariableExpression
  • Core AST APIs - Expression this.println(message) can be represented as- new MethodCallExpression( new VariableExpression("this"), new ConstantExpression("println"), new ArgumentListExpression( new ConstantExpression(message) ) )
  • Core AST API - Statement StatementBlockStatementSwitchStatementCaseStatementBreakStatementExpressionStatementIfStatementTryCatchStatementWhileStatementReturnStatement
  • Core AST API - Statement this.println(message) can be represented as- return new ExpressionStatement( new MethodCallExpression( new VariableExpression("this"), new ConstantExpression("println"), new ArgumentListExpression( new ConstantExpression(message) ) ) )
  • AST Builder
  • AST BuilderThree ways to build AST via ASTBuilderBuild From StringsBuild From CodeBuild From a DSL-like Specification
  • Building AST From String def builder = new AstBuilder() List<ASTNode> nodes = builder.buildFromString( CompilePhase.SEMANTIC_ANALYSIS, true, """ this.println(Hello World) """ )
  • Building AST From StringPhase parameter tells AST from which phase toreturn AST. "statementsOnly" boolean parameter tells thebuilder to discard the generated top level ScriptClassNode. String paramter is the input The builder returns List<ASTNode>
  • Building AST From StringProduces following ASTBlockStatement-> ExpressionStatement -> MethodCallExpression -> VariableExpression -> ConstantExpression -> ArgumentListExpression -> ConstantExpression
  • Building AST From StringAdvantagesDoes not require author to understand ASTNode subtypesAllows author to target a CompilePhaseCommunicates source code being generatedRobust - Should need no changes even if AST is updated inrelease
  • Building AST From StringDisadvantagesIDE can not check syntax or grammarIDE can not refactor across StringSome entities cannot be created, like the AST for a fielddeclaration
  • Building AST From Code def builder = new AstBuilder() List<ASTNode> nodes = builder.buildFromCode( CompilePhase.SEMANTIC_ANALYSIS, true){ println "Hello World" }
  • Building AST From CodeProduces following AST BlockStatement -> ExpressionStatement -> MethodCallExpression -> VariableExpression -> ConstantExpression -> ArgumentListExpression -> ConstantExpression
  • Building AST From CodeAdvantagesClearly communicates source being generatedDoes not require author to understand ASTNode subtypesAllows author to target a CompilePhaseRobust - Should need no changes even if AST is updated ina releaseIDE supports syntax checking and refactoring in Closure
  • Building AST From CodeDisadvantages Some entities cannot be created, like the AST for a fielddeclaration
  • Building AST From DSL-like Specification List<ASTNode> nodes = new AstBuilder().buildFromSpec{ block{ expression { methodCall { variable this constant println argumentList { if(locale == US) constant Hello if(locale == FR) constant Bonjour else constant "Ni hao" } } } } }
  • Building AST From DSL-like SpecificationAdvantagesAllows conditionals (or any Groovy code) to be executedduring the AST building process.Allows any ASTNode subtype to be createdFully documented with lengthy examples in TestCase
  • Building AST From DSL-like SpecificationDisadvantagesIt can be difficult to determine what AST you need towriteVerbose - does not always communicate the source beingcreatedFragile - AST may need to change between major releasesIDE does not yet provide code tips
  • AST TransformationTwo types of AST TransformationsLocal TransformationsGlobal Transformations
  • Local AST TransformationsCan be applied on a per class basis.Can only be applied at semantic analysis or laterphasesAnnotation Driven@Retention - Retention Policy should be SOURCE@Target – Can be Method, Field, Constructor ..//need toverify@GroovyASTTransformationClass
  • Local AST TransformationsLogging Example @Retention(RetentionPolicy.SOURCE) @Target([ElementType.METHOD]) @GroovyASTTransformationClass("LoggingASTTrans formation") @interface WithLogging { }
  • Local AST Transformations @GroovyASTTransformation(phase=CompilePhase. SEMANTIC_ANALYSIS) class LoggingASTTransformation implements ASTTransformation{ @Override public void visit(ASTNode[] nodes, SourceUnit source) { ..... } }
  • Local AST TransformationsUsage class TestAst { @WithLogging void testMethod(){ println "This is test Method" } }
  • Global AST TransformationsGlobal transformations are applied to by thecompiler on the code being compiled, whereverthe transformation apply.A JAR should be added to the classpath of thecompilerIt should contain a service locator file at META-INF/services/org.codehaus.groovy.transform.ASTTransformationFile should have a line with the name of thetransformation class
  • Global AST TransformationsThe transformation class must have a no-argsconstructor and implement theorg.codehaus.groovy.transform.ASTTransformation interfaceIt will be run against every source in thecompilation
  • Global AST Transformation Example
  • Global AST TransformationSummaryWrite an ASTTransformation subclassCreate a Jar metadata file containing the name of yourASTTransformationCreate a Jar containing the class and metadataInvoke groovyc with that Jar on your classpath.
  • Built-in Annotations
  • @DelegateWith @Delegate annotation, a class field becomesan object to which method calls are delegated.Example class Event{ @Delegate Date when String title, url }
  • @Delegate Groovy compiler adds all of Dates methods to theEvent class. Behind the scene methods simply delegate thecall to Date field.
  • @Singleton class T { private static volatile T instance private T() {} static T getInstance () { if (instance) { instance } else { synchronized(T) { if (instance) { instance } else { instance = new T () } } } } }
  • @Singleton @Singleton class T { //properties... //methods.. }
  • @ImmutableNo mutators (methods that modify internal state)Class must be finalFields must be private and finalequals, hashCode and toString must beimplemented in terms of the fields if you want tocompare your objects or use them as keys in e.g.maps
  • @ImmutableJava code requires lot of boiler plate code.Groovy requires only annotation @Immuatable onclass @Immutable final class Person { String first String last }
  • @PackageScope class PackageScopeExample { @PackageScope String name }
  • @Lazy class LazyExample { @Lazy pets = [Cat, Dog, Bird] static main(args){ def example = new LazyExample() println "Pets intialized : "+example.dump().contains(Cat) println "List size : "+example.pets.size() println "Pets intialized : "+example.dump().contains(Cat) } }
  • @NewifyRuby Approach @Newify([Integer]) void test(){ println Integer.new(23) }
  • @NewifyPython Approach class Tree { def elements Tree(Object... elements) { this.elements = elements as List } } class Leaf { def value Leaf(value) { this.value = value } }
  • @Newify def buildTree() { new Tree(new Tree(new Leaf(1), new Leaf(2)), new Leaf(3)) } @Newify([Tree, Leaf])def buildTree() { Tree(Tree(Leaf(1), Leaf(2)), Leaf(3)) }
  • @Category interface Vehicle{ String getName() } @Category(Vehicle) class FlyingAbility{ def fly(){ "I am ${name} and I fly" } }
  • @Mixin @Category(Vehicle) class DrivingAbility{ def drive(){ "I am ${name} and I drive" } } @Mixin([DrivingAbility, FlyingAbility]) class JamesBondVehicle implements Vehicle{ public String getName(){ "James Bond Vehicle" } }
  • Where AST Transformations are used?Grails 2.0GormTransformerControllerActionTransformerControllerTransformerGormToJpaTransformerSpock frameworkGrails PluginsAudit-Trail PluginRich Domain Classes PluginRedis PluginNeo4j Plugin
  • Thank You