http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/AstSpecificationCompiler.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/AstSpecificationCompiler.groovy b/src/main/groovy/AstSpecificationCompiler.groovy deleted file mode 100644 index 5e607b6..0000000 --- a/src/main/groovy/AstSpecificationCompiler.groovy +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * 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/10110145/src/main/groovy/AstStringCompiler.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/AstStringCompiler.groovy b/src/main/groovy/AstStringCompiler.groovy deleted file mode 100644 index 497c125..0000000 --- a/src/main/groovy/AstStringCompiler.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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/10110145/src/main/groovy/CollectRecursiveCalls.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/CollectRecursiveCalls.groovy b/src/main/groovy/CollectRecursiveCalls.groovy deleted file mode 100644 index 2c7e6de..0000000 --- a/src/main/groovy/CollectRecursiveCalls.groovy +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.CodeVisitorSupport -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; - -/** - * Collect all recursive calls within method - * - * @author Johannes Link - */ -@CompileStatic -class CollectRecursiveCalls extends CodeVisitorSupport { - MethodNode method - List<Expression> recursiveCalls = [] - - public void visitMethodCallExpression(MethodCallExpression call) { - if (isRecursive(call)) { - recursiveCalls << call - } - super.visitMethodCallExpression(call) - } - - public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { - if (isRecursive(call)) { - recursiveCalls << call - } - super.visitStaticMethodCallExpression(call) - } - - private boolean isRecursive(call) { - new RecursivenessTester().isRecursive(method: method, call: call) - } - - synchronized List<Expression> collect(MethodNode method) { - recursiveCalls.clear() - this.method = method - this.method.code.visit(this) - recursiveCalls - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/CompilerCustomizationBuilder.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/CompilerCustomizationBuilder.groovy b/src/main/groovy/CompilerCustomizationBuilder.groovy deleted file mode 100644 index 59b8cc5..0000000 --- a/src/main/groovy/CompilerCustomizationBuilder.groovy +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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()) - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/GrapeMain.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/GrapeMain.groovy b/src/main/groovy/GrapeMain.groovy deleted file mode 100644 index c78d25e..0000000 --- a/src/main/groovy/GrapeMain.groovy +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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.tools - -import groovy.grape.Grape -import groovy.transform.Field -import org.apache.commons.cli.CommandLine -import org.apache.commons.cli.DefaultParser -import org.apache.commons.cli.HelpFormatter -import org.apache.commons.cli.Option -import org.apache.commons.cli.OptionGroup -import org.apache.commons.cli.Options -import org.apache.ivy.util.DefaultMessageLogger -import org.apache.ivy.util.Message - -//commands - -@Field install = {arg, cmd -> - if (arg.size() > 5 || arg.size() < 3) { - println 'install requires two to four arguments: <group> <module> [<version> [<classifier>]]' - return - } - def ver = '*' - if (arg.size() >= 4) { - ver = arg[3] - } - def classifier = null - if (arg.size() >= 5) { - classifier = arg[4] - } - - // set the instance so we can re-set the logger - Grape.getInstance() - setupLogging() - - cmd.getOptionValues('r')?.each { String url -> - Grape.addResolver(name:url, root:url) - } - - try { - Grape.grab(autoDownload: true, group: arg[1], module: arg[2], version: ver, classifier: classifier, noExceptions: true) - } catch (Exception e) { - println "An error occured : $ex" - } -} - -@Field uninstall = {arg, cmd -> - if (arg.size() != 4) { - println 'uninstall requires three arguments: <group> <module> <version>' - // TODO make version optional? support classifier? -// println 'uninstall requires two to four arguments, <group> <module> [<version>] [<classifier>]' - return - } - String group = arg[1] - String module = arg[2] - String ver = arg[3] -// def classifier = null - - // set the instance so we can re-set the logger - Grape.getInstance() - setupLogging() - - if (!Grape.enumerateGrapes().find {String groupName, Map g -> - g.any {String moduleName, List<String> versions -> - group == groupName && module == moduleName && ver in versions - } - }) { - println "uninstall did not find grape matching: $group $module $ver" - def fuzzyMatches = Grape.enumerateGrapes().findAll { String groupName, Map g -> - g.any {String moduleName, List<String> versions -> - groupName.contains(group) || moduleName.contains(module) || - group.contains(groupName) || module.contains(moduleName) - } - } - if (fuzzyMatches) { - println 'possible matches:' - fuzzyMatches.each { String groupName, Map g -> println " $groupName: $g" } - } - return - } - Grape.instance.uninstallArtifact(group, module, ver) -} - -@Field list = {arg, cmd -> - println "" - - int moduleCount = 0 - int versionCount = 0 - - // set the instance so we can re-set the logger - Grape.getInstance() - setupLogging() - - Grape.enumerateGrapes().each {String groupName, Map group -> - group.each {String moduleName, List<String> versions -> - println "$groupName $moduleName $versions" - moduleCount++ - versionCount += versions.size() - } - } - println "" - println "$moduleCount Grape modules cached" - println "$versionCount Grape module versions cached" -} - -@Field resolve = {arg, cmd -> - Options options = new Options(); - options.addOption(Option.builder("a").hasArg(false).longOpt("ant").build()); - options.addOption(Option.builder("d").hasArg(false).longOpt("dos").build()); - options.addOption(Option.builder("s").hasArg(false).longOpt("shell").build()); - options.addOption(Option.builder("i").hasArg(false).longOpt("ivy").build()); - CommandLine cmd2 = new DefaultParser().parse(options, arg[1..-1] as String[], true); - arg = cmd2.args - - // set the instance so we can re-set the logger - Grape.getInstance() - setupLogging(Message.MSG_ERR) - - if ((arg.size() % 3) != 0) { - println 'There needs to be a multiple of three arguments: (group module version)+' - return - } - if (args.size() < 3) { - println 'At least one Grape reference is required' - return - } - def before, between, after - def ivyFormatRequested = false - - if (cmd2.hasOption('a')) { - before = '<pathelement location="' - between = '">\n<pathelement location="' - after = '">' - } else if (cmd2.hasOption('d')) { - before = 'set CLASSPATH=' - between = ';' - after = '' - } else if (cmd2.hasOption('s')) { - before = 'export CLASSPATH=' - between = ':' - after = '' - } else if (cmd2.hasOption('i')) { - ivyFormatRequested = true - before = '<dependency ' - between = '">\n<dependency ' - after = '">' - } else { - before = '' - between = '\n' - after = '\n' - } - - iter = arg.iterator() - def params = [[:]] - def depsInfo = [] // this list will contain the module/group/version info of all resolved dependencies - if(ivyFormatRequested) { - params << depsInfo - } - while (iter.hasNext()) { - params.add([group: iter.next(), module: iter.next(), version: iter.next()]) - } - try { - def results = [] - def uris = Grape.resolve(* params) - if(!ivyFormatRequested) { - for (URI uri: uris) { - if (uri.scheme == 'file') { - results += new File(uri).path - } else { - results += uri.toASCIIString() - } - } - } else { - depsInfo.each { dep -> - results += ('org="' + dep.group + '" name="' + dep.module + '" revision="' + dep.revision) - } - } - - if (results) { - println "${before}${results.join(between)}${after}" - } else { - println 'Nothing was resolved' - } - } catch (Exception e) { - println "Error in resolve:\n\t$e.message" - if (e.message =~ /unresolved dependency/) println "Perhaps the grape is not installed?" - } -} - -@Field help = { arg, cmd -> grapeHelp() } - -@Field commands = [ - 'install': [closure: install, - shortHelp: 'Installs a particular grape'], - 'uninstall': [closure: uninstall, - shortHelp: 'Uninstalls a particular grape (non-transitively removes the respective jar file from the grape cache)'], - 'list': [closure: list, - shortHelp: 'Lists all installed grapes'], - 'resolve': [closure: resolve, - shortHelp: 'Enumerates the jars used by a grape'], - 'help': [closure: help, - shortHelp: 'Usage information'] -] - -@Field grapeHelp = { - int spacesLen = commands.keySet().max {it.length()}.length() + 3 - String spaces = ' ' * spacesLen - - PrintWriter pw = new PrintWriter(binding.variables.out ?: System.out) - new HelpFormatter().printHelp( - pw, - 80, - "grape [options] <command> [args]\n", - "options:", - options, - 2, - 4, - null, // footer - true); - pw.flush() - - println "" - println "commands:" - commands.each {String k, v -> - println " ${(k + spaces).substring(0, spacesLen)} $v.shortHelp" - } - println "" -} - -@Field setupLogging = {int defaultLevel = 2 -> // = Message.MSG_INFO -> some parsing error :( - if (cmd.hasOption('q')) { - Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_ERR)) - } else if (cmd.hasOption('w')) { - Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_WARN)) - } else if (cmd.hasOption('i')) { - Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_INFO)) - } else if (cmd.hasOption('V')) { - Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_VERBOSE)) - } else if (cmd.hasOption('d')) { - Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_DEBUG)) - } else { - Message.setDefaultLogger(new DefaultMessageLogger(defaultLevel)) - } -} - -// command line parsing -@Field Options options = new Options(); - -options.addOption(Option.builder("D").longOpt("define").desc("define a system property").numberOfArgs(2).valueSeparator().argName("name=value").build()); -options.addOption(Option.builder("r").longOpt("resolver").desc("define a grab resolver (for install)").hasArg(true).argName("url").build()); -options.addOption(Option.builder("h").hasArg(false).desc("usage information").longOpt("help").build()); - -// Logging Level Options -options.addOptionGroup( - new OptionGroup() - .addOption(Option.builder("q").hasArg(false).desc("Log level 0 - only errors").longOpt("quiet").build()) - .addOption(Option.builder("w").hasArg(false).desc("Log level 1 - errors and warnings").longOpt("warn").build()) - .addOption(Option.builder("i").hasArg(false).desc("Log level 2 - info").longOpt("info").build()) - .addOption(Option.builder("V").hasArg(false).desc("Log level 3 - verbose").longOpt("verbose").build()) - .addOption(Option.builder("d").hasArg(false).desc("Log level 4 - debug").longOpt("debug").build()) -) -options.addOption(Option.builder("v").hasArg(false).desc("display the Groovy and JVM versions").longOpt("version").build()); - -@Field CommandLine cmd - -cmd = new DefaultParser().parse(options, args, true); - -if (cmd.hasOption('h')) { - grapeHelp() - return -} - -if (cmd.hasOption('v')) { - String version = GroovySystem.getVersion(); - println "Groovy Version: $version JVM: ${System.getProperty('java.version')}" - return -} - -if (options.hasOption('D')) { - options.getOptionProperties('D')?.each { k, v -> - System.setProperty(k, v) - } -} - -String[] arg = cmd.args -if (arg?.length == 0) { - grapeHelp() -} else if (commands.containsKey(arg[0])) { - commands[arg[0]].closure(arg, cmd) -} else { - println "grape: '${arg[0]}' is not a grape command. See 'grape --help'" -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/HasRecursiveCalls.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/HasRecursiveCalls.groovy b/src/main/groovy/HasRecursiveCalls.groovy deleted file mode 100644 index 79f8e6d..0000000 --- a/src/main/groovy/HasRecursiveCalls.groovy +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.CodeVisitorSupport -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.ast.expr.StaticMethodCallExpression - -/** - * - * Check if there are any recursive calls in a method - * - * @author Johannes Link - */ -@CompileStatic -class HasRecursiveCalls extends CodeVisitorSupport { - MethodNode method - boolean hasRecursiveCalls = false - - public void visitMethodCallExpression(MethodCallExpression call) { - if (isRecursive(call)) { - hasRecursiveCalls = true - } else { - super.visitMethodCallExpression(call) - } - } - - public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { - if (isRecursive(call)) { - hasRecursiveCalls = true - } else { - super.visitStaticMethodCallExpression(call) - } - } - - private boolean isRecursive(call) { - new RecursivenessTester().isRecursive(method: method, call: call) - } - - synchronized boolean test(MethodNode method) { - hasRecursiveCalls = false - this.method = method - this.method.code.visit(this) - hasRecursiveCalls - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/InWhileLoopWrapper.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/InWhileLoopWrapper.groovy b/src/main/groovy/InWhileLoopWrapper.groovy deleted file mode 100644 index 981f146..0000000 --- a/src/main/groovy/InWhileLoopWrapper.groovy +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.Parameter -import org.codehaus.groovy.ast.VariableScope -import org.codehaus.groovy.ast.expr.BooleanExpression -import org.codehaus.groovy.ast.expr.ConstantExpression -import org.codehaus.groovy.ast.stmt.BlockStatement -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.Statement -import org.codehaus.groovy.ast.stmt.TryCatchStatement -import org.codehaus.groovy.ast.stmt.WhileStatement - -/** - * Wrap the body of a method in a while loop, nested in a try-catch. - * This is the first step in making a tail recursive method iterative. - * - * There are two ways to invoke the next iteration step: - * 1. "continue _RECURE_HERE_" is used by recursive calls outside of closures - * 2. "throw LOOP_EXCEPTION" is used by recursive calls within closures b/c you cannot invoke "continue" from there - * - * @author Johannes Link - */ -@CompileStatic -class InWhileLoopWrapper { - - static final String LOOP_LABEL = '_RECUR_HERE_' - static final GotoRecurHereException LOOP_EXCEPTION = new GotoRecurHereException() - - void wrap(MethodNode method) { - BlockStatement oldBody = method.code as BlockStatement - TryCatchStatement tryCatchStatement = new TryCatchStatement( - oldBody, - EmptyStatement.INSTANCE - ) - tryCatchStatement.addCatch(new CatchStatement( - new Parameter(ClassHelper.make(GotoRecurHereException), 'ignore'), - new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL) - )) - - WhileStatement whileLoop = new WhileStatement( - new BooleanExpression(new ConstantExpression(true)), - new BlockStatement([tryCatchStatement] as List<Statement>, new VariableScope(method.variableScope)) - ) - List<Statement> whileLoopStatements = ((BlockStatement) whileLoop.loopBlock).statements - if (whileLoopStatements.size() > 0) - whileLoopStatements[0].statementLabel = LOOP_LABEL - BlockStatement newBody = new BlockStatement([] as List<Statement>, new VariableScope(method.variableScope)) - newBody.addStatement(whileLoop) - method.code = newBody - } -} - -/** - * Exception will be thrown by recursive calls in closures and caught in while loop to continue to LOOP_LABEL - */ -class GotoRecurHereException extends Throwable { - -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/RecursivenessTester.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/RecursivenessTester.groovy b/src/main/groovy/RecursivenessTester.groovy deleted file mode 100644 index 7c9545a..0000000 --- a/src/main/groovy/RecursivenessTester.groovy +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.transform.tailrec - -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.expr.ConstantExpression -import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.ast.expr.StaticMethodCallExpression -import org.codehaus.groovy.ast.expr.VariableExpression - -/** - * - * Test if a method call is recursive if called within a given method node. - * Handles static calls as well. - * - * Currently known simplifications: - * - Does not check for method overloading or overridden methods. - * - Does not check for matching return types; even void and any object type are considered to be compatible. - * - Argument type matching could be more specific in case of static compilation. - * - Method names via a GString are never considered to be recursive - * - * @author Johannes Link - */ -class RecursivenessTester { - public boolean isRecursive(params) { - assert params.method.class == MethodNode - assert params.call.class == MethodCallExpression || StaticMethodCallExpression - - isRecursive(params.method, params.call) - } - - public boolean isRecursive(MethodNode method, MethodCallExpression call) { - if (!isCallToThis(call)) - return false - // Could be a GStringExpression - if (! (call.method instanceof ConstantExpression)) - return false - if (call.method.value != method.name) - return false - methodParamsMatchCallArgs(method, call) - } - - public boolean isRecursive(MethodNode method, StaticMethodCallExpression call) { - if (!method.isStatic()) - return false - if (method.declaringClass != call.ownerType) - return false - if (call.method != method.name) - return false - methodParamsMatchCallArgs(method, call) - } - - private boolean isCallToThis(MethodCallExpression call) { - if (call.objectExpression == null) - return call.isImplicitThis() - if (! (call.objectExpression instanceof VariableExpression)) { - return false - } - return call.objectExpression.isThisExpression() - } - - private boolean methodParamsMatchCallArgs(method, call) { - if (method.parameters.size() != call.arguments.expressions.size()) - return false - def classNodePairs = [method.parameters*.type, call.arguments*.type].transpose() - return classNodePairs.every { ClassNode paramType, ClassNode argType -> - return areTypesCallCompatible(argType, paramType) - } - } - - /** - * Parameter type and calling argument type can both be derived from the other since typing information is - * optional in Groovy. - * Since int is not derived from Integer (nor the other way around) we compare the boxed types - */ - private areTypesCallCompatible(ClassNode argType, ClassNode paramType) { - ClassNode boxedArg = ClassHelper.getWrapper(argType) - ClassNode boxedParam = ClassHelper.getWrapper(paramType) - return boxedArg.isDerivedFrom(boxedParam) || boxedParam.isDerivedFrom(boxedArg) - } - -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/ReturnAdderForClosures.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/ReturnAdderForClosures.groovy b/src/main/groovy/ReturnAdderForClosures.groovy deleted file mode 100644 index 64ebce7..0000000 --- a/src/main/groovy/ReturnAdderForClosures.groovy +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.transform.tailrec - -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.ast.CodeVisitorSupport -import org.codehaus.groovy.ast.MethodNode -import org.codehaus.groovy.ast.Parameter -import org.codehaus.groovy.ast.expr.ClosureExpression -import org.codehaus.groovy.classgen.ReturnAdder - -/** - * Adds explicit return statements to implicit return points in a closure. This is necessary since - * tail-recursion is detected by having the recursive call within the return statement. - * - * @author Johannes Link - */ -class ReturnAdderForClosures extends CodeVisitorSupport { - - synchronized void visitMethod(MethodNode method) { - method.code.visit(this) - } - - public void visitClosureExpression(ClosureExpression expression) { - //Create a dummy method with the closure's code as the method's code. Then user ReturnAdder, which only works for methods. - MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, expression.code); - new ReturnAdder().visitMethod(node); - super.visitClosureExpression(expression) - } - -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/ReturnStatementToIterationConverter.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/ReturnStatementToIterationConverter.groovy b/src/main/groovy/ReturnStatementToIterationConverter.groovy deleted file mode 100644 index 2c75f4f..0000000 --- a/src/main/groovy/ReturnStatementToIterationConverter.groovy +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.ClassNode -import org.codehaus.groovy.ast.expr.BinaryExpression -import org.codehaus.groovy.ast.expr.Expression -import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.ast.expr.StaticMethodCallExpression -import org.codehaus.groovy.ast.expr.TupleExpression -import org.codehaus.groovy.ast.expr.VariableExpression -import org.codehaus.groovy.ast.stmt.BlockStatement -import org.codehaus.groovy.ast.stmt.ExpressionStatement -import org.codehaus.groovy.ast.stmt.ReturnStatement -import org.codehaus.groovy.ast.stmt.Statement - -import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS -import static org.codehaus.groovy.ast.tools.GeneralUtils.varX - -/** - * Translates all return statements into an invocation of the next iteration. This can be either - * - "continue LOOP_LABEL": Outside closures - * - "throw LOOP_EXCEPTION": Inside closures - * - * Moreover, before adding the recur statement the iteration parameters (originally the method args) - * are set to their new value. To prevent variable aliasing parameters will be copied into temp vars - * before they are changes so that their current iteration value can be used when setting other params. - * - * There's probably place for optimizing the amount of variable copying being done, e.g. - * parameters that are only handed through must not be copied at all. - * - * @author Johannes Link - */ -@CompileStatic -class ReturnStatementToIterationConverter { - - Statement recurStatement = AstHelper.recurStatement() - - Statement convert(ReturnStatement statement, Map<Integer, Map> positionMapping) { - Expression recursiveCall = statement.expression - if (!isAMethodCalls(recursiveCall)) - return statement - - Map<String, Map> tempMapping = [:] - Map tempDeclarations = [:] - List<ExpressionStatement> argAssignments = [] - - BlockStatement result = new BlockStatement() - result.statementLabel = statement.statementLabel - - /* Create temp declarations for all method arguments. - * Add the declarations and var mapping to tempMapping and tempDeclarations for further reference. - */ - getArguments(recursiveCall).eachWithIndex { Expression expression, int index -> - ExpressionStatement tempDeclaration = createTempDeclaration(index, positionMapping, tempMapping, tempDeclarations) - result.addStatement(tempDeclaration) - } - - /* - * Assign the iteration variables their new value before recuring - */ - getArguments(recursiveCall).eachWithIndex { Expression expression, int index -> - ExpressionStatement argAssignment = createAssignmentToIterationVariable(expression, index, positionMapping) - argAssignments.add(argAssignment) - result.addStatement(argAssignment) - } - - Set<String> unusedTemps = replaceAllArgUsages(argAssignments, tempMapping) - for (String temp : unusedTemps) { - result.statements.remove(tempDeclarations[temp]) - } - result.addStatement(recurStatement) - - return result - } - - private ExpressionStatement createAssignmentToIterationVariable(Expression expression, int index, Map<Integer, Map> positionMapping) { - String argName = positionMapping[index]['name'] - ClassNode argAndTempType = positionMapping[index]['type'] as ClassNode - ExpressionStatement argAssignment = (ExpressionStatement) assignS(varX(argName, argAndTempType), expression) - argAssignment - } - - private ExpressionStatement createTempDeclaration(int index, Map<Integer, Map> positionMapping, Map<String, Map> tempMapping, Map tempDeclarations) { - String argName = positionMapping[index]['name'] - String tempName = "_${argName}_" - ClassNode argAndTempType = positionMapping[index]['type'] as ClassNode - ExpressionStatement tempDeclaration = AstHelper.createVariableAlias(tempName, argAndTempType, argName) - tempMapping[argName] = [name: tempName, type: argAndTempType] - tempDeclarations[tempName] = tempDeclaration - return tempDeclaration - } - - private List<Expression> getArguments(Expression recursiveCall) { - if (recursiveCall instanceof MethodCallExpression) - return ((TupleExpression) ((MethodCallExpression) recursiveCall).arguments).expressions - if (recursiveCall instanceof StaticMethodCallExpression) - return ((TupleExpression) ((StaticMethodCallExpression) recursiveCall).arguments).expressions - } - - private boolean isAMethodCalls(Expression expression) { - expression.class in [MethodCallExpression, StaticMethodCallExpression] - } - - private Set<String> replaceAllArgUsages(List<ExpressionStatement> iterationVariablesAssignmentNodes, Map<String, Map> tempMapping) { - Set<String> unusedTempNames = tempMapping.values().collect {Map nameAndType -> (String) nameAndType['name']} as Set<String> - VariableReplacedListener tracker = new UsedVariableTracker() - for (ExpressionStatement statement : iterationVariablesAssignmentNodes) { - replaceArgUsageByTempUsage((BinaryExpression) statement.expression, tempMapping, tracker) - } - unusedTempNames = unusedTempNames - tracker.usedVariableNames - return unusedTempNames - } - - private void replaceArgUsageByTempUsage(BinaryExpression binary, Map tempMapping, UsedVariableTracker tracker) { - VariableAccessReplacer replacer = new VariableAccessReplacer(nameAndTypeMapping: tempMapping, listener: tracker) - // Replacement must only happen in binary.rightExpression. It's a hack in VariableExpressionReplacer which takes care of that. - replacer.replaceIn(binary) - } -} - -@CompileStatic -class UsedVariableTracker implements VariableReplacedListener { - - final Set<String> usedVariableNames = [] as Set - - @Override - void variableReplaced(VariableExpression oldVar, VariableExpression newVar) { - usedVariableNames.add(newVar.name) - } -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/StatementReplacer.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/StatementReplacer.groovy b/src/main/groovy/StatementReplacer.groovy deleted file mode 100644 index 3a9dab3..0000000 --- a/src/main/groovy/StatementReplacer.groovy +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.transform.tailrec - -import groovy.transform.CompileStatic -import org.codehaus.groovy.ast.ASTNode -import org.codehaus.groovy.ast.CodeVisitorSupport -import org.codehaus.groovy.ast.expr.ClosureExpression -import org.codehaus.groovy.ast.stmt.BlockStatement -import org.codehaus.groovy.ast.stmt.DoWhileStatement -import org.codehaus.groovy.ast.stmt.ForStatement -import org.codehaus.groovy.ast.stmt.IfStatement -import org.codehaus.groovy.ast.stmt.Statement -import org.codehaus.groovy.ast.stmt.WhileStatement - -/** - * Tool for replacing Statement objects in an AST by other Statement instances. - * - * Within @TailRecursive it is used to swap ReturnStatements with looping back to RECUR label - * - * @author Johannes Link - */ -@CompileStatic -class StatementReplacer extends CodeVisitorSupport { - - Closure<Boolean> when = { Statement node -> false } - Closure<Statement> replaceWith = { Statement statement -> statement } - int closureLevel = 0 - - void replaceIn(ASTNode root) { - root.visit(this) - } - - public void visitClosureExpression(ClosureExpression expression) { - closureLevel++ - try { - super.visitClosureExpression(expression) - } finally { - closureLevel-- - } - } - - public void visitBlockStatement(BlockStatement block) { - List<Statement> copyOfStatements = new ArrayList<Statement>(block.statements) - copyOfStatements.eachWithIndex { Statement statement, int index -> - replaceIfNecessary(statement) { Statement node -> block.statements[index] = node } - } - super.visitBlockStatement(block); - } - - public void visitIfElse(IfStatement ifElse) { - replaceIfNecessary(ifElse.ifBlock) { Statement s -> ifElse.ifBlock = s } - replaceIfNecessary(ifElse.elseBlock) { Statement s -> ifElse.elseBlock = s } - super.visitIfElse(ifElse); - } - - public void visitForLoop(ForStatement forLoop) { - replaceIfNecessary(forLoop.loopBlock) { Statement s -> forLoop.loopBlock = s } - super.visitForLoop(forLoop); - } - - public void visitWhileLoop(WhileStatement loop) { - replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s } - super.visitWhileLoop(loop); - } - - public void visitDoWhileLoop(DoWhileStatement loop) { - replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s } - super.visitDoWhileLoop(loop); - } - - - private void replaceIfNecessary(Statement nodeToCheck, Closure replacementCode) { - if (conditionFulfilled(nodeToCheck)) { - ASTNode replacement = replaceWith(nodeToCheck) - replacement.setSourcePosition(nodeToCheck); - replacement.copyNodeMetaData(nodeToCheck); - replacementCode(replacement) - } - } - - private boolean conditionFulfilled(ASTNode nodeToCheck) { - if (when.maximumNumberOfParameters < 2) - return when(nodeToCheck) - else - return when(nodeToCheck, isInClosure()) - } - - private boolean isInClosure() { - closureLevel > 0 - } - -} http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/StringUtil.groovy ---------------------------------------------------------------------- diff --git a/src/main/groovy/StringUtil.groovy b/src/main/groovy/StringUtil.groovy deleted file mode 100644 index ed83e53..0000000 --- a/src/main/groovy/StringUtil.groovy +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.util - -import groovy.transform.CompileStatic - -/** - * String utility functions. - */ -@CompileStatic -class StringUtil { - /** - * Provides Groovy with functionality similar to the unix tr command - * which translates a string replacing characters from a source set - * with characters from a replacement set. - * - * @since 1.7.3 - */ - static String tr(String text, String source, String replacement) { - if (!text || !source) { return text } - source = expandHyphen(source) - replacement = expandHyphen(replacement) - - // padding replacement with a last character, if necessary - replacement = replacement.padRight(source.size(), replacement[replacement.size() - 1]) - - return text.collect { String original -> - if (source.contains(original)) { - replacement[source.lastIndexOf(original)] - } else { - original - } - }.join('') - } - - // no expansion for hyphen at start or end of Strings - private static String expandHyphen(String text) { - if (!text.contains('-')) { return text } - return text.replaceAll(/(.)-(.)/, { all, begin, end -> (begin..end).join('') }) - } -}
