This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch danielsun/rewrite-gsrc-to-jsrc
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 91c0a45e9fdc47b9f882193c5e8a0180e3551b14
Author: Daniel Sun <[email protected]>
AuthorDate: Sat Aug 14 14:00:57 2021 +0800

    Rewrite Groovy source code in core to Java
---
 .../groovy/transform/tailrec/AstHelper.groovy      |  75 --------
 .../groovy/transform/tailrec/AstHelper.java        |  78 ++++++++
 .../transform/tailrec/CollectRecursiveCalls.groovy |  60 ------
 .../transform/tailrec/CollectRecursiveCalls.java   |  64 ++++++
 .../transform/tailrec/GotoRecurHereException.java  |  26 +++
 .../transform/tailrec/HasRecursiveCalls.groovy     |  61 ------
 .../transform/tailrec/HasRecursiveCalls.java       |  63 ++++++
 .../transform/tailrec/InWhileLoopWrapper.groovy    |  83 --------
 .../transform/tailrec/InWhileLoopWrapper.java      |  60 ++++++
 .../transform/tailrec/RecursivenessTester.groovy   | 101 ----------
 .../transform/tailrec/RecursivenessTester.java     | 121 ++++++++++++
 ...Closures.groovy => ReturnAdderForClosures.java} |  31 ++-
 .../transform/tailrec/StatementReplacer.groovy     | 106 ----------
 .../transform/tailrec/StatementReplacer.java       | 169 ++++++++++++++++
 .../tailrec/VariableExpressionReplacer.groovy      | 163 ----------------
 .../tailrec/VariableExpressionReplacer.java        | 214 +++++++++++++++++++++
 .../tailrec/VariableExpressionTransformer.groovy   |  46 -----
 .../tailrec/VariableExpressionTransformer.java     |  66 +++++++
 18 files changed, 876 insertions(+), 711 deletions(-)

diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/AstHelper.groovy 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/AstHelper.groovy
deleted file mode 100644
index 35cf13f..0000000
--- a/src/main/groovy/org/codehaus/groovy/transform/tailrec/AstHelper.groovy
+++ /dev/null
@@ -1,75 +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.Expression
-import org.codehaus.groovy.ast.expr.VariableExpression
-import org.codehaus.groovy.ast.stmt.ContinueStatement
-import org.codehaus.groovy.ast.stmt.ExpressionStatement
-import org.codehaus.groovy.ast.stmt.Statement
-
-import java.lang.reflect.Modifier
-
-import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.declS
-import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS
-import static org.codehaus.groovy.ast.tools.GeneralUtils.varX
-
-/**
- * Helping to create a few standard AST constructs
- */
-@CompileStatic
-class AstHelper {
-    static ExpressionStatement createVariableDefinition(String variableName, 
ClassNode variableType, Expression value, boolean variableShouldBeFinal = 
false) {
-        def newVariable = localVarX(variableName, variableType)
-        if (variableShouldBeFinal)
-            newVariable.modifiers = Modifier.FINAL
-        (ExpressionStatement) declS(newVariable, value)
-    }
-
-    static ExpressionStatement createVariableAlias(String aliasName, ClassNode 
variableType, String variableName) {
-        createVariableDefinition(aliasName, variableType, varX(variableName, 
variableType))
-    }
-
-    static VariableExpression createVariableReference(Map variableSpec) {
-        varX((String) variableSpec.name, (ClassNode) variableSpec.type)
-    }
-
-    /**
-     * This statement should make the code jump to surrounding while loop's 
start label
-     * Does not work from within Closures
-     */
-    static Statement recurStatement() {
-        //continue _RECUR_HERE_
-        new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL)
-    }
-
-    /**
-     * This statement will throw exception which will be caught and redirected 
to jump to surrounding while loop's start label
-     * Also works from within Closures but is a tiny bit slower
-     */
-    static Statement recurByThrowStatement() {
-        // throw InWhileLoopWrapper.LOOP_EXCEPTION
-        throwS(propX(classX(InWhileLoopWrapper), 'LOOP_EXCEPTION'))
-    }
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/AstHelper.java 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/AstHelper.java
new file mode 100644
index 0000000..fc09f6c
--- /dev/null
+++ b/src/main/groovy/org/codehaus/groovy/transform/tailrec/AstHelper.java
@@ -0,0 +1,78 @@
+/*
+ *  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.ClassNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+
+/**
+ * Helping to create a few standard AST constructs
+ */
+class AstHelper {
+    public static ExpressionStatement createVariableDefinition(String 
variableName, ClassNode variableType, Expression value) {
+        return createVariableDefinition(variableName, variableType, value, 
false);
+    }
+
+    public static ExpressionStatement createVariableDefinition(String 
variableName, ClassNode variableType, Expression value, boolean 
variableShouldBeFinal) {
+        VariableExpression newVariable = localVarX(variableName, variableType);
+        if (variableShouldBeFinal)
+            newVariable.setModifiers(Modifier.FINAL);
+        return (ExpressionStatement) declS(newVariable, value);
+    }
+
+    public static ExpressionStatement createVariableAlias(String aliasName, 
ClassNode variableType, String variableName) {
+        return createVariableDefinition(aliasName, variableType, 
varX(variableName, variableType));
+    }
+
+    public static VariableExpression createVariableReference(Map<String, ?> 
variableSpec) {
+        return varX((String) variableSpec.get("name"), (ClassNode) 
variableSpec.get("type"));
+    }
+
+    /**
+     * This statement should make the code jump to surrounding while loop's 
start label
+     * Does not work from within Closures
+     */
+    public static Statement recurStatement() {
+        //continue _RECUR_HERE_
+        return new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL);
+    }
+
+    /**
+     * This statement will throw exception which will be caught and redirected 
to jump to surrounding while loop's start label
+     * Also works from within Closures but is a tiny bit slower
+     */
+    public static Statement recurByThrowStatement() {
+        // throw InWhileLoopWrapper.LOOP_EXCEPTION
+        return throwS(propX(classX(InWhileLoopWrapper.class), 
"LOOP_EXCEPTION"));
+    }
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/CollectRecursiveCalls.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/CollectRecursiveCalls.groovy
deleted file mode 100644
index 3f586d8..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/CollectRecursiveCalls.groovy
+++ /dev/null
@@ -1,60 +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
- */
-@CompileStatic
-class CollectRecursiveCalls extends CodeVisitorSupport {
-       MethodNode method
-       List<Expression> recursiveCalls = []
-
-       void visitMethodCallExpression(MethodCallExpression call) {
-               if (isRecursive(call)) {
-                       recursiveCalls << call
-               }
-        super.visitMethodCallExpression(call)
-    }
-
-       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
-       }
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/CollectRecursiveCalls.java
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/CollectRecursiveCalls.java
new file mode 100644
index 0000000..e996a86
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/CollectRecursiveCalls.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.transform.tailrec;
+
+import org.apache.groovy.util.Maps;
+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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Collect all recursive calls within method
+ */
+class CollectRecursiveCalls extends CodeVisitorSupport {
+       private final List<Expression> recursiveCalls = new ArrayList<>();
+       private MethodNode method;
+
+       @Override
+       public void visitMethodCallExpression(MethodCallExpression call) {
+               if (isRecursive(call)) {
+                       recursiveCalls.add(call);
+               }
+        super.visitMethodCallExpression(call);
+    }
+
+       @Override
+       public void visitStaticMethodCallExpression(StaticMethodCallExpression 
call) {
+               if (isRecursive(call)) {
+            recursiveCalls.add(call);
+        }
+               super.visitStaticMethodCallExpression(call);
+       }
+       
+       public synchronized List<Expression> collect(MethodNode method) {
+               recursiveCalls.clear();
+               this.method = method;
+               this.method.getCode().visit(this);
+               return recursiveCalls;
+       }
+
+       private boolean isRecursive(Expression call) {
+               return new RecursivenessTester().isRecursive(Maps.of("method", 
method, "call", call));
+       }
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/GotoRecurHereException.java
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/GotoRecurHereException.java
new file mode 100644
index 0000000..54375ca
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/GotoRecurHereException.java
@@ -0,0 +1,26 @@
+/*
+ *  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;
+
+/**
+ * Exception will be thrown by recursive calls in closures and caught in while 
loop to continue to LOOP_LABEL
+ */
+public class GotoRecurHereException extends Exception {
+    private static final long serialVersionUID = -193137033604506378L;
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/HasRecursiveCalls.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/HasRecursiveCalls.groovy
deleted file mode 100644
index e8799c3..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/HasRecursiveCalls.groovy
+++ /dev/null
@@ -1,61 +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
- */
-@CompileStatic
-class HasRecursiveCalls extends CodeVisitorSupport {
-    MethodNode method
-    boolean hasRecursiveCalls = false
-
-    void visitMethodCallExpression(MethodCallExpression call) {
-        if (isRecursive(call)) {
-            hasRecursiveCalls = true
-        } else {
-            super.visitMethodCallExpression(call)
-        }
-    }
-
-    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
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/HasRecursiveCalls.java 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/HasRecursiveCalls.java
new file mode 100644
index 0000000..9042ed2
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/HasRecursiveCalls.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.transform.tailrec;
+
+import org.apache.groovy.util.Maps;
+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;
+
+/**
+ * Check if there are any recursive calls in a method
+ */
+class HasRecursiveCalls extends CodeVisitorSupport {
+    private MethodNode method;
+    private boolean hasRecursiveCalls = false;
+
+    @Override
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        if (isRecursive(call)) {
+            hasRecursiveCalls = true;
+        } else {
+            super.visitMethodCallExpression(call);
+        }
+    }
+
+    @Override
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression 
call) {
+        if (isRecursive(call)) {
+            hasRecursiveCalls = true;
+        } else {
+            super.visitStaticMethodCallExpression(call);
+        }
+    }
+
+    public synchronized boolean test(MethodNode method) {
+        hasRecursiveCalls = false;
+        this.method = method;
+        this.method.getCode().visit(this);
+        return hasRecursiveCalls;
+    }
+
+    private boolean isRecursive(Expression call) {
+        return new RecursivenessTester().isRecursive(Maps.of("method", method, 
"call", call));
+    }
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/InWhileLoopWrapper.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/InWhileLoopWrapper.groovy
deleted file mode 100644
index d622dc5..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/InWhileLoopWrapper.groovy
+++ /dev/null
@@ -1,83 +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.VariableScope
-import org.codehaus.groovy.ast.stmt.BlockStatement
-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
-
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block
-import static org.codehaus.groovy.ast.tools.GeneralUtils.boolX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.catchS
-import static org.codehaus.groovy.ast.tools.GeneralUtils.constX
-import static org.codehaus.groovy.ast.tools.GeneralUtils.param
-import static org.codehaus.groovy.ast.tools.GeneralUtils.tryCatchS
-
-/**
- * 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:
- * <ol>
- * <li>"continue _RECUR_HERE_" is used by recursive calls outside of 
closures</li>
- * <li>"throw LOOP_EXCEPTION" is used by recursive calls within closures b/c 
you cannot invoke "continue" from there</li>
- * </ol>
- */
-@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 = tryCatchS(
-                oldBody,
-                EmptyStatement.INSTANCE,
-                catchS(
-                        param(ClassHelper.make(GotoRecurHereException), 
'ignore'),
-                        new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL)
-                ))
-
-        WhileStatement whileLoop = new WhileStatement(
-                boolX(constX(true)),
-                block(new VariableScope(method.variableScope), 
tryCatchStatement)
-        )
-        List<Statement> whileLoopStatements = ((BlockStatement) 
whileLoop.loopBlock).statements
-        if (whileLoopStatements.size() > 0)
-            whileLoopStatements[0].statementLabel = LOOP_LABEL
-               BlockStatement newBody = block(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
- */
-@CompileStatic
-class GotoRecurHereException extends Exception {
-    private static final long serialVersionUID = -193137033604506378L
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/InWhileLoopWrapper.java 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/InWhileLoopWrapper.java
new file mode 100644
index 0000000..a4d8f09
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/InWhileLoopWrapper.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.transform.tailrec;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+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;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.util.List;
+
+/**
+ * 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.
+ * <p>
+ * There are two ways to invoke the next iteration step:
+ * <ol>
+ * <li>"continue _RECUR_HERE_" is used by recursive calls outside of 
closures</li>
+ * <li>"throw LOOP_EXCEPTION" is used by recursive calls within closures b/c 
you cannot invoke "continue" from there</li>
+ * </ol>
+ */
+class InWhileLoopWrapper {
+    public void wrap(MethodNode method) {
+        BlockStatement oldBody = DefaultGroovyMethods.asType(method.getCode(), 
BlockStatement.class);
+        TryCatchStatement tryCatchStatement = GeneralUtils.tryCatchS(oldBody, 
EmptyStatement.INSTANCE, 
GeneralUtils.catchS(GeneralUtils.param(ClassHelper.make(GotoRecurHereException.class),
 "ignore"), new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL)));
+
+        WhileStatement whileLoop = new 
WhileStatement(GeneralUtils.boolX(GeneralUtils.constX(true)), 
GeneralUtils.block(new VariableScope(method.getVariableScope()), 
tryCatchStatement));
+        List<Statement> whileLoopStatements = ((BlockStatement) 
whileLoop.getLoopBlock()).getStatements();
+        if (whileLoopStatements.size() > 0) 
whileLoopStatements.get(0).setStatementLabel(LOOP_LABEL);
+        BlockStatement newBody = GeneralUtils.block(new 
VariableScope(method.getVariableScope()));
+        newBody.addStatement(whileLoop);
+        method.setCode(newBody);
+    }
+
+    public static final String LOOP_LABEL = "_RECUR_HERE_";
+    public static final GotoRecurHereException LOOP_EXCEPTION = new 
GotoRecurHereException();
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/RecursivenessTester.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/RecursivenessTester.groovy
deleted file mode 100644
index 15e24e4..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/RecursivenessTester.groovy
+++ /dev/null
@@ -1,101 +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:
- * <ul>
- * <li>Does not check for method overloading or overridden methods</li>
- * <li>Does not check for matching return types; even void and any object type 
are considered to be compatible</li>
- * <li>Argument type matching could be more specific in case of static 
compilation</li>
- * <li>Method names via a GString are never considered to be recursive</li>
- * </ul>
- */
-class RecursivenessTester {
-       boolean isRecursive(params) {
-               assert params.method.class == MethodNode
-               assert params.call.class == MethodCallExpression || 
StaticMethodCallExpression
-
-               isRecursive(params.method, params.call)
-       }
-
-    @SuppressWarnings('Instanceof')
-       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)
-       }
-
-    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)
-    }
-
-    @SuppressWarnings('Instanceof')
-       private boolean isCallToThis(MethodCallExpression call) {
-               if (call.objectExpression == null)
-                       return call.isImplicitThis()
-        if (! (call.objectExpression instanceof VariableExpression)) {
-            return false
-        }
-               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()
-        classNodePairs.every { ClassNode paramType, ClassNode argType  ->
-            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)
-        boxedArg.isDerivedFrom(boxedParam) || 
boxedParam.isDerivedFrom(boxedArg)
-    }
-
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/RecursivenessTester.java
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/RecursivenessTester.java
new file mode 100644
index 0000000..d88d88e
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/RecursivenessTester.java
@@ -0,0 +1,121 @@
+/*
+ *  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.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+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.runtime.DefaultGroovyMethods;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.codehaus.groovy.runtime.DefaultGroovyMethods.transpose;
+
+/**
+ * Test if a method call is recursive if called within a given method node.
+ * Handles static calls as well.
+ * <p>
+ * Currently known simplifications:
+ * <ul>
+ * <li>Does not check for method overloading or overridden methods</li>
+ * <li>Does not check for matching return types; even void and any object type 
are considered to be compatible</li>
+ * <li>Argument type matching could be more specific in case of static 
compilation</li>
+ * <li>Method names via a GString are never considered to be recursive</li>
+ * </ul>
+ */
+class RecursivenessTester {
+    public boolean isRecursive(Map<String, ASTNode> params) {
+        ASTNode method = params.get("method");
+        assert MethodNode.class.equals(method.getClass());
+        ASTNode call = params.get("call");
+        Class<? extends ASTNode> callClass = call.getClass();
+        assert MethodCallExpression.class.equals(callClass) || 
StaticMethodCallExpression.class.equals(callClass);
+
+        if (callClass == MethodCallExpression.class) {
+            return isRecursive((MethodNode) method, (MethodCallExpression) 
call);
+        }
+        return isRecursive((MethodNode) method, (StaticMethodCallExpression) 
call);
+    }
+
+    @SuppressWarnings("Instanceof")
+    public boolean isRecursive(MethodNode method, MethodCallExpression call) {
+        if (!isCallToThis(call)) return false;
+        // Could be a GStringExpression
+        if (!(call.getMethod() instanceof ConstantExpression)) return false;
+        if (!((ConstantExpression) 
call.getMethod()).getValue().equals(method.getName())) return false;
+        return methodParamsMatchCallArgs(method, call);
+    }
+
+    public boolean isRecursive(MethodNode method, StaticMethodCallExpression 
call) {
+        if (!method.isStatic()) return false;
+        if (!method.getDeclaringClass().equals(call.getOwnerType())) return 
false;
+        if (!call.getMethod().equals(method.getName())) return false;
+        return methodParamsMatchCallArgs(method, call);
+    }
+
+    @SuppressWarnings("Instanceof")
+    private boolean isCallToThis(MethodCallExpression call) {
+        if (call.getObjectExpression() == null) return call.isImplicitThis();
+        if (!(call.getObjectExpression() instanceof VariableExpression)) {
+            return false;
+        }
+
+        return ((boolean) 
(DefaultGroovyMethods.invokeMethod(call.getObjectExpression(), 
"isThisExpression", new Object[0])));
+    }
+
+    private boolean methodParamsMatchCallArgs(MethodNode method, Expression 
call) {
+        TupleExpression arguments;
+        if (call instanceof MethodCallExpression) {
+            arguments = ((TupleExpression) ((MethodCallExpression) 
call).getArguments());
+        } else {
+            arguments = ((TupleExpression) ((StaticMethodCallExpression) 
call).getArguments());
+        }
+
+        if (method.getParameters().length != arguments.getExpressions().size())
+            return false;
+
+        List<List<ClassNode>> classNodePairs =
+                transpose(Arrays.asList(
+                        
Arrays.stream(method.getParameters()).map(Parameter::getType).collect(Collectors.toList()),
+                        
arguments.getExpressions().stream().map(Expression::getType).collect(Collectors.toList())));
+        return classNodePairs.stream().allMatch(t -> 
areTypesCallCompatible(t.get(0), t.get(1)));
+    }
+
+    /**
+     * 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 Boolean areTypesCallCompatible(ClassNode argType, ClassNode 
paramType) {
+        ClassNode boxedArg = ClassHelper.getWrapper(argType);
+        ClassNode boxedParam = ClassHelper.getWrapper(paramType);
+        return boxedArg.isDerivedFrom(boxedParam) || 
boxedParam.isDerivedFrom(boxedArg);
+    }
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/ReturnAdderForClosures.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/ReturnAdderForClosures.java
similarity index 63%
rename from 
src/main/groovy/org/codehaus/groovy/transform/tailrec/ReturnAdderForClosures.groovy
rename to 
src/main/groovy/org/codehaus/groovy/transform/tailrec/ReturnAdderForClosures.java
index 62c4aa9..2dc6196 100644
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/ReturnAdderForClosures.groovy
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/ReturnAdderForClosures.java
@@ -16,31 +16,30 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.codehaus.groovy.transform.tailrec
+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
+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.
  */
 class ReturnAdderForClosures extends CodeVisitorSupport {
-
-    synchronized void visitMethod(MethodNode method) {
-        method.code.visit(this)
+    public synchronized void visitMethod(MethodNode method) {
+        method.getCode().visit(this);
     }
 
-    void visitClosureExpression(ClosureExpression expression) {
+    @Override
+    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)
+        MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, 
Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, expression.getCode());
+        new ReturnAdder().visitMethod(node);
+        super.visitClosureExpression(expression);
     }
-
 }
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/StatementReplacer.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/StatementReplacer.groovy
deleted file mode 100644
index 8c7a55a..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/StatementReplacer.groovy
+++ /dev/null
@@ -1,106 +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
- */
-@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)
-    }
-
-    void visitClosureExpression(ClosureExpression expression) {
-        closureLevel++
-        try {
-            super.visitClosureExpression(expression)
-        } finally {
-            closureLevel--
-        }
-    }
-
-    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)
-    }
-
-    void visitIfElse(IfStatement ifElse) {
-        replaceIfNecessary(ifElse.ifBlock) { Statement s -> ifElse.ifBlock = s 
}
-        replaceIfNecessary(ifElse.elseBlock) { Statement s -> ifElse.elseBlock 
= s }
-        super.visitIfElse(ifElse)
-    }
-
-    void visitForLoop(ForStatement forLoop) {
-        replaceIfNecessary(forLoop.loopBlock) { Statement s -> 
forLoop.loopBlock = s }
-        super.visitForLoop(forLoop)
-    }
-
-    void visitWhileLoop(WhileStatement loop) {
-        replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s 
}
-        super.visitWhileLoop(loop)
-    }
-
-    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.sourcePosition = nodeToCheck
-            replacement.copyNodeMetaData(nodeToCheck)
-            replacementCode(replacement)
-        }
-    }
-
-    private boolean conditionFulfilled(ASTNode nodeToCheck) {
-        if (when.maximumNumberOfParameters < 2)
-            return when(nodeToCheck)
-        when(nodeToCheck, isInClosure())
-    }
-
-    private boolean isInClosure() {
-        closureLevel > 0
-    }
-
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/StatementReplacer.java 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/StatementReplacer.java
new file mode 100644
index 0000000..a3f1c61
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/StatementReplacer.java
@@ -0,0 +1,169 @@
+/*
+ *  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.lang.Closure;
+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;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tool for replacing Statement objects in an AST by other Statement instances.
+ * <p>
+ * Within @TailRecursive it is used to swap ReturnStatements with looping back 
to RECUR label
+ */
+class StatementReplacer extends CodeVisitorSupport {
+    public void replaceIn(ASTNode root) {
+        root.visit(this);
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        closureLevel++;
+        try {
+            super.visitClosureExpression(expression);
+        } finally {
+            closureLevel--;
+        }
+    }
+
+    public void visitBlockStatement(final BlockStatement block) {
+        List<Statement> copyOfStatements = new 
ArrayList<Statement>(block.getStatements());
+        DefaultGroovyMethods.eachWithIndex(copyOfStatements, new 
Closure<Void>(this, this) {
+            public void doCall(Statement statement, final int index) {
+                replaceIfNecessary(statement, new 
Closure<Statement>(StatementReplacer.this, StatementReplacer.this) {
+                    public Statement doCall(Statement node) {
+                        block.getStatements().set(index, node);
+                        return node;
+                    }
+                });
+            }
+        });
+        super.visitBlockStatement(block);
+    }
+
+    public void visitIfElse(final IfStatement ifElse) {
+        replaceIfNecessary(ifElse.getIfBlock(), new Closure<Statement>(this, 
this) {
+            public Statement doCall(Statement s) {
+                ifElse.setIfBlock(s);
+                return s;
+            }
+        });
+        replaceIfNecessary(ifElse.getElseBlock(), new Closure<Statement>(this, 
this) {
+            public Statement doCall(Statement s) {
+                ifElse.setElseBlock(s);
+                return s;
+            }
+        });
+        super.visitIfElse(ifElse);
+    }
+
+    public void visitForLoop(final ForStatement forLoop) {
+        replaceIfNecessary(forLoop.getLoopBlock(), new 
Closure<Statement>(this, this) {
+            public Statement doCall(Statement s) {
+                forLoop.setLoopBlock(s);
+                return s;
+            }
+        });
+        super.visitForLoop(forLoop);
+    }
+
+    public void visitWhileLoop(final WhileStatement loop) {
+        replaceIfNecessary(loop.getLoopBlock(), new Closure<Statement>(this, 
this) {
+            public Statement doCall(Statement s) {
+                loop.setLoopBlock(s);
+                return s;
+            }
+        });
+        super.visitWhileLoop(loop);
+    }
+
+    public void visitDoWhileLoop(final DoWhileStatement loop) {
+        replaceIfNecessary(loop.getLoopBlock(), new Closure<Statement>(this, 
this) {
+            public Statement doCall(Statement s) {
+                loop.setLoopBlock(s);
+                return s;
+            }
+        });
+        super.visitDoWhileLoop(loop);
+    }
+
+    private void replaceIfNecessary(Statement nodeToCheck, Closure 
replacementCode) {
+        if (conditionFulfilled(nodeToCheck)) {
+            Statement replacement = replaceWith.call(nodeToCheck);
+            replacement.setSourcePosition(nodeToCheck);
+            replacement.copyNodeMetaData(nodeToCheck);
+            replacementCode.call(replacement);
+        }
+    }
+
+    private boolean conditionFulfilled(ASTNode nodeToCheck) {
+        if (when.getMaximumNumberOfParameters() < 2) return 
when.call(nodeToCheck);
+        return when.call(nodeToCheck, isInClosure());
+    }
+
+    private boolean isInClosure() {
+        return closureLevel > 0;
+    }
+
+    public Closure<Boolean> getWhen() {
+        return when;
+    }
+
+    public void setWhen(Closure<Boolean> when) {
+        this.when = when;
+    }
+
+    public Closure<Statement> getReplaceWith() {
+        return replaceWith;
+    }
+
+    public void setReplaceWith(Closure<Statement> replaceWith) {
+        this.replaceWith = replaceWith;
+    }
+
+    public int getClosureLevel() {
+        return closureLevel;
+    }
+
+    public void setClosureLevel(int closureLevel) {
+        this.closureLevel = closureLevel;
+    }
+
+    private Closure<Boolean> when = new Closure<Boolean>(this, this) {
+        public Boolean doCall(Statement node) {
+            return false;
+        }
+    };
+    private Closure<Statement> replaceWith = new Closure<Statement>(this, 
this) {
+        public Statement doCall(Statement statement) {
+            return statement;
+        }
+    };
+    private int closureLevel = 0;
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionReplacer.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionReplacer.groovy
deleted file mode 100644
index 9dbb801..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionReplacer.groovy
+++ /dev/null
@@ -1,163 +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.AutoFinal
-import groovy.transform.CompileStatic
-import org.codehaus.groovy.ast.ASTNode
-import org.codehaus.groovy.ast.CodeVisitorSupport
-import org.codehaus.groovy.ast.expr.BinaryExpression
-import org.codehaus.groovy.ast.expr.BooleanExpression
-import org.codehaus.groovy.ast.expr.Expression
-import org.codehaus.groovy.ast.expr.ExpressionTransformer
-import org.codehaus.groovy.ast.expr.VariableExpression
-import org.codehaus.groovy.ast.stmt.AssertStatement
-import org.codehaus.groovy.ast.stmt.CaseStatement
-import org.codehaus.groovy.ast.stmt.DoWhileStatement
-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.SwitchStatement
-import org.codehaus.groovy.ast.stmt.SynchronizedStatement
-import org.codehaus.groovy.ast.stmt.ThrowStatement
-import org.codehaus.groovy.ast.stmt.WhileStatement
-import org.codehaus.groovy.ast.tools.GeneralUtils
-
-import java.lang.reflect.Method
-
-/**
- * Tool for replacing VariableExpression instances in an AST by other 
VariableExpression instances.
- * Regardless of a real change taking place in nested expressions, all 
considered expression (trees) will be replaced.
- * This could be optimized to accelerate compilation.
- *
- * Within @TailRecursive it is used
- * - to swap the access of method args with the access to iteration variables
- * - to swap the access of iteration variables with the access of temp vars
- */
-@AutoFinal @CompileStatic
-class VariableExpressionReplacer extends CodeVisitorSupport {
-
-    Closure<Boolean> when = { VariableExpression node -> false }
-    Closure<VariableExpression> replaceWith = { VariableExpression 
variableExpression -> variableExpression }
-
-    private ExpressionTransformer transformer
-
-    synchronized void replaceIn(ASTNode root) {
-        transformer = new VariableExpressionTransformer(when: when, 
replaceWith: replaceWith)
-        root.visit(this)
-    }
-
-    void visitReturnStatement(ReturnStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement)
-        super.visitReturnStatement(statement)
-    }
-
-    void visitIfElse(IfStatement ifElse) {
-        replaceExpressionPropertyWhenNecessary(ifElse, 'booleanExpression', 
BooleanExpression)
-        super.visitIfElse(ifElse)
-    }
-
-    void visitForLoop(ForStatement forLoop) {
-        replaceExpressionPropertyWhenNecessary(forLoop, 'collectionExpression')
-        super.visitForLoop(forLoop)
-    }
-
-    /**
-     * It's the only Expression type in which replacing is considered.
-     * That's an abuse of the class, but I couldn't think of a better way.
-     */
-    void visitBinaryExpression(BinaryExpression expression) {
-        //A hack: Only replace right expression b/c 
ReturnStatementToIterationConverter needs it that way :-/
-        replaceExpressionPropertyWhenNecessary(expression, 'rightExpression')
-        expression.rightExpression.visit(this)
-        super.visitBinaryExpression(expression)
-    }
-
-    void visitWhileLoop(WhileStatement loop) {
-        replaceExpressionPropertyWhenNecessary(loop, 'booleanExpression', 
BooleanExpression)
-        super.visitWhileLoop(loop)
-    }
-
-    void visitDoWhileLoop(DoWhileStatement loop) {
-        replaceExpressionPropertyWhenNecessary(loop, 'booleanExpression', 
BooleanExpression)
-        super.visitDoWhileLoop(loop)
-    }
-
-    void visitSwitch(SwitchStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement)
-        super.visitSwitch(statement)
-    }
-
-    void visitCaseStatement(CaseStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement)
-        super.visitCaseStatement(statement)
-    }
-
-    void visitExpressionStatement(ExpressionStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement)
-        super.visitExpressionStatement(statement)
-    }
-
-    void visitThrowStatement(ThrowStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement)
-        super.visitThrowStatement(statement)
-    }
-
-    void visitAssertStatement(AssertStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement, 'booleanExpression', 
BooleanExpression)
-        replaceExpressionPropertyWhenNecessary(statement, 'messageExpression')
-        super.visitAssertStatement(statement)
-    }
-
-    void visitSynchronizedStatement(SynchronizedStatement statement) {
-        replaceExpressionPropertyWhenNecessary(statement)
-        super.visitSynchronizedStatement(statement)
-    }
-
-    private void replaceExpressionPropertyWhenNecessary(ASTNode node, String 
propName = 'expression', Class propClass = Expression) {
-        Expression expr = getExpression(node, propName)
-
-        if (expr instanceof VariableExpression) {
-            if (when(expr)) {
-                VariableExpression newExpr = replaceWith(expr)
-                replaceExpression(node, propName, propClass, expr, newExpr)
-            }
-        } else {
-            Expression newExpr = transformer.transform(expr)
-            replaceExpression(node, propName, propClass, expr, newExpr)
-        }
-    }
-
-    private void replaceExpression(ASTNode node, String propName, Class 
propClass, Expression oldExpr, Expression newExpr) {
-        //Use reflection to enable CompileStatic
-        String setterName = GeneralUtils.getSetterName(propName)
-        Method setExpressionMethod = node.class.getMethod(setterName, 
propClass)
-        newExpr.copyNodeMetaData(oldExpr)
-        newExpr.setSourcePosition(oldExpr)
-        setExpressionMethod.invoke(node, newExpr)
-    }
-
-    private Expression getExpression(ASTNode node, String propName) {
-        //Use reflection to enable CompileStatic
-        String getterName = GeneralUtils.getGetterName(propName)
-        Method getExpressionMethod = node.class.getMethod(getterName)
-        getExpressionMethod.invoke(node) as Expression
-    }
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionReplacer.java
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionReplacer.java
new file mode 100644
index 0000000..e400983
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionReplacer.java
@@ -0,0 +1,214 @@
+/*
+ *  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.lang.Closure;
+import org.apache.groovy.internal.util.UncheckedThrow;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+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.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.lang.reflect.Method;
+
+/**
+ * Tool for replacing VariableExpression instances in an AST by other 
VariableExpression instances.
+ * Regardless of a real change taking place in nested expressions, all 
considered expression (trees) will be replaced.
+ * This could be optimized to accelerate compilation.
+ * <p>
+ * Within @TailRecursive it is used
+ * - to swap the access of method args with the access to iteration variables
+ * - to swap the access of iteration variables with the access of temp vars
+ */
+class VariableExpressionReplacer extends CodeVisitorSupport {
+    @Override
+    public void visitReturnStatement(final ReturnStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement);
+        super.visitReturnStatement(statement);
+    }
+
+    @Override
+    public void visitIfElse(final IfStatement ifElse) {
+        replaceExpressionPropertyWhenNecessary(ifElse, "booleanExpression", 
BooleanExpression.class);
+        super.visitIfElse(ifElse);
+    }
+
+    @Override
+    public void visitForLoop(final ForStatement forLoop) {
+        replaceExpressionPropertyWhenNecessary(forLoop, 
"collectionExpression");
+        super.visitForLoop(forLoop);
+    }
+
+    /**
+     * It's the only Expression type in which replacing is considered.
+     * That's an abuse of the class, but I couldn't think of a better way.
+     */
+    @Override
+    public void visitBinaryExpression(final BinaryExpression expression) {
+        //A hack: Only replace right expression b/c 
ReturnStatementToIterationConverter needs it that way :-/
+        replaceExpressionPropertyWhenNecessary(expression, "rightExpression");
+        expression.getRightExpression().visit(this);
+        super.visitBinaryExpression(expression);
+    }
+
+    @Override
+    public void visitWhileLoop(final WhileStatement loop) {
+        replaceExpressionPropertyWhenNecessary(loop, "booleanExpression", 
BooleanExpression.class);
+        super.visitWhileLoop(loop);
+    }
+
+    @Override
+    public void visitDoWhileLoop(final DoWhileStatement loop) {
+        replaceExpressionPropertyWhenNecessary(loop, "booleanExpression", 
BooleanExpression.class);
+        super.visitDoWhileLoop(loop);
+    }
+
+    @Override
+    public void visitSwitch(final SwitchStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement);
+        super.visitSwitch(statement);
+    }
+
+    @Override
+    public void visitCaseStatement(final CaseStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement);
+        super.visitCaseStatement(statement);
+    }
+
+    @Override
+    public void visitExpressionStatement(final ExpressionStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement);
+        super.visitExpressionStatement(statement);
+    }
+
+    @Override
+    public void visitThrowStatement(final ThrowStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement);
+        super.visitThrowStatement(statement);
+    }
+
+    @Override
+    public void visitAssertStatement(final AssertStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement, "booleanExpression", 
BooleanExpression.class);
+        replaceExpressionPropertyWhenNecessary(statement, "messageExpression");
+        super.visitAssertStatement(statement);
+    }
+
+    @Override
+    public void visitSynchronizedStatement(final SynchronizedStatement 
statement) {
+        replaceExpressionPropertyWhenNecessary(statement);
+        super.visitSynchronizedStatement(statement);
+    }
+
+    public synchronized void replaceIn(final ASTNode root) {
+        transformer = new VariableExpressionTransformer(when, replaceWith);
+        root.visit(this);
+    }
+
+    private void replaceExpressionPropertyWhenNecessary(final ASTNode node, 
final String propName, final Class propClass) {
+        Expression expr = getExpression(node, propName);
+
+        if (expr instanceof VariableExpression) {
+            if (when.call(expr)) {
+                VariableExpression newExpr = replaceWith.call(expr);
+                replaceExpression(node, propName, propClass, expr, newExpr);
+            }
+        } else {
+            Expression newExpr = transformer.transform(expr);
+            replaceExpression(node, propName, propClass, expr, newExpr);
+        }
+    }
+
+    private void replaceExpressionPropertyWhenNecessary(final ASTNode node, 
final String propName) {
+        replaceExpressionPropertyWhenNecessary(node, propName, 
Expression.class);
+    }
+
+    private void replaceExpressionPropertyWhenNecessary(final ASTNode node) {
+        replaceExpressionPropertyWhenNecessary(node, "expression", 
Expression.class);
+    }
+
+    private void replaceExpression(final ASTNode node, final String propName, 
final Class propClass, final Expression oldExpr, final Expression newExpr) {
+        try {
+            //Use reflection to enable CompileStatic
+            String setterName = GeneralUtils.getSetterName(propName);
+            Method setExpressionMethod = node.getClass().getMethod(setterName, 
propClass);
+            newExpr.copyNodeMetaData(oldExpr);
+            newExpr.setSourcePosition(oldExpr);
+            setExpressionMethod.invoke(node, newExpr);
+        } catch (Throwable t) {
+            UncheckedThrow.rethrow(t);
+        }
+    }
+
+    private Expression getExpression(final ASTNode node, final String 
propName) {
+        try {
+            //Use reflection to enable CompileStatic
+            String getterName = GeneralUtils.getGetterName(propName);
+            Method getExpressionMethod = node.getClass().getMethod(getterName);
+            return 
DefaultGroovyMethods.asType(getExpressionMethod.invoke(node), Expression.class);
+        } catch (Throwable t) {
+            UncheckedThrow.rethrow(t);
+            return null;
+        }
+    }
+
+    public Closure<Boolean> getWhen() {
+        return when;
+    }
+
+    public void setWhen(Closure<Boolean> when) {
+        this.when = when;
+    }
+
+    public Closure<VariableExpression> getReplaceWith() {
+        return replaceWith;
+    }
+
+    public void setReplaceWith(Closure<VariableExpression> replaceWith) {
+        this.replaceWith = replaceWith;
+    }
+
+    private Closure<Boolean> when = new Closure<Boolean>(this, this) {
+        public Boolean doCall(final VariableExpression node) {
+            return false;
+        }
+    };
+    private Closure<VariableExpression> replaceWith = new 
Closure<VariableExpression>(this, this) {
+        public VariableExpression doCall(final VariableExpression 
variableExpression) {
+            return variableExpression;
+        }
+    };
+    private ExpressionTransformer transformer;
+}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionTransformer.groovy
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionTransformer.groovy
deleted file mode 100644
index 9683bc9..0000000
--- 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionTransformer.groovy
+++ /dev/null
@@ -1,46 +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.expr.Expression
-import org.codehaus.groovy.ast.expr.ExpressionTransformer
-import org.codehaus.groovy.ast.expr.VariableExpression
-
-/**
- * An expression transformer used in the process of replacing the access to 
variables
- */
-@CompileStatic
-class VariableExpressionTransformer implements ExpressionTransformer {
-
-    Closure<Boolean> when
-    Closure<VariableExpression> replaceWith
-
-    @Override
-    @SuppressWarnings('Instanceof')
-    Expression transform(Expression expr) {
-        if ((expr instanceof VariableExpression) && when(expr)) {
-            VariableExpression newExpr = replaceWith(expr)
-            newExpr.sourcePosition = expr
-            newExpr.copyNodeMetaData(expr)
-            return newExpr
-        }
-        expr.transformExpression(this)
-    }
-}
diff --git 
a/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionTransformer.java
 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionTransformer.java
new file mode 100644
index 0000000..78a8360
--- /dev/null
+++ 
b/src/main/groovy/org/codehaus/groovy/transform/tailrec/VariableExpressionTransformer.java
@@ -0,0 +1,66 @@
+/*
+ *  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.lang.Closure;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+
+/**
+ * An expression transformer used in the process of replacing the access to 
variables
+ */
+class VariableExpressionTransformer implements ExpressionTransformer {
+    public VariableExpressionTransformer(Closure<Boolean> when, 
Closure<VariableExpression> replaceWith) {
+        this.when = when;
+        this.replaceWith = replaceWith;
+    }
+
+    @Override
+    @SuppressWarnings("Instanceof")
+    public Expression transform(Expression expr) {
+        if ((expr instanceof VariableExpression) && when.call(expr)) {
+            VariableExpression newExpr = replaceWith.call(expr);
+            newExpr.setSourcePosition(expr);
+            newExpr.copyNodeMetaData(expr);
+            return newExpr;
+        }
+
+        return expr.transformExpression(this);
+    }
+
+    public Closure<Boolean> getWhen() {
+        return when;
+    }
+
+    public void setWhen(Closure<Boolean> when) {
+        this.when = when;
+    }
+
+    public Closure<VariableExpression> getReplaceWith() {
+        return replaceWith;
+    }
+
+    public void setReplaceWith(Closure<VariableExpression> replaceWith) {
+        this.replaceWith = replaceWith;
+    }
+
+    private Closure<Boolean> when;
+    private Closure<VariableExpression> replaceWith;
+}

Reply via email to