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("""
+ * @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())
+ }
+}