public class CpsTransformer
extends org.codehaus.groovy.control.customizers.CompilationCustomizer
implements org.codehaus.groovy.ast.GroovyCodeVisitor
Every method not annotated with NonCPS gets rewritten. The general
strategy of CPS transformation is as follows:
Before:
Object foo(int x, int y) {
return x+y;
}
After:
Object foo(int x, int y) {
// the first part is AST of the method body
// the rest (including implicit receiver argument) is actual value of arguments
throw new CpsCallableInvocation(___cps___N, this, new Object[] {x, y});
}
private static CpsFunction ___cps___N = ___cps___N();
private static final CpsFunction ___cps___N() {
Builder b = new Builder(...);
return new CpsFunction(['x','y'], b.plus(b.localVariable("x"), b.localVariable("y"))
}
That is, we transform a Groovy AST of the method body into a tree of
Blocks by using Builder, then the method just returns this
function object and expect the caller to evaluate it, instead of executing
the method synchronously before it returns.
This class achieves this transformation by implementing
GroovyCodeVisitor and traverse Groovy AST tree in the in-order. As we
traverse this tree, we produce another Groovy AST tree that invokes
Builder. Note that we aren't calling Builder directly here; that's
supposed to happen when the Groovy code under transformation actually runs.
Groovy AST that calls Builder is a tree of function call, so we build
MethodCallExpressions in the top-down manner. We do this by
makeNode(String, Runnable), which creates a call to
Builder.xxx(...), then supply the closure that fills in the arguments
to this call by walking down the original Groovy AST tree. This walk-down is
done by calling visit(ASTNode) (to recursively visit
ASTs), or by calling literal(String) methods, which
generate string/class/etc literals, as sometimes Builder methods need
them as well.
| Modifier and Type | Class and Description |
|---|---|
protected static interface |
CpsTransformer.ParentClosure |
| Modifier and Type | Field and Description |
|---|---|
protected org.codehaus.groovy.ast.ClassNode |
classNode |
protected TransformerConfiguration |
config |
static AtomicLong |
iota |
protected CpsTransformer.ParentClosure |
parent
As we visit expressions in the method body, we convert them to the
Builder invocations and pass them back to this closure. |
| Constructor and Description |
|---|
CpsTransformer() |
| Modifier and Type | Method and Description |
|---|---|
void |
call(org.codehaus.groovy.control.SourceUnit source,
org.codehaus.groovy.classgen.GeneratorContext context,
org.codehaus.groovy.ast.ClassNode classNode) |
protected void |
getMultipleAssignmentValueOrCast(org.codehaus.groovy.ast.expr.VariableExpression varExp,
org.codehaus.groovy.ast.expr.Expression rhs,
org.codehaus.groovy.ast.expr.Expression index) |
protected Class |
getTrustTag()
|
protected void |
literal(boolean b) |
protected void |
literal(org.codehaus.groovy.ast.ClassNode c) |
protected void |
literal(int n) |
protected void |
literal(String s)
Used in the closure block of
makeNode(String, Runnable) to create
a literal string argument. |
protected void |
loc(org.codehaus.groovy.ast.ASTNode e) |
protected org.codehaus.groovy.ast.expr.Expression |
makeBuilder(org.codehaus.groovy.ast.MethodNode m)
Generates code that instantiates a new
Builder. |
protected org.codehaus.groovy.ast.expr.TupleExpression |
makeChildren(org.codehaus.groovy.ast.expr.Expression... args)
Shorthand for
TupleExpression.TupleExpression(Expression[]). |
protected org.codehaus.groovy.ast.expr.TupleExpression |
makeChildren(Runnable body)
Given closure, package them up into a tuple.
|
protected void |
makeNode(org.codehaus.groovy.ast.ClassNode type,
org.codehaus.groovy.ast.expr.Expression... args)
Makes an AST fragment that instantiates a new instance of the given type.
|
protected void |
makeNode(org.codehaus.groovy.ast.ClassNode type,
Runnable body)
Makes an AST fragment that instantiates a new instance of the given type.
|
protected void |
makeNode(String methodName,
org.codehaus.groovy.ast.expr.Expression... args)
Makes an AST fragment that calls
Builder with specific method. |
protected void |
makeNode(String methodName,
Runnable body)
Makes an AST fragment that calls
Builder with specific method. |
protected String |
prepostfixOperatorSuffix(org.codehaus.groovy.syntax.Token operation) |
protected void |
processConstructors(org.codehaus.groovy.ast.ClassNode classNode)
Constructors can't be transformed - if we throw a
CpsCallableInvocation from inside a constructor, there's
no way to get back to the continuation. |
void |
setConfiguration(TransformerConfiguration config) |
protected boolean |
shouldBeTransformed(org.codehaus.groovy.ast.MethodNode node)
Should this method be transformed?
|
protected void |
visit(org.codehaus.groovy.ast.ASTNode e) |
protected void |
visit(Collection<? extends org.codehaus.groovy.ast.ASTNode> col) |
void |
visitArgumentlistExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression expression) |
void |
visitArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression exp) |
void |
visitAssertStatement(org.codehaus.groovy.ast.stmt.AssertStatement statement) |
protected void |
visitAssignmentOrCast(org.codehaus.groovy.ast.expr.VariableExpression varExp,
org.codehaus.groovy.ast.expr.Expression rhs) |
void |
visitAttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression exp) |
void |
visitBinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression exp) |
void |
visitBitwiseNegationExpression(org.codehaus.groovy.ast.expr.BitwiseNegationExpression exp) |
void |
visitBlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement b) |
void |
visitBooleanExpression(org.codehaus.groovy.ast.expr.BooleanExpression exp) |
void |
visitBreakStatement(org.codehaus.groovy.ast.stmt.BreakStatement statement) |
void |
visitBytecodeExpression(org.codehaus.groovy.classgen.BytecodeExpression expression) |
void |
visitCaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement stmt) |
void |
visitCastExpression(org.codehaus.groovy.ast.expr.CastExpression exp) |
void |
visitCatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement stmt) |
void |
visitClassExpression(org.codehaus.groovy.ast.expr.ClassExpression expression) |
void |
visitClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression exp) |
void |
visitClosureListExpression(org.codehaus.groovy.ast.expr.ClosureListExpression closureListExpression) |
void |
visitConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression expression) |
void |
visitConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression call) |
void |
visitContinueStatement(org.codehaus.groovy.ast.stmt.ContinueStatement statement) |
void |
visitDeclarationExpression(org.codehaus.groovy.ast.expr.DeclarationExpression exp) |
void |
visitDoWhileLoop(org.codehaus.groovy.ast.stmt.DoWhileStatement loop) |
void |
visitExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement statement) |
void |
visitFieldExpression(org.codehaus.groovy.ast.expr.FieldExpression exp) |
void |
visitForLoop(org.codehaus.groovy.ast.stmt.ForStatement forLoop) |
void |
visitGStringExpression(org.codehaus.groovy.ast.expr.GStringExpression exp) |
void |
visitIfElse(org.codehaus.groovy.ast.stmt.IfStatement stmt) |
void |
visitListExpression(org.codehaus.groovy.ast.expr.ListExpression exp) |
void |
visitMapEntryExpression(org.codehaus.groovy.ast.expr.MapEntryExpression expression) |
void |
visitMapExpression(org.codehaus.groovy.ast.expr.MapExpression exp) |
void |
visitMethod(org.codehaus.groovy.ast.MethodNode m)
Transforms asynchronous workflow method.
|
void |
visitMethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression call) |
void |
visitMethodPointerExpression(org.codehaus.groovy.ast.expr.MethodPointerExpression exp) |
protected void |
visitNontransformedField(org.codehaus.groovy.ast.FieldNode f) |
protected void |
visitNontransformedMethod(org.codehaus.groovy.ast.MethodNode m)
For methods that are not CPS-transformed.
|
protected void |
visitNontransformedStatement(org.codehaus.groovy.ast.stmt.Statement s) |
void |
visitNotExpression(org.codehaus.groovy.ast.expr.NotExpression exp) |
void |
visitPostfixExpression(org.codehaus.groovy.ast.expr.PostfixExpression exp) |
void |
visitPrefixExpression(org.codehaus.groovy.ast.expr.PrefixExpression exp) |
void |
visitPropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression exp) |
void |
visitRangeExpression(org.codehaus.groovy.ast.expr.RangeExpression exp) |
void |
visitReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement statement) |
void |
visitShortTernaryExpression(org.codehaus.groovy.ast.expr.ElvisOperatorExpression exp) |
void |
visitSpreadExpression(org.codehaus.groovy.ast.expr.SpreadExpression expression) |
void |
visitSpreadMapExpression(org.codehaus.groovy.ast.expr.SpreadMapExpression expression) |
void |
visitStaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression exp) |
void |
visitSwitch(org.codehaus.groovy.ast.stmt.SwitchStatement stmt) |
void |
visitSynchronizedStatement(org.codehaus.groovy.ast.stmt.SynchronizedStatement statement) |
void |
visitTernaryExpression(org.codehaus.groovy.ast.expr.TernaryExpression exp) |
void |
visitThrowStatement(org.codehaus.groovy.ast.stmt.ThrowStatement st) |
void |
visitTryCatchFinally(org.codehaus.groovy.ast.stmt.TryCatchStatement stmt) |
void |
visitTupleExpression(org.codehaus.groovy.ast.expr.TupleExpression expression) |
void |
visitUnaryMinusExpression(org.codehaus.groovy.ast.expr.UnaryMinusExpression exp) |
void |
visitUnaryPlusExpression(org.codehaus.groovy.ast.expr.UnaryPlusExpression exp) |
void |
visitVariableExpression(org.codehaus.groovy.ast.expr.VariableExpression exp) |
void |
visitWhileLoop(org.codehaus.groovy.ast.stmt.WhileStatement loop) |
protected void |
visitWithSafepoint(org.codehaus.groovy.ast.stmt.Statement st)
Like
visit(ASTNode) but also inserts the safepoint at the top. |
public static final AtomicLong iota
protected org.codehaus.groovy.ast.ClassNode classNode
protected TransformerConfiguration config
protected CpsTransformer.ParentClosure parent
Builder invocations and pass them back to this closure.public void setConfiguration(@Nonnull TransformerConfiguration config)
public void call(org.codehaus.groovy.control.SourceUnit source,
org.codehaus.groovy.classgen.GeneratorContext context,
org.codehaus.groovy.ast.ClassNode classNode)
call in class org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperationprotected void processConstructors(org.codehaus.groovy.ast.ClassNode classNode)
CpsCallableInvocation from inside a constructor, there's
no way to get back to the continuation. The object does not get created and so we're unable to proceed with it.
The same thing applies for object initializers.protected boolean shouldBeTransformed(org.codehaus.groovy.ast.MethodNode node)
public void visitMethod(org.codehaus.groovy.ast.MethodNode m)
protected org.codehaus.groovy.ast.expr.Expression makeBuilder(org.codehaus.groovy.ast.MethodNode m)
Builder.
Hook for subtypes to tweak builder, for example to
Builder.contextualize(com.cloudbees.groovy.cps.sandbox.CallSiteTag...)
Builder b = new Builder(new MethodLocation(...)); b.withClosureType(...);
m - Method being transformed.protected Class getTrustTag()
protected void visitNontransformedMethod(org.codehaus.groovy.ast.MethodNode m)
protected void visitNontransformedField(org.codehaus.groovy.ast.FieldNode f)
protected void visitNontransformedStatement(org.codehaus.groovy.ast.stmt.Statement s)
protected void visit(org.codehaus.groovy.ast.ASTNode e)
protected void visit(Collection<? extends org.codehaus.groovy.ast.ASTNode> col)
protected void visitWithSafepoint(org.codehaus.groovy.ast.stmt.Statement st)
visit(ASTNode) but also inserts the safepoint at the top.protected void makeNode(String methodName, org.codehaus.groovy.ast.expr.Expression... args)
Builder with specific method.methodName - Method on Builder to call.protected void makeNode(String methodName, Runnable body)
Builder with specific method.methodName - Method on Builder to call.protected void makeNode(org.codehaus.groovy.ast.ClassNode type,
org.codehaus.groovy.ast.expr.Expression... args)
protected void makeNode(org.codehaus.groovy.ast.ClassNode type,
Runnable body)
protected org.codehaus.groovy.ast.expr.TupleExpression makeChildren(org.codehaus.groovy.ast.expr.Expression... args)
TupleExpression.TupleExpression(Expression[]).protected org.codehaus.groovy.ast.expr.TupleExpression makeChildren(Runnable body)
protected void loc(org.codehaus.groovy.ast.ASTNode e)
protected void literal(String s)
makeNode(String, Runnable) to create
a literal string argument.protected void literal(org.codehaus.groovy.ast.ClassNode c)
protected void literal(int n)
protected void literal(boolean b)
public void visitMethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression call)
visitMethodCallExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitBlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement b)
visitBlockStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitForLoop(org.codehaus.groovy.ast.stmt.ForStatement forLoop)
visitForLoop in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitWhileLoop(org.codehaus.groovy.ast.stmt.WhileStatement loop)
visitWhileLoop in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitDoWhileLoop(org.codehaus.groovy.ast.stmt.DoWhileStatement loop)
visitDoWhileLoop in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitIfElse(org.codehaus.groovy.ast.stmt.IfStatement stmt)
visitIfElse in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement statement)
visitExpressionStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement statement)
visitReturnStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitAssertStatement(org.codehaus.groovy.ast.stmt.AssertStatement statement)
visitAssertStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitTryCatchFinally(org.codehaus.groovy.ast.stmt.TryCatchStatement stmt)
visitTryCatchFinally in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitSwitch(org.codehaus.groovy.ast.stmt.SwitchStatement stmt)
visitSwitch in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitCaseStatement(org.codehaus.groovy.ast.stmt.CaseStatement stmt)
visitCaseStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitBreakStatement(org.codehaus.groovy.ast.stmt.BreakStatement statement)
visitBreakStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitContinueStatement(org.codehaus.groovy.ast.stmt.ContinueStatement statement)
visitContinueStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitThrowStatement(org.codehaus.groovy.ast.stmt.ThrowStatement st)
visitThrowStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitSynchronizedStatement(org.codehaus.groovy.ast.stmt.SynchronizedStatement statement)
visitSynchronizedStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitCatchStatement(org.codehaus.groovy.ast.stmt.CatchStatement stmt)
visitCatchStatement in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitStaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression exp)
visitStaticMethodCallExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitConstructorCallExpression(org.codehaus.groovy.ast.expr.ConstructorCallExpression call)
visitConstructorCallExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitTernaryExpression(org.codehaus.groovy.ast.expr.TernaryExpression exp)
visitTernaryExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitShortTernaryExpression(org.codehaus.groovy.ast.expr.ElvisOperatorExpression exp)
visitShortTernaryExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorprotected void getMultipleAssignmentValueOrCast(org.codehaus.groovy.ast.expr.VariableExpression varExp,
org.codehaus.groovy.ast.expr.Expression rhs,
org.codehaus.groovy.ast.expr.Expression index)
public void visitBinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression exp)
visitBinaryExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorBinaryExpressionHelper.eval(BinaryExpression)public void visitPrefixExpression(org.codehaus.groovy.ast.expr.PrefixExpression exp)
visitPrefixExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitPostfixExpression(org.codehaus.groovy.ast.expr.PostfixExpression exp)
visitPostfixExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorprotected String prepostfixOperatorSuffix(org.codehaus.groovy.syntax.Token operation)
public void visitBooleanExpression(org.codehaus.groovy.ast.expr.BooleanExpression exp)
visitBooleanExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitClosureExpression(org.codehaus.groovy.ast.expr.ClosureExpression exp)
visitClosureExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitTupleExpression(org.codehaus.groovy.ast.expr.TupleExpression expression)
visitTupleExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitMapExpression(org.codehaus.groovy.ast.expr.MapExpression exp)
visitMapExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitMapEntryExpression(org.codehaus.groovy.ast.expr.MapEntryExpression expression)
visitMapEntryExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitListExpression(org.codehaus.groovy.ast.expr.ListExpression exp)
visitListExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitRangeExpression(org.codehaus.groovy.ast.expr.RangeExpression exp)
visitRangeExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitPropertyExpression(org.codehaus.groovy.ast.expr.PropertyExpression exp)
visitPropertyExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitAttributeExpression(org.codehaus.groovy.ast.expr.AttributeExpression exp)
visitAttributeExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitFieldExpression(org.codehaus.groovy.ast.expr.FieldExpression exp)
visitFieldExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitMethodPointerExpression(org.codehaus.groovy.ast.expr.MethodPointerExpression exp)
visitMethodPointerExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression expression)
visitConstantExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitClassExpression(org.codehaus.groovy.ast.expr.ClassExpression expression)
visitClassExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitVariableExpression(org.codehaus.groovy.ast.expr.VariableExpression exp)
visitVariableExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitDeclarationExpression(org.codehaus.groovy.ast.expr.DeclarationExpression exp)
visitDeclarationExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorprotected void visitAssignmentOrCast(org.codehaus.groovy.ast.expr.VariableExpression varExp,
org.codehaus.groovy.ast.expr.Expression rhs)
public void visitGStringExpression(org.codehaus.groovy.ast.expr.GStringExpression exp)
visitGStringExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression exp)
visitArrayExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitSpreadExpression(org.codehaus.groovy.ast.expr.SpreadExpression expression)
visitSpreadExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitSpreadMapExpression(org.codehaus.groovy.ast.expr.SpreadMapExpression expression)
visitSpreadMapExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitNotExpression(org.codehaus.groovy.ast.expr.NotExpression exp)
visitNotExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitUnaryMinusExpression(org.codehaus.groovy.ast.expr.UnaryMinusExpression exp)
visitUnaryMinusExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitUnaryPlusExpression(org.codehaus.groovy.ast.expr.UnaryPlusExpression exp)
visitUnaryPlusExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitBitwiseNegationExpression(org.codehaus.groovy.ast.expr.BitwiseNegationExpression exp)
visitBitwiseNegationExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitCastExpression(org.codehaus.groovy.ast.expr.CastExpression exp)
visitCastExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitArgumentlistExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression expression)
visitArgumentlistExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitClosureListExpression(org.codehaus.groovy.ast.expr.ClosureListExpression closureListExpression)
visitClosureListExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorpublic void visitBytecodeExpression(org.codehaus.groovy.classgen.BytecodeExpression expression)
visitBytecodeExpression in interface org.codehaus.groovy.ast.GroovyCodeVisitorCopyright © 2011–2019. All rights reserved.