You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/20 04:29:20 UTC

[12/47] groovy git commit: Move source files to proper packages

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy b/src/main/groovy/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy
new file mode 100644
index 0000000..e033af8
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy
@@ -0,0 +1,1080 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.builder
+
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.ConstructorNode
+import org.codehaus.groovy.ast.DynamicVariable
+import org.codehaus.groovy.ast.FieldNode
+import org.codehaus.groovy.ast.GenericsType
+import org.codehaus.groovy.ast.ImportNode
+import org.codehaus.groovy.ast.InnerClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.MixinNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.PropertyNode
+import org.codehaus.groovy.ast.VariableScope
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ArrayExpression
+import org.codehaus.groovy.ast.expr.AttributeExpression
+import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.BitwiseNegationExpression
+import org.codehaus.groovy.ast.expr.BooleanExpression
+import org.codehaus.groovy.ast.expr.CastExpression
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.ClosureListExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression
+import org.codehaus.groovy.ast.expr.DeclarationExpression
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.FieldExpression
+import org.codehaus.groovy.ast.expr.GStringExpression
+import org.codehaus.groovy.ast.expr.ListExpression
+import org.codehaus.groovy.ast.expr.MapEntryExpression
+import org.codehaus.groovy.ast.expr.MapExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.MethodPointerExpression
+import org.codehaus.groovy.ast.expr.NamedArgumentListExpression
+import org.codehaus.groovy.ast.expr.NotExpression
+import org.codehaus.groovy.ast.expr.PostfixExpression
+import org.codehaus.groovy.ast.expr.PrefixExpression
+import org.codehaus.groovy.ast.expr.PropertyExpression
+import org.codehaus.groovy.ast.expr.RangeExpression
+import org.codehaus.groovy.ast.expr.SpreadExpression
+import org.codehaus.groovy.ast.expr.SpreadMapExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression
+import org.codehaus.groovy.ast.expr.TernaryExpression
+import org.codehaus.groovy.ast.expr.TupleExpression
+import org.codehaus.groovy.ast.expr.UnaryMinusExpression
+import org.codehaus.groovy.ast.expr.UnaryPlusExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.AssertStatement
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.BreakStatement
+import org.codehaus.groovy.ast.stmt.CaseStatement
+import org.codehaus.groovy.ast.stmt.CatchStatement
+import org.codehaus.groovy.ast.stmt.ContinueStatement
+import org.codehaus.groovy.ast.stmt.EmptyStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.ForStatement
+import org.codehaus.groovy.ast.stmt.IfStatement
+import org.codehaus.groovy.ast.stmt.ReturnStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.ast.stmt.SwitchStatement
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement
+import org.codehaus.groovy.ast.stmt.ThrowStatement
+import org.codehaus.groovy.ast.stmt.TryCatchStatement
+import org.codehaus.groovy.ast.stmt.WhileStatement
+import org.codehaus.groovy.runtime.MethodClosure
+import org.codehaus.groovy.syntax.Token
+import org.codehaus.groovy.syntax.Types
+
+/**
+ * Handles parsing the properties from the closure into values that can be referenced.
+ * 
+ * This object is very stateful and not threadsafe. It accumulates expressions in the 
+ * 'expression' field as they are found and executed within the DSL. 
+ * 
+ * Note: this class consists of many one-line method calls. A better implementation
+ * might be to take a declarative approach and replace the one-liners with map entries. 
+ * 
+ * @author Hamlet D'Arcy
+ */
+class AstSpecificationCompiler implements GroovyInterceptable {
+
+    private final List<ASTNode> expression = []
+
+    /**
+     * Creates the DSL compiler.
+     */
+    AstSpecificationCompiler(@DelegatesTo(AstSpecificationCompiler) Closure spec) {
+        spec.delegate = this
+        spec()
+    }
+
+    /**
+     * Gets the current generated expression.
+     */
+    List<ASTNode> getExpression() {
+        return expression
+    }
+
+    /**
+    * This method takes a List of Classes (a "spec"), and makes sure that the expression field 
+    * contains those classes. It is a safety mechanism to enforce that the DSL is being called
+    * properly. 
+    * 
+    * @param methodName
+    *   the name of the method within the DSL that is being invoked. Used in creating error messages. 
+    * @param spec
+    *   the list of Class objects that the method expects to have in the expression field when invoked.
+    * @return 
+    *   the portions of the expression field that adhere to the spec. 
+    */ 
+    private List<ASTNode> enforceConstraints(String methodName, List<Class> spec) {
+
+        // enforce that the correct # arguments was passed
+        if (spec.size() != expression.size()) {
+            throw new IllegalArgumentException("$methodName could not be invoked. Expected to receive parameters $spec but found ${expression?.collect { it.class }}")
+        }
+
+        // enforce types and collect result
+        (0..(spec.size() - 1)).collect { int it ->
+            def actualClass = expression[it].class
+            def expectedClass = spec[it]
+            if (!expectedClass.isAssignableFrom(actualClass)) {
+                throw new IllegalArgumentException("$methodName could not be invoked. Expected to receive parameters $spec but found ${expression?.collect { it.class }}")
+            }
+            expression[it]
+        }
+    }
+
+    /**
+    * This method helps you take Closure parameters to a method and bundle them into 
+    * constructor calls to a specific ASTNode subtype. 
+    * @param name 
+    *       name of object being constructed, used to create helpful error message. 
+    * @param argBlock
+    *       the actual parameters being specified for the node
+    * @param constructorStatement
+    *       the type specific construction code that will be run
+    */ 
+    private void captureAndCreateNode(String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, Closure constructorStatement) {
+        if (!argBlock) throw new IllegalArgumentException("nodes of type $name require arguments to be specified")
+
+        def oldProps = new ArrayList(expression)
+        expression.clear()
+        new AstSpecificationCompiler(argBlock)
+        def result = constructorStatement(expression) // invoke custom constructor for node
+        expression.clear()
+        expression.addAll(oldProps)
+        expression.add(result)
+    }
+
+    /**
+    * Helper method to convert a DSL invocation into an ASTNode instance. 
+    * 
+    * @param target     
+    *       the class you are going to create
+    * @param typeAlias  
+    *       the DSL keyword that was used to invoke this type
+    * @param ctorArgs   
+    *       a specification of what arguments the constructor expects
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    */ 
+    private void makeNode(Class target, String typeAlias, List<Class<? super ASTNode>> ctorArgs, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            target.newInstance(*enforceConstraints(typeAlias, ctorArgs))
+        }
+    }
+
+    /**
+    * Helper method to convert a DSL invocation with a list of parameters specified 
+    * in a Closure into an ASTNode instance. 
+    * 
+    * @param target     
+    *       the class you are going to create
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    */ 
+    private void makeNodeFromList(Class target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        //todo: add better error handling?
+        captureAndCreateNode(target.simpleName, argBlock) {
+            target.newInstance(new ArrayList(expression))
+        }
+    }
+
+    /**
+    * Helper method to convert a DSL invocation with a String parameter into a List of ASTNode instances. 
+    * 
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    * @param input   
+    *       the single String argument used during invocation
+    */ 
+    private void makeListOfNodes(@DelegatesTo(AstSpecificationCompiler) Closure argBlock, String input) {
+        captureAndCreateNode(input, argBlock) {
+            new ArrayList(expression)
+        }
+    }
+
+    /**
+    * Helper method to convert a DSL invocation with a String parameter into an Array of ASTNode instances. 
+    * 
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    * @param target   
+    *       the target type
+    */ 
+    private void makeArrayOfNodes(Object target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            expression.toArray(target)
+        }
+    }
+    
+    /**
+    * Helper method to convert a DSL invocation into an ASTNode instance when a Class parameter is specified. 
+    * 
+    * @param target     
+    *       the class you are going to create
+    * @param alias  
+    *       the DSL keyword that was used to invoke this type
+    * @param spec
+    *       the list of Classes that you expect to be present as parameters
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    * @param type 
+    *       a type parameter
+    */ 
+    private void makeNodeWithClassParameter(Class target, String alias, List<Class> spec, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, Class type) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            expression.add(0, ClassHelper.make(type))
+            target.newInstance(*enforceConstraints(alias, spec))
+        }
+    }
+
+    private void makeNodeWithStringParameter(Class target, String alias, List<Class> spec, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, String text) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            expression.add(0, text)
+            target.newInstance(*enforceConstraints(alias, spec))
+        }
+    }
+
+    /**
+     * Creates a CastExpression.
+     */
+    void cast(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeWithClassParameter(CastExpression, 'cast', [ClassNode, Expression], argBlock, type)
+    }
+
+    /**
+     * Creates an ConstructorCallExpression.
+     */
+    void constructorCall(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeWithClassParameter(ConstructorCallExpression, 'constructorCall', [ClassNode, Expression], argBlock, type)
+    }
+
+    /**
+     * Creates a MethodCallExpression.
+     */
+    void methodCall(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(MethodCallExpression, 'methodCall', [Expression, Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates an AnnotationConstantExpression.
+     */
+    void annotationConstant(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(AnnotationConstantExpression, 'annotationConstant', [AnnotationNode], argBlock)
+    }
+
+    /**
+     * Creates a PostfixExpression.
+     */
+    void postfix(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(PostfixExpression, 'postfix', [Expression, Token], argBlock)
+    }
+
+    /**
+     * Creates a FieldExpression.
+     */
+    void field(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(FieldExpression, 'field', [FieldNode], argBlock)
+    }
+
+    /**
+     * Creates a MapExpression.
+     */
+    void map(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(MapExpression, argBlock)
+    }
+
+    /**
+     * Creates a TupleExpression.
+     */
+    void tuple(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(TupleExpression, argBlock)
+    }
+
+    /**
+     * Creates a MapEntryExpression.
+     */
+    void mapEntry(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(MapEntryExpression, 'mapEntry', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a gString.
+     */
+    void gString(String verbatimText, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeWithStringParameter(GStringExpression, 'gString', [String, List, List], argBlock, verbatimText)
+    }
+
+
+    /**
+     * Creates a methodPointer.
+     */
+
+    void methodPointer(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(MethodPointerExpression, 'methodPointer', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a property.
+     */
+    void property(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(PropertyExpression, 'property', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a RangeExpression.
+     */
+    void range(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(RangeExpression, 'range', [Expression, Expression, Boolean], argBlock)
+    }
+
+    /**
+     * Creates EmptyStatement.
+     */
+    void empty() {
+        expression << EmptyStatement.INSTANCE
+    }
+
+    /**
+     * Creates a label.
+     */
+    void label(String label) {
+        expression << label
+    }
+
+    /**
+     * Creates an ImportNode.
+     */
+    void importNode(Class target, String alias = null) {
+        expression << new ImportNode(ClassHelper.make(target), alias)
+    }
+
+    /**
+     * Creates a CatchStatement.
+     */
+    void catchStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(CatchStatement, 'catchStatement', [Parameter, Statement], argBlock)
+    }
+
+    /**
+     * Creates a ThrowStatement.
+     */
+    void throwStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ThrowStatement, 'throwStatement', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a SynchronizedStatement.
+     */
+    void synchronizedStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(SynchronizedStatement, 'synchronizedStatement', [Expression, Statement], argBlock)
+    }
+
+    /**
+     * Creates a ReturnStatement.
+     */
+    void returnStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ReturnStatement, 'returnStatement', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a TernaryExpression.
+     */
+
+    private void ternary(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(TernaryExpression, 'ternary', [BooleanExpression, Expression, Expression], argBlock)
+    }
+
+
+    /**
+     * Creates an ElvisOperatorExpression.
+     */
+    void elvisOperator(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ElvisOperatorExpression, 'elvisOperator', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a BreakStatement.
+     */
+    void breakStatement(String label = null) {
+        if (label) {
+            expression << new BreakStatement(label)
+        } else {
+            expression << new BreakStatement()
+        }
+    }
+
+    /**
+     * Creates a ContinueStatement.
+     */
+    void continueStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (!argBlock) {
+            expression << new ContinueStatement()
+        } else {
+            makeNode(ContinueStatement, 'continueStatement', [String], argBlock)
+        }
+    }
+
+    /**
+     * Create a CaseStatement.
+     */
+    void caseStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(CaseStatement, 'caseStatement', [Expression, Statement], argBlock)
+    }
+
+    /**
+     * Creates a BlockStatement.
+     */
+    void defaultCase(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        block(argBlock) // same as arg block
+    }
+
+    /**
+     * Creates a PrefixExpression.
+     */
+    void prefix(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(PrefixExpression, 'prefix', [Token, Expression], argBlock)
+    }
+
+    /**
+     * Creates a NotExpression.
+     */
+    void not(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(NotExpression, 'not', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a DynamicVariable.
+     */
+    void dynamicVariable(String variable, boolean isStatic = false) {
+        expression << new DynamicVariable(variable, isStatic)
+    }
+
+    /**
+     * Creates a ClassNode[].
+     */
+    void exceptions(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeArrayOfNodes([] as ClassNode[], argBlock)
+    }
+
+    /**
+     * Designates a list of AnnotationNodes.
+     */
+    void annotations(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<AnnotationNode>")
+    }
+
+
+    /**
+     * Designates a list of MethodNodes.
+     */
+    void methods(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<MethodNode>")
+    }
+
+    /**
+     * Designates a list of ConstructorNodes.
+     */
+    void constructors(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ConstructorNode>")
+    }
+
+    /**
+     * Designates a list of {@code PropertyNode}s.
+     */
+    void properties(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<PropertyNode>")
+    }
+
+    /**
+     * Designates a list of {@code FieldNode}s.
+     */
+    void fields(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<FieldNode>")
+    }
+
+    /**
+     * Designates a list of ConstantExpressions.
+     */
+
+    void strings(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ConstantExpression>")
+    }
+
+    /**
+     * Designates a list of Expressions.
+     */
+
+    void values(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<Expression>")
+    }
+
+    /**
+     * Creates a boolean value.
+     */
+    void inclusive(boolean value) {
+        expression << value
+    }
+
+    /**
+     * Creates a ConstantExpression.
+     */
+    void constant(Object value) {
+        expression << new ConstantExpression(value)
+    }
+
+    /**
+     * Creates an IfStatement.
+     */
+    void ifStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(IfStatement, 'ifStatement', [BooleanExpression, Statement, Statement], argBlock)
+    }
+
+    /**
+     * Creates a SpreadExpression.
+     */
+    void spread(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(SpreadExpression, 'spread', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a SpreadMapExpression.
+     */
+    void spreadMap(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(SpreadMapExpression, 'spreadMap', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a WhileStatement.
+     */
+    void whileStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(WhileStatement, 'whileStatement', [BooleanExpression, Statement], argBlock)
+    }
+
+    /**
+     * Create a ForStatement.
+     */
+    void forStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ForStatement, 'forStatement', [Parameter, Expression, Statement], argBlock)
+    }
+
+    /**
+     * Creates a ClosureListExpression.
+     */
+    void closureList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(ClosureListExpression, argBlock)
+    }
+
+    /**
+     * Creates a DeclarationExpression.
+     */
+    void declaration(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(DeclarationExpression, 'declaration', [Expression, Token, Expression], argBlock)
+    }
+
+    /**
+     * Creates a ListExpression.
+     */
+    void list(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(ListExpression, argBlock)
+    }
+
+    /**
+     * Creates a BitwiseNegationExpression.
+     */
+    void bitwiseNegation(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(BitwiseNegationExpression, 'bitwiseNegation', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a ClosureExpression.
+     */
+    void closure(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ClosureExpression, 'closure', [Parameter[], Statement], argBlock)
+    }
+
+    /**
+     * Creates a BooleanExpression.
+     */
+    void booleanExpression(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(BooleanExpression, 'booleanExpression', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a BinaryExpression.
+     */
+    void binary(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(BinaryExpression, 'binary', [Expression, Token, Expression], argBlock)
+    }
+
+    /**
+     * Creates a UnaryPlusExpression.
+     */
+    void unaryPlus(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(UnaryPlusExpression, 'unaryPlus', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a ClassExpression.
+     */
+    void classExpression(Class type) {
+        expression << new ClassExpression(ClassHelper.make(type))
+    }
+
+    /**
+     * Creates a UnaryMinusExpression
+     */
+    void unaryMinus(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(UnaryMinusExpression, 'unaryMinus', [Expression], argBlock)
+    }
+
+    /**
+     * Creates an AttributeExpression.
+     */
+    void attribute(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(AttributeExpression, 'attribute', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates an ExpressionStatement.
+     */
+    void expression(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ExpressionStatement, 'expression', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a NamedArgumentListExpression.
+     */
+    void namedArgumentList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(NamedArgumentListExpression, argBlock)
+    }
+
+    /**
+     * Creates a ClassNode[].
+     */
+    void interfaces(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ClassNode>")
+    }
+
+    /**
+     * Creates a MixinNode[].
+     */
+    void mixins(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<MixinNode>")
+    }
+
+    /**
+     * Creates a GenericsTypes[].
+     */
+    void genericsTypes(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<GenericsTypes>")
+    }
+
+    /**
+     * Creates a ClassNode.
+     */
+    void classNode(Class target) {
+        expression << ClassHelper.make(target, false)
+    }
+
+    /**
+     * Creates a Parameter[].
+     */
+    void parameters(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeArrayOfNodes([] as Parameter[], argBlock)
+    }
+
+    /**
+     * Creates a BlockStatement.
+     */
+    void block(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("BlockStatement", argBlock) {
+            return new BlockStatement(new ArrayList(expression), new VariableScope())
+        }
+    }
+
+    /**
+     * Creates a Parameter.
+     */
+    void parameter(Map<String, Class> args, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (!args) throw new IllegalArgumentException()
+        if (args.size() > 1) throw new IllegalArgumentException()
+
+        //todo: add better error handling?
+        if (argBlock) {
+            args.each {name, type ->
+                captureAndCreateNode("Parameter", argBlock) {
+                    new Parameter(ClassHelper.make(type), name, expression[0])
+                }
+            }
+        } else {
+            args.each {name, type ->
+                expression << (new Parameter(ClassHelper.make(type), name))
+            }
+        }
+    }
+
+    /**
+     * Creates an ArrayExpression.
+     */
+    void array(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("ArrayExpression", argBlock) {
+            new ArrayExpression(ClassHelper.make(type), new ArrayList(expression))
+        }
+    }
+
+    /**
+     * Creates a GenericsType.
+     */
+    void genericsType(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (argBlock) {
+            captureAndCreateNode("GenericsType", argBlock) {
+                new GenericsType(ClassHelper.make(type), expression[0] as ClassNode[], expression[1])
+            }
+        } else {
+            expression << new GenericsType(ClassHelper.make(type))
+        }
+    }
+
+    /**
+     * Creates a list of upperBound ClassNodes.
+     */
+    void upperBound(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, 'List<ClassNode>')
+    }
+
+    /**
+     * Create lowerBound ClassNode.
+     */
+    void lowerBound(Class target) {
+        expression << ClassHelper.make(target)
+    }
+
+    /**
+     * Creates a 2 element list of name and Annotation. Used with Annotation Members.
+     */
+    void member(String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("Annotation Member", argBlock) {
+            [name, expression[0]]
+        }
+    }
+
+    /**
+     * Creates an ArgumentListExpression.
+     */
+    void argumentList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        if (!argBlock) {
+            expression << new ArgumentListExpression()
+        } else {
+            makeNodeFromList(ArgumentListExpression, argBlock)
+        }
+    }
+
+    /**
+     * Creates an AnnotationNode.
+     */
+    void annotation(Class target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (argBlock) {
+            //todo: add better error handling
+            captureAndCreateNode("ArgumentListExpression", argBlock) {
+                def node = new AnnotationNode(ClassHelper.make(target))
+                expression?.each {
+                    node.addMember(it[0], it[1])
+                }
+                node
+            }
+        } else {
+            expression << new AnnotationNode(ClassHelper.make(target))
+        }
+    }
+
+    /**
+     * Creates a MixinNode.
+     */
+    void mixin(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("AttributeExpression", argBlock) {
+            if (expression.size() > 1) {
+                new MixinNode(name, modifiers, expression[0], new ArrayList(expression[1]) as ClassNode[])
+            } else {
+                new MixinNode(name, modifiers, expression[0])
+            }
+        }
+    }
+
+    /**
+     * Creates a ClassNode
+     */
+    void classNode(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("ClassNode", argBlock) {
+            def result = new ClassNode(name, modifiers,
+                    expression[0],
+                    new ArrayList(expression[1]) as ClassNode[],
+                    new ArrayList(expression[2]) as MixinNode[]
+            )
+            while (expression.size() > 3) {
+                if (!List.isAssignableFrom(expression[3].getClass())) {
+                    throw new IllegalArgumentException("Expecting to find list of additional items instead found: " + expression[3].getClass())
+                }
+                if (expression[3].size() > 0) {
+                    def clazz = expression[3][0].getClass()
+                    switch(clazz) {
+                        case GenericsType:
+                            result.setGenericsTypes(new ArrayList(expression[3]) as GenericsType[])
+                            break
+                        case MethodNode:
+                            expression[3].each{ result.addMethod(it) }
+                            break
+                        case ConstructorNode:
+                            expression[3].each{ result.addConstructor(it) }
+                            break
+                        case PropertyNode:
+                            expression[3].each{
+                                it.field.owner = result
+                                result.addProperty(it)
+                            }
+                            break
+                        case FieldNode:
+                            expression[3].each{
+                                it.owner = result
+                                result.addField(it)
+                            }
+                            break
+                        case AnnotationNode:
+                            result.addAnnotations(new ArrayList(expression[3]))
+                            break
+                        default:
+                            throw new IllegalArgumentException("Unexpected item found in ClassNode spec. Expecting [Field|Method|Property|Constructor|Annotation|GenericsType] but found: $clazz.name")
+                    }
+                }
+                expression.remove(3)
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates an AssertStatement.
+     */
+    void assertStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("AssertStatement", argBlock) {
+            if (expression.size() < 2) {
+                new AssertStatement(*enforceConstraints('assertStatement', [BooleanExpression]))
+            } else {
+                new AssertStatement(*enforceConstraints('assertStatement', [BooleanExpression, Expression]))
+            }
+        }
+    }
+
+    /**
+     * Creates a TryCatchStatement.
+     */
+    void tryCatch(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("TryCatchStatement", argBlock) {
+            def result = new TryCatchStatement(expression[0], expression[1])
+            def catchStatements = expression.tail().tail()
+            catchStatements.each {statement -> result.addCatch(statement) }
+            return result
+        }
+    }
+
+    /**
+     * Creates a VariableExpression.
+     */
+    void variable(String variable) {
+        expression << new VariableExpression(variable)
+    }
+
+    /**
+     * Creates a MethodNode.
+     */
+    void method(String name, int modifiers, Class returnType, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("MethodNode", argBlock) {
+            //todo: enforce contract
+            def result = new MethodNode(name, modifiers, ClassHelper.make(returnType), expression[0], expression[1], expression[2])
+            if (expression[3]) {
+                result.addAnnotations(new ArrayList(expression[3]))
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates a token.
+     */
+    void token(String value) {
+        if (value == null) throw new IllegalArgumentException("Null: value")
+
+        def tokenID = Types.lookupKeyword(value)
+        if (tokenID == Types.UNKNOWN) {
+            tokenID = Types.lookupSymbol(value)
+        }
+        if (tokenID == Types.UNKNOWN) throw new IllegalArgumentException("could not find token for $value")
+
+        expression << new Token(tokenID, value, -1, -1)
+    }
+
+    /**
+     * Creates a RangeExpression.
+     */
+    void range(Range range) {
+        if (range == null) throw new IllegalArgumentException('Null: range')
+        expression << new RangeExpression(new ConstantExpression(range.getFrom()), new ConstantExpression(range.getTo()), true) //default is inclusive
+    }
+
+    /**
+     * Creates a SwitchStatement.
+     */
+    void switchStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("SwitchStatement", argBlock) {
+            def switchExpression = expression.head()
+            def caseStatements = expression.tail().tail()
+            def defaultExpression = expression.tail().head()
+            new SwitchStatement(switchExpression, caseStatements, defaultExpression)
+        }
+    }
+
+    /**
+     * Creates a mapEntry.
+     */
+    void mapEntry(Map map) {
+        map.entrySet().each {
+            expression << new MapEntryExpression(
+                    new ConstantExpression(it.key),
+                    new ConstantExpression(it.value))
+        }
+    }
+
+    //
+    // todo: these methods can still be reduced smaller
+    //
+
+    /**
+     * Creates a FieldNode.
+     */
+    void fieldNode(String name, int modifiers, Class type, Class owner, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("FieldNode", argBlock) {
+            def annotations = null
+            if (expression.size() > 1) {
+                annotations = expression[1]
+                expression.remove(1)
+            }
+            expression.add(0, ClassHelper.make(owner))
+            expression.add(0, ClassHelper.make(type))
+            expression.add(0, modifiers)
+            expression.add(0, name)
+            def result = new FieldNode(*enforceConstraints('fieldNode', [String, Integer, ClassNode, ClassNode, Expression]))
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates an inner class.
+     */
+    void innerClass(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("InnerClassNode", argBlock) {
+            //todo: enforce contract
+            new InnerClassNode(
+                    expression[0],
+                    name,
+                    modifiers,
+                    expression[1],
+                    new ArrayList(expression[2]) as ClassNode[],
+                    new ArrayList(expression[3]) as MixinNode[])
+        }
+    }
+
+    /**
+     * Creates a PropertyNode.
+     */
+    void propertyNode(String name, int modifiers, Class type, Class owner, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        //todo: improve error handling?
+        captureAndCreateNode("PropertyNode", argBlock) {
+            def annotations = null
+            // check if the last expression looks like annotations
+            if (List.isAssignableFrom(expression[-1].getClass())) {
+                annotations = expression[-1]
+                expression.remove(expression.size() - 1)
+            }
+            def result = new PropertyNode(name, modifiers, ClassHelper.make(type), ClassHelper.make(owner),
+                    expression[0],  // initial value (possibly null)
+                    expression[1],  // getter block (possibly null)
+                    expression[2])  // setter block (possibly null)
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates a StaticMethodCallExpression.
+     */
+    void staticMethodCall(Class target, String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("StaticMethodCallExpression", argBlock) {
+            expression.add(0, name)
+            expression.add(0, ClassHelper.make(target))
+            new StaticMethodCallExpression(*enforceConstraints('staticMethodCall', [ClassNode, String, Expression]))
+        }
+    }
+
+    /**
+     * Creates a StaticMethodCallExpression.
+     */
+    void staticMethodCall(MethodClosure target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("StaticMethodCallExpression", argBlock) {
+            expression.add(0, target.method)
+            expression.add(0, ClassHelper.makeWithoutCaching(target.owner.class, false))
+            new StaticMethodCallExpression(*enforceConstraints('staticMethodCall', [ClassNode, String, Expression]))
+        }
+    }
+
+    /**
+     * Creates a ConstructorNode.
+     */
+    void constructor(int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("ConstructorNode", argBlock) {
+            def annotations = null
+            if (expression.size() > 3) {
+                annotations = expression[3]
+                expression.remove(3)
+            }
+            expression.add(0, modifiers)
+            def result = new ConstructorNode(*enforceConstraints('constructor', [Integer, Parameter[], ClassNode[], Statement]))
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/ast/builder/AstStringCompiler.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/ast/builder/AstStringCompiler.groovy b/src/main/groovy/org/codehaus/groovy/ast/builder/AstStringCompiler.groovy
new file mode 100644
index 0000000..1ea3970
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/ast/builder/AstStringCompiler.groovy
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.builder
+
+import groovy.transform.PackageScope
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.ModuleNode
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.CompilerConfiguration
+
+/**
+ * This class handles converting Strings to ASTNode lists.
+ *
+ * @author Hamlet D'Arcy
+ */
+@PackageScope class AstStringCompiler {
+    
+    /**
+     * Performs the String source to {@link List} of {@link ASTNode}.
+     *
+     * @param script
+     *      a Groovy script in String form
+     * @param compilePhase
+     *      the int based CompilePhase to compile it to.
+     * @param statementsOnly
+     */
+    List<ASTNode> compile(String script, CompilePhase compilePhase, boolean statementsOnly) {
+        def scriptClassName = "script" + System.currentTimeMillis()
+        GroovyClassLoader classLoader = new GroovyClassLoader()
+        GroovyCodeSource codeSource = new GroovyCodeSource(script, scriptClassName + ".groovy", "/groovy/script")
+        CompilationUnit cu = new CompilationUnit(CompilerConfiguration.DEFAULT, codeSource.codeSource, classLoader)
+        cu.addSource(codeSource.getName(), script);
+        cu.compile(compilePhase.getPhaseNumber())
+        // collect all the ASTNodes into the result, possibly ignoring the script body if desired
+        return cu.ast.modules.inject([]) {List acc, ModuleNode node ->
+            if (node.statementBlock) acc.add(node.statementBlock)
+            node.classes?.each {
+                if (!(it.name == scriptClassName && statementsOnly)) {
+                    acc << it
+                }
+            }
+            acc
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/classgen/genArrayAccess.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/classgen/genArrayAccess.groovy b/src/main/groovy/org/codehaus/groovy/classgen/genArrayAccess.groovy
new file mode 100644
index 0000000..08cb68a
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/classgen/genArrayAccess.groovy
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen
+
+println """
+package org.codehaus.groovy.runtime.dgmimpl;
+
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ReflectionCache;
+
+public class ArrayOperations {
+  ${genInners()}
+}
+"""
+
+def genInners () {
+    def res = ""
+
+    final Map primitives = [
+            "boolean": "Boolean",
+            "byte": "Byte",
+            "char": "Character",
+            "short": "Short",
+            "int": "Integer",
+            "long": "Long",
+            "float": "Float",
+            "double": "Double"
+    ]
+
+    primitives.each {primName, clsName ->
+        res += """
+         public static class ${clsName}ArrayGetAtMetaMethod extends ArrayGetAtMetaMethod {
+            private static final CachedClass ARR_CLASS = ReflectionCache.getCachedClass(${primName}[].class);
+
+            public Class getReturnType() {
+                return ${clsName}.class;
+            }
+
+            public final CachedClass getDeclaringClass() {
+                return ARR_CLASS;
+            }
+
+            public Object invoke(Object object, Object[] args) {
+                final ${primName}[] objects = (${primName}[]) object;
+                return objects[normaliseIndex(((Integer) args[0]).intValue(), objects.length)];
+            }
+
+            public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+                if (!(args [0] instanceof Integer))
+                  return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
+                else
+                    return new PojoMetaMethodSite(site, metaClass, metaMethod, params) {
+                        public Object invoke(Object receiver, Object[] args) {
+                            final ${primName}[] objects = (${primName}[]) receiver;
+                            return objects[normaliseIndex(((Integer) args[0]).intValue(), objects.length)];
+                        }
+
+                        public Object callBinop(Object receiver, Object arg) {
+                            if ((receiver instanceof ${primName}[] && arg instanceof Integer)
+                                    && checkMetaClass()) {
+                                final ${primName}[] objects = (${primName}[]) receiver;
+                                return objects[normaliseIndex(((Integer) arg).intValue(), objects.length)];
+                            }
+                            else
+                              return super.callBinop(receiver,arg);
+                        }
+
+                        public Object invokeBinop(Object receiver, Object arg) {
+                            final ${primName}[] objects = (${primName}[]) receiver;
+                            return objects[normaliseIndex(((Integer) arg).intValue(), objects.length)];
+                        }
+                    };
+            }
+         }
+
+
+        public static class ${clsName}ArrayPutAtMetaMethod extends ArrayPutAtMetaMethod {
+            private static final CachedClass OBJECT_CLASS = ReflectionCache.OBJECT_CLASS;
+            private static final CachedClass ARR_CLASS = ReflectionCache.getCachedClass(${primName}[].class);
+            private static final CachedClass [] PARAM_CLASS_ARR = new CachedClass[] {INTEGER_CLASS, OBJECT_CLASS};
+
+            public ${clsName}ArrayPutAtMetaMethod() {
+                parameterTypes = PARAM_CLASS_ARR;
+            }
+
+            public final CachedClass getDeclaringClass() {
+                return ARR_CLASS;
+            }
+
+            public Object invoke(Object object, Object[] args) {
+                final ${primName}[] objects = (${primName}[]) object;
+                final int index = normaliseIndex(((Integer) args[0]).intValue(), objects.length);
+                Object newValue = args[1];
+                if (!(newValue instanceof ${clsName})) {
+                    Number n = (Number) newValue;
+                    objects[index] = ((Number)newValue).${primName}Value();
+                }
+                else
+                  objects[index] = ((${clsName})args[1]).${primName}Value();
+                return null;
+            }
+
+            public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+                if (!(args [0] instanceof Integer) || !(args [1] instanceof ${clsName}))
+                  return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
+                else
+                    return new PojoMetaMethodSite(site, metaClass, metaMethod, params) {
+                        public Object call(Object receiver, Object[] args) {
+                            if ((receiver instanceof ${primName}[] && args[0] instanceof Integer && args[1] instanceof ${clsName} )
+                                    && checkMetaClass()) {
+                                final ${primName}[] objects = (${primName}[]) receiver;
+                                objects[normaliseIndex(((Integer) args[0]).intValue(), objects.length)] = ((${clsName})args[1]).${primName}Value();
+                                return null;
+                            }
+                            else
+                              return super.call(receiver,args);
+                        }
+                    };
+            }
+        }
+
+       """
+    }
+
+    res
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/classgen/genArrays.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/classgen/genArrays.groovy b/src/main/groovy/org/codehaus/groovy/classgen/genArrays.groovy
new file mode 100644
index 0000000..9bbe3cf
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/classgen/genArrays.groovy
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen
+
+print """
+
+public class ArrayUtil {
+   ${genMethods()}
+}
+
+"""
+
+def genMethods () {
+    def res = ""
+    for (i in 1..250)
+      res += "\n\n" + genMethod (i)
+    res
+}
+
+def genMethod (int paramNum) {
+    def res = "public static Object [] createArray ("
+    for (k in 0..<paramNum) {
+        res += "Object arg" + k
+        if (k != paramNum-1)
+          res += ", "
+    }
+    res += ") {\n"
+    res += "return new Object [] {\n"
+        for (k in 0..<paramNum) {
+            res += "arg" + k
+            if (k != paramNum-1)
+              res += ", "
+        }
+        res += "};\n"
+    res += "}"
+    res
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/classgen/genDgmMath.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/classgen/genDgmMath.groovy b/src/main/groovy/org/codehaus/groovy/classgen/genDgmMath.groovy
new file mode 100644
index 0000000..71bdd5f
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/classgen/genDgmMath.groovy
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen
+
+def types = ["Integer", "Long", "Float", "Double"]
+
+def getMath (a,b) {
+    if (a == "Double" || b == "Double" || a == "Float" || b == "Float")
+      return "FloatingPointMath"
+
+    if (a == "Long" || b == "Long")
+      return "LongMath"
+
+    "IntegerMath"
+}
+
+println """
+public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+    NumberMath m = NumberMath.getMath((Number)receiver, (Number)args[0]);
+"""
+
+types.each {
+    a ->
+    print """
+    if (receiver instanceof $a) {"""
+    types.each {
+        b ->
+        print """
+        if (args[0] instanceof $b)
+            return new NumberNumberCallSite (site, metaClass, metaMethod, params, (Number)receiver, (Number)args[0]){
+                public final Object invoke(Object receiver, Object[] args) {
+                    return ${getMath(a,b)}.INSTANCE.addImpl(($a)receiver,($b)args[0]);
+                }
+
+                public final Object invokeBinop(Object receiver, Object arg) {
+                    return ${getMath(a,b)}.INSTANCE.addImpl(($a)receiver,($b)arg);
+                }
+            };
+        """
+    }
+    println "}"
+}
+
+println """
+    return new NumberNumberCallSite (site, metaClass, metaMethod, params, (Number)receiver, (Number)args[0]){
+        public final Object invoke(Object receiver, Object[] args) {
+            return math.addImpl((Number)receiver,(Number)args[0]);
+        }
+
+        public final Object invokeBinop(Object receiver, Object arg) {
+            return math.addImpl((Number)receiver,(Number)arg);
+        }
+}
+"""
+
+for (i in 2..256) {
+    print "public Object invoke$i (Object receiver, "
+    for (j in 1..(i-1)) {
+        print "Object a$j, "
+    }
+    println "Object a$i) {"
+
+    print "  return invoke (receiver, new Object[] {"
+
+    for (j in 1..(i-1)) {
+        print "a$j, "
+    }
+    println "a$i} );"
+
+    println "}"
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/classgen/genMathModification.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/classgen/genMathModification.groovy b/src/main/groovy/org/codehaus/groovy/classgen/genMathModification.groovy
new file mode 100644
index 0000000..10cc7eb
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/classgen/genMathModification.groovy
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen
+
+def ops = [
+        "plus",
+        "minus",
+        "multiply",
+        "div",
+        "or",
+        "and",
+        "xor",
+        "intdiv",
+        "mod",
+        "leftShift",
+        "rightShift",
+        "rightShiftUnsigned"
+]
+
+def numbers = ["Byte":"byte", "Short":"short", "Integer":"int", "Long":"long", "Float":"float", "Double":"double"]
+
+ops.each { op ->
+    numbers.each { wrappedType, type ->
+        println "public boolean ${type}_${op};";    
+    }
+}
+
+ops.each { op ->
+    println "if (\"${op}\".equals(name)) {"
+    numbers.each { wrappedType, type ->
+        println """if (klazz==${wrappedType}.class) {
+                ${type}_${op} = true;
+            }"""
+    }
+    println "if (klazz==Object.class) {"
+    numbers.each { wrappedType, type ->
+        println "${type}_${op} = true;"
+            }
+    println "}"
+    println "}"
+}
+
+ops.each { op ->
+    numbers.each { wrappedType1, type1 ->
+        numbers.each { wrappedType2, type2 ->
+            def math = getMath(wrappedType1, wrappedType2)
+            if (math [op]) {
+                println """public static ${math.resType} ${op}(${type1} op1, ${type2} op2) {
+                   if (instance.${type1}_${op}) {
+                      return ${op}Slow(op1, op2);
+                   }
+                   else {
+                      return ${math.resType != type1 ? "((" + math.resType+ ")op1)" : "op1"} ${math[op]} ${math.resType != type2 ? "((" + math.resType+ ")op2)" : "op2"};
+                   }
+                }"""
+                println """private static ${math.resType} ${op}Slow(${type1} op1,${type2} op2) {
+                      return ((Number)InvokerHelper.invokeMethod(op1, "${op}", op2)).${math.resType}Value();
+                }"""
+            }
+        }
+    }
+}
+
+def isFloatingPoint(number) {
+    return number == "Double" || number == "Float";
+}
+
+def isLong(number) {
+    return number == "Long";
+}
+
+def getMath (left, right) {
+    if (isFloatingPoint(left) || isFloatingPoint(right)) {
+        return [
+                resType : "double",
+
+                plus : "+",
+                minus : "-",
+                multiply : "*",
+                div : "/",
+        ];
+    }
+    if (isLong(left) || isLong(right)){
+        return [
+                resType : "long",
+
+                plus : "+",
+                minus : "-",
+                multiply : "*",
+                div : "/",
+                or : "|",
+                and : "&",
+                xor : "^",
+                intdiv : "/",
+                mod : "%",
+                leftShift : "<<",
+                rightShift : ">>",
+                rightShiftUnsigned : ">>>"
+        ]
+    }
+    return [
+            resType : "int",
+
+            plus : "+",
+            minus : "-",
+            multiply : "*",
+            div : "/",
+            or : "|",
+            and : "&",
+            xor : "^",
+            intdiv : "/",
+            mod : "%",
+            leftShift : "<<",
+            rightShift : ">>",
+            rightShiftUnsigned : ">>>"
+    ]
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy b/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
new file mode 100644
index 0000000..7e84968
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
@@ -0,0 +1,301 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control.customizers
+
+import groovy.transform.CompilationUnitAware
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.ListExpression
+import org.codehaus.groovy.classgen.GeneratorContext
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformationClass
+
+import java.lang.annotation.Annotation
+
+/**
+ * This customizer allows applying an AST transformation to a source unit with
+ * several strategies.
+ *
+ * Creating a customizer with the {@link ASTTransformationCustomizer#ASTTransformationCustomizer(Class)
+ * class constructor} will trigger an AST transformation for
+ * each class node of a source unit. However, you cannot pass parameters to the annotation so the default values
+ * will be used. Writing :
+ * <pre>
+ *     def configuration = new CompilerConfiguration()
+ *     configuration.addCompilationCustomizers(new ASTTransformationCustomizer(Log))
+ *     def shell = new GroovyShell(configuration)
+ *     shell.evaluate("""
+ *        class MyClass {
+ *
+ *        }""")
+ * </pre>
+ *
+ * is equivalent to :
+ *
+ * <pre>
+ *     def shell = new GroovyShell()
+ *     shell.evaluate("""
+ *        &#64;Log
+ *        class MyClass {
+ *
+ *        }""")
+ * </pre>
+ *
+ * The class passed as a constructor parameter must be an AST transformation annotation.
+ *
+ * Alternatively, you can apply a global AST transformation by calling the
+ * {@link ASTTransformationCustomizer#ASTTransformationCustomizer(ASTTransformation) AST transformation
+ * constructor}. In that case, the transformation is applied once for the whole source unit.
+ *
+ * Unlike a global AST transformation declared in the META-INF/services/org.codehaus.groovy.transform.ASTTransformation
+ * file, which are applied if the file is in the classpath, using this customizer you'll have the choice to apply
+ * your transformation selectively. It can also be useful to debug global AST transformations without having to
+ * package your annotation in a jar file.
+ *
+ * @author Cedric Champeau
+ *
+ * @since 1.8.0
+ * 
+ */
+class ASTTransformationCustomizer extends CompilationCustomizer implements CompilationUnitAware {
+    private final AnnotationNode annotationNode;
+    final ASTTransformation transformation
+
+    protected CompilationUnit compilationUnit;
+    private boolean applied = false; // used for global AST transformations
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * It's assumed that the annotation is not annotated with {@code GroovyASTTransformationClass} and so the
+     * second argument supplies the link to the ASTTransformation class that should be used.
+     * @param transformationAnnotation
+     * @param astTransformationClassName
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, astTransformationClassName, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. It's assumed that the annotation
+     * is not annotated with {@code GroovyASTTransformationClass} and so the second argument supplies the link to
+     * the ASTTransformation class that should be used.
+     * @param transformationAnnotation
+     * @param astTransformationClassName
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
+        this(transformationAnnotation, astTransformationClassName, transformationAnnotation.classLoader)
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * Additionally, you can pass a map of parameters that will be used to parameterize the annotation.
+     * It's assumed that the annotation is not annotated with {@code GroovyASTTransformationClass} and so the
+     * second argument supplies the link to the ASTTransformation class that should be used.
+     * @param transformationAnnotation
+     * @param astTransformationClassName
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, astTransformationClassName, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+        setAnnotationParameters(annotationParams)
+    }
+
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
+        this(annotationParams, transformationAnnotation, transformationAnnotation.classLoader)
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * @param transformationAnnotation
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation.
+     * @param transformationAnnotation
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation) {
+        this(transformationAnnotation, transformationAnnotation.classLoader)
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified transformation.
+     */
+    ASTTransformationCustomizer(final ASTTransformation transformation) {
+        super(findPhase(transformation))
+        this.transformation = transformation
+        this.annotationNode = null
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * Additionally, you can pass a map of parameters that will be used to parameterize the annotation.
+     * @param transformationAnnotation
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+        setAnnotationParameters(annotationParams)
+    }
+
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation) {
+        this(annotationParams, transformationAnnotation, transformationAnnotation.classLoader)
+    }
+
+    ASTTransformationCustomizer(final Map annotationParams, final ASTTransformation transformation) {
+        this(transformation)
+        setAnnotationParameters(annotationParams)
+    }
+
+    void setCompilationUnit(CompilationUnit unit) {
+        compilationUnit = unit
+    }
+
+    private static Class<ASTTransformation> findASTTranformationClass(Class<? extends Annotation> anAnnotationClass, ClassLoader transformationClassLoader) {
+        final GroovyASTTransformationClass annotation = anAnnotationClass.getAnnotation(GroovyASTTransformationClass)
+        if (annotation==null) throw new IllegalArgumentException("Provided class doesn't look like an AST @interface")
+
+        Class[] classes = annotation.classes()
+        String[] classesAsStrings = annotation.value()
+        if (classes.length+classesAsStrings.length>1) {
+            throw new IllegalArgumentException("AST transformation customizer doesn't support AST transforms with multiple classes")
+        }
+        return classes?classes[0]:Class.forName(classesAsStrings[0], true, transformationClassLoader?:anAnnotationClass.classLoader)
+    }
+
+    private static Class<ASTTransformation> findASTTranformationClass(Class<? extends Annotation> anAnnotationClass, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        return Class.forName(astTransformationClassName, true, transformationClassLoader?:anAnnotationClass.classLoader) as Class<ASTTransformation>
+    }
+
+    private static CompilePhase findPhase(ASTTransformation transformation) {
+        if (transformation==null) throw new IllegalArgumentException("Provided transformation must not be null")
+        final Class<?> clazz = transformation.class
+        final GroovyASTTransformation annotation = clazz.getAnnotation(GroovyASTTransformation)
+        if (annotation==null) throw new IllegalArgumentException("Provided ast transformation is not annotated with "+GroovyASTTransformation.name)
+
+        annotation.phase()
+    }
+
+    private static CompilePhase findPhase(Class<? extends Annotation> annotationClass, ClassLoader transformationClassLoader) {
+        Class<ASTTransformation> clazz = findASTTranformationClass(annotationClass, transformationClassLoader);
+
+        findPhase(clazz.newInstance())
+    }
+
+    private static CompilePhase findPhase(Class<? extends Annotation> annotationClass, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        Class<ASTTransformation> clazz = findASTTranformationClass(annotationClass, astTransformationClassName, transformationClassLoader);
+
+        findPhase(clazz.newInstance())
+    }
+
+    /**
+     * Specify annotation parameters. For example, if the annotation is :
+     * <pre>@Log(value='logger')</pre>
+     * You could create an AST transformation customizer and specify the "value" parameter thanks to this method:
+     * <pre>annotationParameters = [value: 'logger']
+     *
+     * Note that you cannot specify annotation closure values directly. If the annotation you want to add takes
+     * a closure as an argument, you will have to set a {@link ClosureExpression} instead. This can be done by either
+     * creating a custom {@link ClosureExpression} from code, or using the {@link org.codehaus.groovy.ast.builder.AstBuilder}.
+     *
+     * Here is an example :
+     * <pre>
+     *        // add @Contract({distance >= 0 })
+     *        customizer = new ASTTransformationCustomizer(Contract)
+     *        final expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {->
+     *            distance >= 0
+     *        }.expression[0]
+     *        customizer.annotationParameters = [value: expression]</pre>
+     *
+     * @param params the annotation parameters
+     *
+     * @since 1.8.1
+     */
+    public void setAnnotationParameters(Map<String,Object> params) {
+        if (params==null || annotationNode==null) return;
+        params.each { key, value ->
+            if (!annotationNode.classNode.getMethod(key)) {
+                throw new IllegalArgumentException("${annotationNode.classNode.name} does not accept any [$key] parameter")
+            }
+            if (value instanceof Closure) {
+                throw new IllegalArgumentException("Direct usage of closure is not supported by the AST " +
+                "compilation customizer. Please use ClosureExpression instead.")
+            } else if (value instanceof Expression) {
+                // avoid NPEs due to missing source code
+                value.setLineNumber(0)
+                value.setLastLineNumber(0)
+                annotationNode.addMember(key, value)
+            } else if (value instanceof Class) {
+                annotationNode.addMember(key, new ClassExpression(ClassHelper.make(value)))
+            } else if (value instanceof List) {
+                annotationNode.addMember(key, new ListExpression(value.collect {
+                    it instanceof Class ? new ClassExpression(ClassHelper.make(it)) : new ConstantExpression(it)
+                }))
+            } else {
+                annotationNode.addMember(key, new ConstantExpression(value))
+            }
+        }
+    }
+
+    @Override
+    void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+        if (transformation instanceof CompilationUnitAware) {
+            transformation.compilationUnit = compilationUnit
+        }
+        if (annotationNode!=null) {
+            // this is a local ast transformation which is applied on every class node
+            annotationNode.sourcePosition = classNode
+            transformation.visit([annotationNode, classNode] as ASTNode[], source)
+        } else {
+            // this is a global AST transformation
+            if (!applied) transformation.visit(null, source)
+        }
+        applied = true
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/control/customizers/builder/ASTTransformationCustomizerFactory.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/control/customizers/builder/ASTTransformationCustomizerFactory.groovy b/src/main/groovy/org/codehaus/groovy/control/customizers/builder/ASTTransformationCustomizerFactory.groovy
new file mode 100644
index 0000000..4e4f5be
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/control/customizers/builder/ASTTransformationCustomizerFactory.groovy
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.codehaus.groovy.control.customizers.builder
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+
+/**
+ * This factory generates an {@link ASTTransformationCustomizer ast transformation customizer}.
+ * <p>
+ * Simple syntax:
+ * <pre>builder.ast(ToString)</pre>
+ * With AST transformation options:
+ * <pre>builder.ast(includeNames:true, ToString)</pre>
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+class ASTTransformationCustomizerFactory extends AbstractFactory {
+
+    @Override
+    @CompileStatic
+    public boolean isLeaf() {
+        true
+    }
+
+    @Override
+    @CompileStatic
+    public boolean onHandleNodeAttributes(final FactoryBuilderSupport builder, final Object node, final Map attributes) {
+        false
+    }
+
+    @Override
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        ASTTransformationCustomizer customizer
+        if (attributes) {
+            customizer = new ASTTransformationCustomizer(attributes, value)
+        } else {
+            customizer = new ASTTransformationCustomizer(value)
+        }
+        customizer
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0ad8c07c/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy b/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy
new file mode 100644
index 0000000..59b8cc5
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/control/customizers/builder/CompilerCustomizationBuilder.groovy
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.codehaus.groovy.control.customizers.builder
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+
+/**
+ * <p>A builder which allows easy configuration of compilation customizers. Instead of creating
+ * various compilation customizers by hand, you may use this builder instead, which provides a
+ * shorter syntax and removes most of the verbosity.
+ *
+ */
+@CompileStatic
+class CompilerCustomizationBuilder extends FactoryBuilderSupport {
+    public CompilerCustomizationBuilder() {
+        registerFactories()
+    }
+
+    public static CompilerConfiguration withConfig(CompilerConfiguration config, Closure code) {
+        CompilerCustomizationBuilder builder = new CompilerCustomizationBuilder()
+        config.invokeMethod('addCompilationCustomizers', builder.invokeMethod('customizers', code))
+
+        config
+    }
+
+    @Override
+    protected Object postNodeCompletion(final Object parent, final Object node) {
+        Object value = super.postNodeCompletion(parent, node)
+        Object factory = getContextAttribute(CURRENT_FACTORY)
+        if (factory instanceof PostCompletionFactory) {
+            value = factory.postCompleteNode(this, parent, value)
+            setParent(parent, value)
+        }
+
+        value
+    }
+
+    private void registerFactories() {
+        registerFactory("ast", new ASTTransformationCustomizerFactory())
+        registerFactory("customizers", new CustomizersFactory())
+        registerFactory("imports", new ImportCustomizerFactory())
+        registerFactory("inline", new InlinedASTCustomizerFactory())
+        registerFactory("secureAst", new SecureASTCustomizerFactory())
+        registerFactory("source", new SourceAwareCustomizerFactory())
+    }
+}