http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java
new file mode 100644
index 0000000..7c06e69
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java
@@ -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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a case statement in a switch statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class CaseStatement extends Statement {
+
+    private Statement code;
+    private Expression expression;
+    
+    public CaseStatement(Expression expression, Statement code) {
+        this.expression = expression;
+        this.code = code;
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+    
+    public void setExpression(Expression e) {
+        expression=e;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCaseStatement(this);
+    }
+    
+    public String toString() {
+        return super.toString() + "[expression: " + expression + "; code: " + 
code + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java
new file mode 100644
index 0000000..3f40957
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java
@@ -0,0 +1,61 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+
+
+/**
+ * Represents a catch (Exception var) { } statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class CatchStatement extends Statement {
+
+    private Parameter variable;
+
+    private Statement code;
+    
+    public CatchStatement(Parameter variable, Statement code) {
+        this.variable = variable;
+        this.code = code;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCatchStatement(this);
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+
+    public ClassNode getExceptionType() {
+        return variable.getType();
+    }
+
+    public Parameter getVariable() {
+        return variable;
+    }
+
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java
new file mode 100644
index 0000000..034dcf2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java
@@ -0,0 +1,48 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents a continue statement in a loop statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class ContinueStatement extends Statement {
+
+    private String label;
+    
+    public ContinueStatement() {
+        this(null);
+    }
+    
+    public ContinueStatement(String label) {
+        this.label = label;
+    }
+    
+    public String getLabel() {
+        return label;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitContinueStatement(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
new file mode 100644
index 0000000..a7b518b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
@@ -0,0 +1,58 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a do { ... } while (condition) loop in Groovy
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class DoWhileStatement extends Statement implements LoopingStatement {
+
+    private BooleanExpression booleanExpression;
+    private Statement loopBlock;
+    
+
+    public DoWhileStatement(BooleanExpression booleanExpression, Statement 
loopBlock) {
+        this.booleanExpression = booleanExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitDoWhileLoop(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+
+    public void setLoopBlock(Statement loopBlock) {
+        this.loopBlock = loopBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java
new file mode 100644
index 0000000..d4b706c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java
@@ -0,0 +1,39 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents an empty statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class EmptyStatement extends Statement {
+
+    public static final EmptyStatement INSTANCE = new EmptyStatement();
+    
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+
+    public boolean isEmpty() {
+        return true;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
new file mode 100644
index 0000000..c6376b2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
@@ -0,0 +1,61 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * A simple statement such as a method call where the return value is ignored
+ *
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class ExpressionStatement extends Statement {
+
+    private Expression expression;
+
+    public ExpressionStatement(Expression expression) {
+        if (expression == null) {
+            throw new IllegalArgumentException("expression cannot be null");
+        }
+        this.expression = expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitExpressionStatement(this);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public String getText() {
+        return expression.getText();
+    }
+
+    public String toString() {
+        return super.toString() + "[expression:" + expression + "]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java
new file mode 100644
index 0000000..072ee6e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java
@@ -0,0 +1,83 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Represents a standard for loop in Groovy
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class ForStatement extends Statement implements LoopingStatement {
+    public static final Parameter FOR_LOOP_DUMMY = new 
Parameter(ClassHelper.OBJECT_TYPE,"forLoopDummyParameter");
+
+    private Parameter variable;
+    private Expression collectionExpression;
+    private Statement loopBlock;
+    private VariableScope scope;
+    
+
+    public ForStatement(Parameter variable, Expression collectionExpression, 
Statement loopBlock) {
+        this.variable = variable; 
+        this.collectionExpression = collectionExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitForLoop(this);
+    }
+    
+    public Expression getCollectionExpression() {
+        return collectionExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+
+    public Parameter getVariable() {
+        return variable;
+    }
+    
+    public ClassNode getVariableType() {
+        return variable.getType();
+    }
+    
+    public void setCollectionExpression(Expression collectionExpression) {
+        this.collectionExpression = collectionExpression;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+       scope = variableScope;        
+    }
+
+    public VariableScope getVariableScope() {
+        return scope;
+    }
+
+    public void setLoopBlock(Statement loopBlock) {
+        this.loopBlock = loopBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java
new file mode 100644
index 0000000..3f614cc
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java
@@ -0,0 +1,69 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents an if (condition) { ... } else { ... } statement in Groovy
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class IfStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Statement ifBlock;
+    private Statement elseBlock;
+    
+
+    public IfStatement(BooleanExpression booleanExpression, Statement ifBlock, 
Statement elseBlock) {
+        this.booleanExpression = booleanExpression;
+        this.ifBlock = ifBlock;
+        this.elseBlock = elseBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitIfElse(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+    
+    public Statement getIfBlock() {
+        return ifBlock;
+    }
+
+    public Statement getElseBlock() {
+        return elseBlock;
+    }
+
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+
+    public void setIfBlock(Statement statement) {
+        ifBlock = statement;
+    }
+
+    public void setElseBlock(Statement statement) {
+        elseBlock = statement;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java
new file mode 100644
index 0000000..4568103
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java
@@ -0,0 +1,38 @@
+/*
+ *  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.stmt;
+
+/**
+* This is an AST Node that provides some sort of looping mechanism. Typically
+* in the form of a block that will be executed repeatedly. 
+* DoWhileStatements, WhileStatements, and ForStatements are all examples of 
LoopingStatements. 
+*
+* @author Hamlet D'Arcy
+*/ 
+public interface LoopingStatement {
+
+     /**
+     * Gets the loop block. 
+     */
+     Statement getLoopBlock();
+     /**
+     * Sets the loop block. 
+     */
+     void setLoopBlock(Statement loopBlock);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java
new file mode 100644
index 0000000..9e08ebd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java
@@ -0,0 +1,72 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * A return statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class ReturnStatement extends Statement {
+    /**
+     * Only used for synthetic return statements emitted by the compiler.
+     * For comparisons use isReturningNullOrVoid() instead.
+     */
+    public static final ReturnStatement RETURN_NULL_OR_VOID = new 
ReturnStatement(ConstantExpression.NULL);
+
+    private Expression expression;
+    
+    public ReturnStatement(ExpressionStatement statement) {
+        this(statement.getExpression());
+        setStatementLabel(statement.getStatementLabel());
+    }
+    
+    public ReturnStatement(Expression expression) {
+        this.expression = expression;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitReturnStatement(this);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "return " + expression.getText();
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public boolean isReturningNullOrVoid() {
+        return expression instanceof ConstantExpression
+            && ((ConstantExpression)expression).isNullExpression();
+    }
+
+    public String toString() {
+        return super.toString() + "[expression:" + expression + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java
new file mode 100644
index 0000000..80dbc4d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java
@@ -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.ast.stmt;
+
+import org.codehaus.groovy.ast.ASTNode;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Base class for any statement
+ *
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class Statement extends ASTNode {
+
+    private List<String> statementLabels;
+
+    public Statement() {
+        statementLabels = null;
+    }
+
+    public List<String> getStatementLabels() {
+        return statementLabels;
+    }
+
+    // TODO @Deprecated
+    public String getStatementLabel() {
+        // last label by default which is added first by APP
+        return statementLabels == null ? null : statementLabels.get(0);
+    }
+
+    // TODO @Deprecated
+    public void setStatementLabel(String label) {
+        if (statementLabels == null) statementLabels = new 
LinkedList<String>();
+        statementLabels.add(label);
+    }
+
+    public void addStatementLabel(String label) {
+        if (statementLabels == null) statementLabels = new 
LinkedList<String>();
+        statementLabels.add(label);
+    }
+
+    public boolean isEmpty() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java
new file mode 100644
index 0000000..bad0194
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java
@@ -0,0 +1,91 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a switch (object) { case value: ... case [1, 2, 3]: ...  
default: ... } statement in Groovy.
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class SwitchStatement extends Statement {
+
+    private Expression expression;
+    private List<CaseStatement> caseStatements = new 
ArrayList<CaseStatement>();
+    private Statement defaultStatement;
+    
+
+    public SwitchStatement(Expression expression) {
+        this(expression, EmptyStatement.INSTANCE);
+    }
+
+    public SwitchStatement(Expression expression, Statement defaultStatement) {
+        this.expression = expression;
+        this.defaultStatement = defaultStatement;
+    }
+
+    public SwitchStatement(Expression expression, List<CaseStatement> 
caseStatements, Statement defaultStatement) {
+        this.expression = expression;
+        this.caseStatements = caseStatements;
+        this.defaultStatement = defaultStatement;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSwitch(this);
+    }
+    
+    public List<CaseStatement> getCaseStatements() {
+        return caseStatements;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void setExpression(Expression e) {
+        expression=e;
+    }
+    
+    public Statement getDefaultStatement() {
+        return defaultStatement;
+    }
+
+    public void setDefaultStatement(Statement defaultStatement) {
+        this.defaultStatement = defaultStatement;
+    }
+
+    public void addCase(CaseStatement caseStatement) {
+        caseStatements.add(caseStatement);
+    }
+
+    /**
+     * @return the case statement of the given index or null
+     */
+    public CaseStatement getCaseStatement(int idx) {
+        if (idx >= 0 && idx < caseStatements.size()) {
+            return caseStatements.get(idx);
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
new file mode 100644
index 0000000..1fd3e5c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
@@ -0,0 +1,58 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a synchronized statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class SynchronizedStatement extends Statement {
+
+    private Statement code;
+    private Expression expression;
+    
+    public SynchronizedStatement(Expression expression, Statement code) {
+        this.expression = expression;
+        this.code = code;
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+    
+    public void setCode(Statement statement) {
+        code = statement;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSynchronizedStatement(this);
+    }
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java
new file mode 100644
index 0000000..a217840
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java
@@ -0,0 +1,54 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a throw statement
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class ThrowStatement extends Statement {
+
+    private Expression expression;
+    
+    public ThrowStatement(Expression expression) {
+        this.expression = expression;
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitThrowStatement(this);
+    }
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    @Override
+    public String getText() {
+        return "throw " + expression.getText();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
new file mode 100644
index 0000000..172e403
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
@@ -0,0 +1,84 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a try { ... } catch () finally {} statement in Groovy
+ * 
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class TryCatchStatement extends Statement {
+
+    private Statement tryStatement;
+    private List<CatchStatement> catchStatements = new 
ArrayList<CatchStatement>();
+    private Statement finallyStatement;
+    
+
+    public TryCatchStatement(Statement tryStatement, Statement 
finallyStatement) {
+        this.tryStatement = tryStatement;
+        this.finallyStatement = finallyStatement;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTryCatchFinally(this);
+    }
+    
+    public List<CatchStatement> getCatchStatements() {
+        return catchStatements;
+    }
+
+    public Statement getFinallyStatement() {
+        return finallyStatement;
+    }
+
+    public Statement getTryStatement() {
+        return tryStatement;
+    }
+
+    public void addCatch(CatchStatement catchStatement) {
+        catchStatements.add(catchStatement);
+    }
+
+    /**
+     * @return the catch statement of the given index or null
+     */
+    public CatchStatement getCatchStatement(int idx) {
+        if (idx >= 0 && idx < catchStatements.size()) {
+            return catchStatements.get(idx);
+        }
+        return null;
+    }
+
+    public void setTryStatement(Statement tryStatement) {
+        this.tryStatement = tryStatement;
+    }
+
+    public void setCatchStatement(int idx, CatchStatement catchStatement) {
+        catchStatements.set(idx, catchStatement);
+    }
+
+    public void setFinallyStatement(Statement finallyStatement) {
+        this.finallyStatement = finallyStatement;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java 
b/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java
new file mode 100644
index 0000000..e325481
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java
@@ -0,0 +1,59 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a while (condition) { ... } loop in Groovy
+ *
+ * @author <a href="mailto:[email protected]";>James Strachan</a>
+ */
+public class WhileStatement extends Statement implements LoopingStatement {
+
+    private BooleanExpression booleanExpression;
+    private Statement loopBlock;
+
+
+    public WhileStatement(BooleanExpression booleanExpression, Statement 
loopBlock) {
+        this.booleanExpression = booleanExpression;
+        this.loopBlock = loopBlock;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitWhileLoop(this);
+    }
+
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+
+    public void setLoopBlock(Statement loopBlock) {
+        this.loopBlock = loopBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/stmt/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/package.html 
b/src/main/java/org/codehaus/groovy/ast/stmt/package.html
new file mode 100644
index 0000000..8226776
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.stmt.*</title>
+  </head>
+  <body>
+    <p>AST nodes for Groovy statements</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java
new file mode 100644
index 0000000..32d4a81
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java
@@ -0,0 +1,120 @@
+/*
+ *  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.tools;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PropertyNode;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static java.beans.Introspector.decapitalize;
+
+public class BeanUtils {
+    static final String GET_PREFIX = "get";
+    static final String IS_PREFIX = "is";
+
+    /**
+     * Get all properties including JavaBean pseudo properties matching getter 
conventions.
+     *
+     * @param type the ClassNode
+     * @param includeSuperProperties whether to include super properties
+     * @param includeStatic whether to include static properties
+     * @param includePseudoGetters whether to include JavaBean pseudo 
(getXXX/isYYY) properties with no corresponding field
+     * @return the list of found property nodes
+     */
+    public static List<PropertyNode> getAllProperties(ClassNode type, boolean 
includeSuperProperties, boolean includeStatic, boolean includePseudoGetters) {
+        // TODO add generics support so this can be used for @EAHC
+        // TODO add an includePseudoSetters so this can be used for 
@TupleConstructor
+        ClassNode node = type;
+        List<PropertyNode> result = new ArrayList<PropertyNode>();
+        Set<String> names = new HashSet<String>();
+        while (node != null) {
+            addExplicitProperties(node, result, names, includeStatic);
+            if (!includeSuperProperties) break;
+            node = node.getSuperClass();
+        }
+        addPseudoProperties(type, result, names, includeStatic, 
includePseudoGetters, includeSuperProperties);
+        return result;
+    }
+
+    private static void addExplicitProperties(ClassNode cNode, 
List<PropertyNode> result, Set<String> names, boolean includeStatic) {
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (includeStatic || !pNode.isStatic()) {
+                if (!names.contains(pNode.getName())) {
+                    result.add(pNode);
+                    names.add(pNode.getName());
+                }
+            }
+        }
+    }
+
+    private static void addPseudoProperties(ClassNode cNode, 
List<PropertyNode> result, Set<String> names, boolean includeStatic, boolean 
includePseudoGetters, boolean includeSuperProperties) {
+        if (!includePseudoGetters) return;
+        List<MethodNode> methods = cNode.getAllDeclaredMethods();
+        ClassNode node = cNode.getSuperClass();
+        if (includeSuperProperties) {
+            while (node != null) {
+                for (MethodNode next : node.getAllDeclaredMethods()) {
+                    if (!next.isPrivate()) {
+                        methods.add(next);
+                    }
+                }
+                node = node.getSuperClass();
+            }
+        }
+        for (MethodNode mNode : methods) {
+            if (!includeStatic && mNode.isStatic()) continue;
+            String name = mNode.getName();
+            if ((name.length() <= 3 && !name.startsWith(IS_PREFIX)) || 
name.equals("getClass") || name.equals("getMetaClass") || 
name.equals("getDeclaringClass")) {
+                // Optimization: skip invalid propertyNames
+                continue;
+            }
+            if (mNode.getDeclaringClass() != cNode && mNode.isPrivate()) {
+                // skip private super methods
+                continue;
+            }
+            int paramCount = mNode.getParameters().length;
+            ClassNode returnType = mNode.getReturnType();
+            if (paramCount == 0) {
+                if (name.startsWith(GET_PREFIX)) {
+                    // Simple getter
+                    String propName = decapitalize(name.substring(3));
+                    if (!names.contains(propName)) {
+                        result.add(new PropertyNode(propName, 
mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null));
+                        names.add(propName);
+                    }
+                } else {
+                    if (name.startsWith(IS_PREFIX) && 
returnType.equals(ClassHelper.boolean_TYPE)) {
+                        // boolean getter
+                        String propName = decapitalize(name.substring(2));
+                        if (!names.contains(propName)) {
+                            names.add(propName);
+                            result.add(new PropertyNode(propName, 
mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java
new file mode 100644
index 0000000..5c43586
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java
@@ -0,0 +1,80 @@
+/*
+ * 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.tools;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.Map;
+
+@Deprecated
+public class ClassNodeUtils {
+    @Deprecated
+    public static void addInterfaceMethods(ClassNode cNode, Map<String, 
MethodNode> methodsMap) {
+        
org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromInterfaces(cNode,
 methodsMap);
+    }
+
+    @Deprecated
+    public static Map<String, MethodNode> 
getDeclaredMethodMapsFromInterfaces(ClassNode cNode) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.getDeclaredMethodsFromInterfaces(cNode);
+    }
+
+    @Deprecated
+    public static void addDeclaredMethodMapsFromSuperInterfaces(ClassNode 
cNode, Map<String, MethodNode> methodsMap) {
+        
org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromAllInterfaces(cNode,
 methodsMap);
+    }
+
+    @Deprecated
+    public static boolean hasPossibleStaticMethod(ClassNode cNode, String 
name, Expression arguments, boolean trySpread) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticMethod(cNode, name, 
arguments, trySpread);
+    }
+
+    @Deprecated
+    public static boolean hasPossibleStaticProperty(ClassNode cNode, String 
methodName) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticProperty(cNode, 
methodName);
+    }
+
+    @Deprecated
+    public static String getPropNameForAccessor(String accessorName) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.getPropNameForAccessor(accessorName);
+    }
+
+    @Deprecated
+    public static boolean isValidAccessorName(String accessorName) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.isValidAccessorName(accessorName);
+    }
+
+    @Deprecated
+    public static boolean hasStaticProperty(ClassNode cNode, String propName) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.hasStaticProperty(cNode, propName);
+    }
+
+    @Deprecated
+    public static PropertyNode getStaticProperty(ClassNode cNode, String 
propName) {
+        return 
org.apache.groovy.ast.tools.ClassNodeUtils.getStaticProperty(cNode, propName);
+    }
+
+    @Deprecated
+    public static boolean isInnerClass(ClassNode cNode) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass(cNode);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java
new file mode 100644
index 0000000..06d4995
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java
@@ -0,0 +1,69 @@
+/*
+ *  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.tools;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.control.io.ReaderSource;
+/**
+ * Handy methods when working with Closure AST data structures.
+ */
+
+public class ClosureUtils {
+
+    /**
+     * Converts a ClosureExpression into the String source.
+     *
+     * @param readerSource a source
+     * @param expression a closure. Can't be null
+     * @return the source the closure was created from
+     * @throws java.lang.IllegalArgumentException when expression is null
+     * @throws java.lang.Exception when closure can't be read from source
+     */
+    public static String convertClosureToSource(ReaderSource readerSource, 
ClosureExpression expression) throws Exception {
+        String source = GeneralUtils.convertASTToSource(readerSource, 
expression);
+        if (!source.startsWith("{")) {
+            throw new Exception("Error converting ClosureExpression into 
source code. Closures must start with {. Found: " + source);
+        }
+        return source;
+    }
+
+    /**
+     * Does the Closure have a single char-like (char or Character) argument.
+     * @param c a Closure
+     * @return true if it has exactly one argument and the type is char or 
Character
+     */
+    public static boolean hasSingleCharacterArg(Closure c) {
+        if (c.getMaximumNumberOfParameters() != 1) return false;
+        String typeName = c.getParameterTypes()[0].getName();
+        return typeName.equals("char") || 
typeName.equals("java.lang.Character");
+    }
+
+    /**
+     * Does the Closure have a single String argument.
+     * @param c a Closure
+     * @return true if it has exactly one argument and the type is String
+     */
+    public static boolean hasSingleStringArg(Closure c) {
+        if (c.getMaximumNumberOfParameters() != 1) return false;
+        String typeName = c.getParameterTypes()[0].getName();
+        return typeName.equals("java.lang.String");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
new file mode 100644
index 0000000..252d6e3
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -0,0 +1,798 @@
+/*
+ *  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.tools;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+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.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+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.ThrowStatement;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.runtime.GeneratedClosure;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.AbstractASTTransformation;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Handy methods when working with the Groovy AST
+ */
+public class GeneralUtils {
+    public static final Token ASSIGN = Token.newSymbol(Types.ASSIGN, -1, -1);
+    public static final Token EQ = Token.newSymbol(Types.COMPARE_EQUAL, -1, 
-1);
+    public static final Token NE = Token.newSymbol(Types.COMPARE_NOT_EQUAL, 
-1, -1);
+    public static final Token LT = Token.newSymbol(Types.COMPARE_LESS_THAN, 
-1, -1);
+    public static final Token AND = Token.newSymbol(Types.LOGICAL_AND, -1, -1);
+    public static final Token OR = Token.newSymbol(Types.LOGICAL_OR, -1, -1);
+    public static final Token CMP = Token.newSymbol(Types.COMPARE_TO, -1, -1);
+    private static final Token INSTANCEOF = 
Token.newSymbol(Types.KEYWORD_INSTANCEOF, -1, -1);
+    private static final Token PLUS = Token.newSymbol(Types.PLUS, -1, -1);
+    private static final Token INDEX = Token.newSymbol("[", -1, -1);
+
+    public static BinaryExpression andX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, AND, rhv);
+    }
+
+    public static ArgumentListExpression args(Expression... expressions) {
+        List<Expression> args = new ArrayList<Expression>();
+        Collections.addAll(args, expressions);
+        return new ArgumentListExpression(args);
+    }
+
+    public static ArgumentListExpression args(List<Expression> expressions) {
+        return new ArgumentListExpression(expressions);
+    }
+
+    public static ArgumentListExpression args(Parameter[] parameters) {
+        return new ArgumentListExpression(parameters);
+    }
+
+    public static ArgumentListExpression args(String... names) {
+        List<Expression> vars = new ArrayList<Expression>();
+        for (String name : names) {
+            vars.add(varX(name));
+        }
+        return new ArgumentListExpression(vars);
+    }
+
+    public static Statement assignS(Expression target, Expression value) {
+        return new ExpressionStatement(assignX(target, value));
+    }
+
+    public static Expression assignX(Expression target, Expression value) {
+        return new BinaryExpression(target, ASSIGN, value);
+    }
+
+    public static Expression attrX(Expression oe, Expression prop) {
+        return new AttributeExpression(oe, prop);
+    }
+
+    public static BinaryExpression binX(Expression left, Token token, 
Expression right) {
+        return new BinaryExpression(left, token, right);
+    }
+
+    public static BlockStatement block(VariableScope varScope, Statement... 
stmts) {
+        BlockStatement block = new BlockStatement();
+        block.setVariableScope(varScope);
+        for (Statement stmt : stmts) block.addStatement(stmt);
+        return block;
+    }
+
+    public static BlockStatement block(VariableScope varScope, List<Statement> 
stmts) {
+        BlockStatement block = new BlockStatement();
+        block.setVariableScope(varScope);
+        for (Statement stmt : stmts) block.addStatement(stmt);
+        return block;
+    }
+
+    public static BlockStatement block(Statement... stmts) {
+        BlockStatement block = new BlockStatement();
+        for (Statement stmt : stmts) block.addStatement(stmt);
+        return block;
+    }
+
+    public static MethodCallExpression callSuperX(String methodName, 
Expression args) {
+        return callX(varX("super"), methodName, args);
+    }
+
+    public static MethodCallExpression callSuperX(String methodName) {
+        return callSuperX(methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static MethodCallExpression callThisX(String methodName, Expression 
args) {
+        return callX(varX("this"), methodName, args);
+    }
+
+    public static MethodCallExpression callThisX(String methodName) {
+        return callThisX(methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static MethodCallExpression callX(Expression receiver, String 
methodName, Expression args) {
+        return new MethodCallExpression(receiver, methodName, args);
+    }
+
+    public static MethodCallExpression callX(Expression receiver, Expression 
method, Expression args) {
+        return new MethodCallExpression(receiver, method, args);
+    }
+
+    public static MethodCallExpression callX(Expression receiver, String 
methodName) {
+        return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static StaticMethodCallExpression callX(ClassNode receiver, String 
methodName, Expression args) {
+        return new StaticMethodCallExpression(receiver, methodName, args);
+    }
+
+    public static StaticMethodCallExpression callX(ClassNode receiver, String 
methodName) {
+        return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static CastExpression castX(ClassNode type, Expression expression) {
+        return new CastExpression(type, expression);
+    }
+
+    public static CastExpression castX(ClassNode type, Expression expression, 
boolean ignoreAutoboxing) {
+        return new CastExpression(type, expression, ignoreAutoboxing);
+    }
+
+    public static ClassExpression classX(ClassNode clazz) {
+        return new ClassExpression(clazz);
+    }
+
+    public static ClassExpression classX(Class clazz) {
+        return classX(ClassHelper.make(clazz).getPlainNodeReference());
+    }
+
+    public static ClosureExpression closureX(Parameter[] params, Statement 
code) {
+        return new ClosureExpression(params, code);
+    }
+
+    public static ClosureExpression closureX(Statement code) {
+        return closureX(Parameter.EMPTY_ARRAY, code);
+    }
+
+    public static Parameter[] cloneParams(Parameter[] source) {
+        Parameter[] result = new Parameter[source.length];
+        for (int i = 0; i < source.length; i++) {
+            Parameter srcParam = source[i];
+            Parameter dstParam = new Parameter(srcParam.getOriginType(), 
srcParam.getName());
+            result[i] = dstParam;
+        }
+        return result;
+    }
+
+    /**
+     * Build a binary expression that compares two values
+     * @param lhv expression for the value to compare from
+     * @param rhv expression for the value value to compare to
+     * @return the expression comparing two values
+     */
+    public static BinaryExpression cmpX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, CMP, rhv);
+    }
+
+    public static ConstantExpression constX(Object val) {
+        return new ConstantExpression(val);
+    }
+
+    public static ConstantExpression constX(Object val, boolean keepPrimitive) 
{
+        return new ConstantExpression(val, keepPrimitive);
+    }
+
+    /**
+     * Copies all <tt>candidateAnnotations</tt> with retention policy {@link 
java.lang.annotation.RetentionPolicy#RUNTIME}
+     * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
+     * <p>
+     * Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} 
members are not supported at present.
+     */
+    public static void copyAnnotatedNodeAnnotations(final AnnotatedNode 
annotatedNode, final List<AnnotationNode> copied, List<AnnotationNode> 
notCopied) {
+        List<AnnotationNode> annotationList = annotatedNode.getAnnotations();
+        for (AnnotationNode annotation : annotationList)  {
+
+            List<AnnotationNode> annotations = 
annotation.getClassNode().getAnnotations(AbstractASTTransformation.RETENTION_CLASSNODE);
+            if (annotations.isEmpty()) continue;
+
+            if (hasClosureMember(annotation)) {
+                notCopied.add(annotation);
+                continue;
+            }
+
+            AnnotationNode retentionPolicyAnnotation = annotations.get(0);
+            Expression valueExpression = 
retentionPolicyAnnotation.getMember("value");
+            if (!(valueExpression instanceof PropertyExpression)) continue;
+
+            PropertyExpression propertyExpression = (PropertyExpression) 
valueExpression;
+            boolean processAnnotation =
+                    propertyExpression.getProperty() instanceof 
ConstantExpression &&
+                            (
+                                    "RUNTIME".equals(((ConstantExpression) 
(propertyExpression.getProperty())).getValue()) ||
+                                            
"CLASS".equals(((ConstantExpression) 
(propertyExpression.getProperty())).getValue())
+                            );
+
+            if (processAnnotation)  {
+                AnnotationNode newAnnotation = new 
AnnotationNode(annotation.getClassNode());
+                for (Map.Entry<String, Expression> member : 
annotation.getMembers().entrySet())  {
+                    newAnnotation.addMember(member.getKey(), 
member.getValue());
+                }
+                newAnnotation.setSourcePosition(annotatedNode);
+
+                copied.add(newAnnotation);
+            }
+        }
+    }
+
+    public static Statement createConstructorStatementDefault(FieldNode fNode) 
{
+        final String name = fNode.getName();
+        final ClassNode fType = fNode.getType();
+        final Expression fieldExpr = propX(varX("this"), name);
+        Expression initExpr = fNode.getInitialValueExpression();
+        Statement assignInit;
+        if (initExpr == null || (initExpr instanceof ConstantExpression && 
((ConstantExpression)initExpr).isNullExpression())) {
+            if (ClassHelper.isPrimitiveType(fType)) {
+                assignInit = EmptyStatement.INSTANCE;
+            } else {
+                assignInit = assignS(fieldExpr, 
ConstantExpression.EMPTY_EXPRESSION);
+            }
+        } else {
+            assignInit = assignS(fieldExpr, initExpr);
+        }
+        fNode.setInitialValueExpression(null);
+        Expression value = findArg(name);
+        return ifElseS(equalsNullX(value), assignInit, assignS(fieldExpr, 
castX(fType, value)));
+    }
+
+    public static ConstructorCallExpression ctorX(ClassNode type, Expression 
args) {
+        return new ConstructorCallExpression(type, args);
+    }
+
+    public static ConstructorCallExpression ctorX(ClassNode type) {
+        return new ConstructorCallExpression(type, 
ArgumentListExpression.EMPTY_ARGUMENTS);
+    }
+
+    public static Statement ctorSuperS(Expression args) {
+        return stmt(ctorX(ClassNode.SUPER, args));
+    }
+
+    public static Statement ctorThisS(Expression args) {
+        return stmt(ctorX(ClassNode.THIS, args));
+    }
+
+    public static Statement ctorSuperS() {
+        return stmt(ctorX(ClassNode.SUPER));
+    }
+
+    public static Statement ctorThisS() {
+        return stmt(ctorX(ClassNode.THIS));
+    }
+
+    public static Statement declS(Expression target, Expression init) {
+        return new ExpressionStatement(new DeclarationExpression(target, 
ASSIGN, init));
+    }
+
+    public static BinaryExpression eqX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, EQ, rhv);
+    }
+
+    public static BooleanExpression equalsNullX(Expression argExpr) {
+        return new BooleanExpression(eqX(argExpr, new 
ConstantExpression(null)));
+    }
+
+    public static FieldExpression fieldX(FieldNode fieldNode) {
+        return new FieldExpression(fieldNode);
+    }
+
+    public static FieldExpression fieldX(ClassNode owner, String fieldName) {
+        return new FieldExpression(owner.getField(fieldName));
+    }
+
+    public static Expression findArg(String argName) {
+        return new PropertyExpression(new VariableExpression("args"), argName);
+    }
+
+    public static List<MethodNode> getAllMethods(ClassNode type) {
+        ClassNode node = type;
+        List<MethodNode> result = new ArrayList<MethodNode>();
+        while (node != null) {
+            result.addAll(node.getMethods());
+            node = node.getSuperClass();
+        }
+        return result;
+    }
+
+    public static List<PropertyNode> getAllProperties(ClassNode type) {
+        ClassNode node = type;
+        List<PropertyNode> result = new ArrayList<PropertyNode>();
+        while (node != null) {
+            result.addAll(node.getProperties());
+            node = node.getSuperClass();
+        }
+        return result;
+    }
+
+    public static String getGetterName(PropertyNode pNode) {
+        return "get" + Verifier.capitalize(pNode.getName());
+    }
+
+    public static List<FieldNode> getInstanceNonPropertyFields(ClassNode 
cNode) {
+        final List<FieldNode> result = new ArrayList<FieldNode>();
+        for (FieldNode fNode : cNode.getFields()) {
+            if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == 
null) {
+                result.add(fNode);
+            }
+        }
+        return result;
+    }
+
+    public static List<String> getInstanceNonPropertyFieldNames(ClassNode 
cNode) {
+        List<FieldNode> fList = getInstanceNonPropertyFields(cNode);
+        List<String> result = new ArrayList<String>(fList.size());
+        for (FieldNode fNode : fList) {
+            result.add(fNode.getName());
+        }
+        return result;
+    }
+
+    public static List<PropertyNode> getInstanceProperties(ClassNode cNode) {
+        final List<PropertyNode> result = new ArrayList<PropertyNode>();
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (!pNode.isStatic()) {
+                result.add(pNode);
+            }
+        }
+        return result;
+    }
+
+    public static List<String> getInstancePropertyNames(ClassNode cNode) {
+        List<PropertyNode> pList = BeanUtils.getAllProperties(cNode, false, 
false, true);
+        List<String> result = new ArrayList<String>(pList.size());
+        for (PropertyNode pNode : pList) {
+            result.add(pNode.getName());
+        }
+        return result;
+    }
+
+    public static List<FieldNode> getInstancePropertyFields(ClassNode cNode) {
+        final List<FieldNode> result = new ArrayList<FieldNode>();
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (!pNode.isStatic()) {
+                result.add(pNode.getField());
+            }
+        }
+        return result;
+    }
+
+    public static Set<ClassNode> getInterfacesAndSuperInterfaces(ClassNode 
type) {
+        Set<ClassNode> res = new LinkedHashSet<ClassNode>();
+        if (type.isInterface()) {
+            res.add(type);
+            return res;
+        }
+        ClassNode next = type;
+        while (next != null) {
+            res.addAll(next.getAllInterfaces());
+            next = next.getSuperClass();
+        }
+        return res;
+    }
+
+    public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
+        final List<FieldNode> result;
+        if (cNode == ClassHelper.OBJECT_TYPE) {
+            result = new ArrayList<FieldNode>();
+        } else {
+            result = getSuperNonPropertyFields(cNode.getSuperClass());
+        }
+        for (FieldNode fNode : cNode.getFields()) {
+            if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == 
null) {
+                result.add(fNode);
+            }
+        }
+        return result;
+    }
+
+    public static List<FieldNode> getSuperPropertyFields(ClassNode cNode) {
+        final List<FieldNode> result;
+        if (cNode == ClassHelper.OBJECT_TYPE) {
+            result = new ArrayList<FieldNode>();
+        } else {
+            result = getSuperPropertyFields(cNode.getSuperClass());
+        }
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (!pNode.isStatic()) {
+                result.add(pNode.getField());
+            }
+        }
+        return result;
+    }
+
+    public static BinaryExpression hasClassX(Expression instance, ClassNode 
cNode) {
+        return eqX(classX(cNode), callX(instance, "getClass"));
+    }
+
+    private static boolean hasClosureMember(AnnotationNode annotation) {
+
+        Map<String, Expression> members = annotation.getMembers();
+        for (Map.Entry<String, Expression> member : members.entrySet())  {
+            if (member.getValue() instanceof ClosureExpression) return true;
+
+            if (member.getValue() instanceof ClassExpression)  {
+                ClassExpression classExpression = (ClassExpression) 
member.getValue();
+                Class<?> typeClass = classExpression.getType().isResolved() ? 
classExpression.getType().redirect().getTypeClass() : null;
+                if (typeClass != null && 
GeneratedClosure.class.isAssignableFrom(typeClass)) return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean hasDeclaredMethod(ClassNode cNode, String name, int 
argsCount) {
+        List<MethodNode> ms = cNode.getDeclaredMethods(name);
+        for (MethodNode m : ms) {
+            Parameter[] paras = m.getParameters();
+            if (paras != null && paras.length == argsCount) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static BinaryExpression hasEqualFieldX(FieldNode fNode, Expression 
other) {
+        return eqX(varX(fNode), propX(other, fNode.getName()));
+    }
+
+    public static BinaryExpression hasEqualPropertyX(ClassNode annotatedNode, 
PropertyNode pNode, VariableExpression other) {
+        return eqX(getterThisX(annotatedNode, pNode), 
getterX(other.getOriginType(), other, pNode));
+    }
+
+    @Deprecated
+    public static BinaryExpression hasEqualPropertyX(PropertyNode pNode, 
Expression other) {
+        String getterName = getGetterName(pNode);
+        return eqX(callThisX(getterName), callX(other, getterName));
+    }
+
+    public static BooleanExpression hasSameFieldX(FieldNode fNode, Expression 
other) {
+        return sameX(varX(fNode), propX(other, fNode.getName()));
+    }
+
+    public static BooleanExpression hasSamePropertyX(PropertyNode pNode, 
Expression other) {
+        ClassNode cNode = pNode.getDeclaringClass();
+        return sameX(getterThisX(cNode, pNode), getterX(cNode, other, pNode));
+    }
+
+    public static Statement ifElseS(Expression cond, Statement thenStmt, 
Statement elseStmt) {
+        return new IfStatement(
+                cond instanceof BooleanExpression ? (BooleanExpression) cond : 
new BooleanExpression(cond),
+                thenStmt,
+                elseStmt
+        );
+    }
+
+    public static Statement ifS(Expression cond, Expression trueExpr) {
+        return ifS(cond, new ExpressionStatement(trueExpr));
+    }
+
+    public static Statement ifS(Expression cond, Statement trueStmt) {
+        return new IfStatement(
+                cond instanceof BooleanExpression ? (BooleanExpression) cond : 
new BooleanExpression(cond),
+                trueStmt,
+                EmptyStatement.INSTANCE
+        );
+    }
+
+    public static Expression indexX(Expression target, Expression value) {
+        return new BinaryExpression(target, INDEX, value);
+    }
+
+    public static BooleanExpression isInstanceOfX(Expression objectExpression, 
ClassNode cNode) {
+        return new BooleanExpression(new BinaryExpression(objectExpression, 
INSTANCEOF, classX(cNode)));
+    }
+
+    public static BooleanExpression isOneX(Expression expr) {
+        return new BooleanExpression(new BinaryExpression(expr, EQ, new 
ConstantExpression(1)));
+    }
+
+    public static boolean isOrImplements(ClassNode type, ClassNode 
interfaceType) {
+        return type.equals(interfaceType) || 
type.implementsInterface(interfaceType);
+    }
+
+    public static BooleanExpression isTrueX(Expression argExpr) {
+        return new BooleanExpression(new BinaryExpression(argExpr, EQ, new 
ConstantExpression(Boolean.TRUE)));
+    }
+
+    public static BooleanExpression isZeroX(Expression expr) {
+        return new BooleanExpression(new BinaryExpression(expr, EQ, new 
ConstantExpression(0)));
+    }
+
+    public static BinaryExpression ltX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, LT, rhv);
+    }
+
+    /**
+     * @deprecated use 
MethodNodeUtils#methodDescriptorWithoutReturnType(MethodNode) instead
+     */
+    @Deprecated
+    public static String makeDescriptorWithoutReturnType(MethodNode mn) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mn.getName()).append(':');
+        for (Parameter p : mn.getParameters()) {
+            sb.append(p.getType()).append(',');
+        }
+        return sb.toString();
+    }
+
+    public static BinaryExpression neX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, NE, rhv);
+    }
+
+    public static BooleanExpression notNullX(Expression argExpr) {
+        return new BooleanExpression(new BinaryExpression(argExpr, NE, new 
ConstantExpression(null)));
+    }
+
+    public static NotExpression notX(Expression expr) {
+        return new NotExpression(expr instanceof BooleanExpression ? expr : 
new BooleanExpression(expr));
+    }
+
+    public static BinaryExpression orX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, OR, rhv);
+    }
+
+    public static Parameter param(ClassNode type, String name) {
+        return param(type, name, null);
+    }
+
+    public static Parameter param(ClassNode type, String name, Expression 
initialExpression) {
+        Parameter param = new Parameter(type, name);
+        if (initialExpression != null) {
+            param.setInitialExpression(initialExpression);
+        }
+        return param;
+    }
+
+    public static Parameter[] params(Parameter... params) {
+        return params != null ? params : Parameter.EMPTY_ARRAY;
+    }
+
+    public static BinaryExpression plusX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, PLUS, rhv);
+    }
+
+    public static Expression propX(Expression owner, String property) {
+        return new PropertyExpression(owner, property);
+    }
+
+    public static Expression propX(Expression owner, Expression property) {
+        return new PropertyExpression(owner, property);
+    }
+
+    public static Statement returnS(Expression expr) {
+        return new ReturnStatement(new ExpressionStatement(expr));
+    }
+
+    public static Statement safeExpression(Expression fieldExpr, Expression 
expression) {
+        return new IfStatement(
+                equalsNullX(fieldExpr),
+                new ExpressionStatement(fieldExpr),
+                new ExpressionStatement(expression));
+    }
+
+    public static BooleanExpression sameX(Expression self, Expression other) {
+        return new BooleanExpression(callX(self, "is", args(other)));
+    }
+
+    public static Statement stmt(Expression expr) {
+        return new ExpressionStatement(expr);
+    }
+
+    public static TernaryExpression ternaryX(Expression cond, Expression 
trueExpr, Expression elseExpr) {
+        return new TernaryExpression(
+                cond instanceof BooleanExpression ? (BooleanExpression) cond : 
new BooleanExpression(cond),
+                trueExpr,
+                elseExpr);
+    }
+
+    public static VariableExpression varX(String name) {
+        return new VariableExpression(name);
+    }
+
+    public static VariableExpression varX(Variable variable) {
+        return new VariableExpression(variable);
+    }
+
+    public static VariableExpression varX(String name, ClassNode type) {
+        return new VariableExpression(name, type);
+    }
+
+    public static ThrowStatement throwS(Expression expr) {
+        return new ThrowStatement(expr);
+    }
+
+    public static CatchStatement catchS(Parameter variable, Statement code) {
+        return new CatchStatement(variable, code);
+    }
+
+    /**
+     * This method is similar to {@link #propX(Expression, Expression)} but 
will make sure that if the property
+     * being accessed is defined inside the classnode provided as a parameter, 
then a getter call is generated
+     * instead of a field access.
+     * @param annotatedNode the class node where the property node is accessed 
from
+     * @param pNode the property being accessed
+     * @return a method call expression or a property expression
+     */
+    public static Expression getterThisX(ClassNode annotatedNode, PropertyNode 
pNode) {
+        ClassNode owner = pNode.getDeclaringClass();
+        if (annotatedNode.equals(owner)) {
+            return callThisX(getterName(annotatedNode, pNode));
+        }
+        return propX(new VariableExpression("this"), pNode.getName());
+    }
+
+    private static String getterName(ClassNode annotatedNode, PropertyNode 
pNode) {
+        String getterName = "get" + 
MetaClassHelper.capitalize(pNode.getName());
+        boolean existingExplicitGetter = annotatedNode.getMethod(getterName, 
Parameter.EMPTY_ARRAY) != null;
+        if (ClassHelper.boolean_TYPE.equals(pNode.getOriginType()) && 
!existingExplicitGetter) {
+            getterName = "is" + MetaClassHelper.capitalize(pNode.getName());
+        }
+        return getterName;
+    }
+
+    /**
+     * This method is similar to {@link #propX(Expression, Expression)} but 
will make sure that if the property
+     * being accessed is defined inside the classnode provided as a parameter, 
then a getter call is generated
+     * instead of a field access.
+     * @param annotatedNode the class node where the property node is accessed 
from
+     * @param receiver the object having the property
+     * @param pNode the property being accessed
+     * @return a method call expression or a property expression
+     */
+    public static Expression getterX(ClassNode annotatedNode, Expression 
receiver, PropertyNode pNode) {
+        ClassNode owner = pNode.getDeclaringClass();
+        if (annotatedNode.equals(owner)) {
+            return callX(receiver, getterName(annotatedNode, pNode));
+        }
+        return propX(receiver, pNode.getName());
+    }
+
+    /**
+     * Converts an expression into the String source. Only some specific 
expressions like closure expression
+     * support this.
+     *
+     * @param readerSource a source
+     * @param expression an expression. Can't be null
+     * @return the source the closure was created from
+     * @throws java.lang.IllegalArgumentException when expression is null
+     * @throws java.lang.Exception when closure can't be read from source
+     */
+    public static String convertASTToSource(ReaderSource readerSource, ASTNode 
expression) throws Exception {
+        if (expression == null) throw new IllegalArgumentException("Null: 
expression");
+
+        StringBuilder result = new StringBuilder();
+        for (int x = expression.getLineNumber(); x <= 
expression.getLastLineNumber(); x++) {
+            String line = readerSource.getLine(x, null);
+            if (line == null) {
+                throw new Exception(
+                        "Error calculating source code for expression. Trying 
to read line " + x + " from " + readerSource.getClass()
+                );
+            }
+            if (x == expression.getLastLineNumber()) {
+                line = line.substring(0, expression.getLastColumnNumber() - 1);
+            }
+            if (x == expression.getLineNumber()) {
+                line = line.substring(expression.getColumnNumber() - 1);
+            }
+            //restoring line breaks is important b/c of lack of semicolons
+            result.append(line).append('\n');
+        }
+
+
+        String source = result.toString().trim();
+
+        return source;
+    }
+
+    public static boolean copyStatementsWithSuperAdjustment(ClosureExpression 
pre, BlockStatement body) {
+        Statement preCode = pre.getCode();
+        boolean changed = false;
+        if (preCode instanceof BlockStatement) {
+            BlockStatement block = (BlockStatement) preCode;
+            List<Statement> statements = block.getStatements();
+            for (int i = 0; i < statements.size(); i++) {
+                Statement statement = statements.get(i);
+                // adjust the first statement if it's a super call
+                if (i == 0 && statement instanceof ExpressionStatement) {
+                    ExpressionStatement es = (ExpressionStatement) statement;
+                    Expression preExp = es.getExpression();
+                    if (preExp instanceof MethodCallExpression) {
+                        MethodCallExpression mce = (MethodCallExpression) 
preExp;
+                        String name = mce.getMethodAsString();
+                        if ("super".equals(name)) {
+                            es.setExpression(new 
ConstructorCallExpression(ClassNode.SUPER, mce.getArguments()));
+                            changed = true;
+                        }
+                    }
+                }
+                body.addStatement(statement);
+            }
+        }
+        return changed;
+    }
+
+    public static String getSetterName(String name) {
+        return "set" + Verifier.capitalize(name);
+    }
+
+    public static boolean isDefaultVisibility(int modifiers) {
+        return (modifiers & (Modifier.PRIVATE | Modifier.PUBLIC | 
Modifier.PROTECTED)) == 0;
+    }
+
+    public static boolean inSamePackage(ClassNode first, ClassNode second) {
+        PackageNode firstPackage = first.getPackage();
+        PackageNode secondPackage = second.getPackage();
+        return ((firstPackage == null && secondPackage == null) ||
+                        firstPackage != null && secondPackage != null && 
firstPackage.getName().equals(secondPackage.getName()));
+    }
+
+    public static boolean inSamePackage(Class first, Class second) {
+        Package firstPackage = first.getPackage();
+        Package secondPackage = second.getPackage();
+        return ((firstPackage == null && secondPackage == null) ||
+                        firstPackage != null && secondPackage != null && 
firstPackage.getName().equals(secondPackage.getName()));
+    }
+}

Reply via email to