use of org.codehaus.groovy.ast.stmt.BlockStatement in project groovy by apache.
the class InnerClassVisitor method visitConstructorCallExpression.
@Override
public void visitConstructorCallExpression(ConstructorCallExpression call) {
super.visitConstructorCallExpression(call);
if (!call.isUsingAnonymousInnerClass()) {
passThisReference(call);
return;
}
InnerClassNode innerClass = (InnerClassNode) call.getType();
ClassNode outerClass = innerClass.getOuterClass();
ClassNode superClass = innerClass.getSuperClass();
if (superClass instanceof InnerClassNode && !superClass.isInterface() && !(superClass.isStaticClass() || ((superClass.getModifiers() & ACC_STATIC) == ACC_STATIC))) {
insertThis0ToSuperCall(call, innerClass);
}
if (!innerClass.getDeclaredConstructors().isEmpty())
return;
if ((innerClass.getModifiers() & ACC_STATIC) != 0)
return;
VariableScope scope = innerClass.getVariableScope();
if (scope == null)
return;
// expressions = constructor call arguments
List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions();
// block = init code for the constructor we produce
BlockStatement block = new BlockStatement();
// parameters = parameters of the constructor
final int additionalParamCount = 1 + scope.getReferencedLocalVariablesCount();
List<Parameter> parameters = new ArrayList<Parameter>(expressions.size() + additionalParamCount);
// superCallArguments = arguments for the super call == the constructor call arguments
List<Expression> superCallArguments = new ArrayList<Expression>(expressions.size());
// first we add a super() call for all expressions given in the
// constructor call expression
int pCount = additionalParamCount;
for (Expression expr : expressions) {
pCount++;
// add one parameter for each expression in the
// constructor call
Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + pCount);
parameters.add(param);
// add to super call
superCallArguments.add(new VariableExpression(param));
}
// add the super call
ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression(superCallArguments));
block.addStatement(new ExpressionStatement(cce));
// we need to add "this" to access unknown methods/properties
// this is saved in a field named this$0
pCount = 0;
expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
boolean isStatic = isStaticThis(innerClass, scope);
ClassNode outerClassType = getClassNode(outerClass, isStatic);
if (!isStatic && inClosure)
outerClassType = ClassHelper.CLOSURE_TYPE;
outerClassType = outerClassType.getPlainNodeReference();
Parameter thisParameter = new Parameter(outerClassType, "p" + pCount);
parameters.add(pCount, thisParameter);
thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, outerClassType, null);
addFieldInit(thisParameter, thisField, block);
// for each shared variable we add a reference and save it as field
for (Iterator it = scope.getReferencedLocalVariablesIterator(); it.hasNext(); ) {
pCount++;
org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) it.next();
VariableExpression ve = new VariableExpression(var);
ve.setClosureSharedVariable(true);
ve.setUseReferenceDirectly(true);
expressions.add(pCount, ve);
ClassNode rawReferenceType = ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
Parameter p = new Parameter(rawReferenceType, "p" + pCount);
parameters.add(pCount, p);
p.setOriginType(var.getOriginType());
final VariableExpression initial = new VariableExpression(p);
initial.setSynthetic(true);
initial.setUseReferenceDirectly(true);
final FieldNode pField = innerClass.addFieldFirst(ve.getName(), PUBLIC_SYNTHETIC, rawReferenceType, initial);
pField.setHolder(true);
pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
}
innerClass.addConstructor(ACC_SYNTHETIC, parameters.toArray(new Parameter[parameters.size()]), ClassNode.EMPTY_ARRAY, block);
}
use of org.codehaus.groovy.ast.stmt.BlockStatement in project groovy by apache.
the class ClosureWriter method createClosureClass.
protected ClassNode createClosureClass(ClosureExpression expression, int mods) {
ClassNode classNode = controller.getClassNode();
ClassNode outerClass = controller.getOutermostClass();
MethodNode methodNode = controller.getMethodNode();
String name = classNode.getName() + "$" + // add a more informative name
controller.getContext().getNextClosureInnerName(outerClass, classNode, methodNode);
boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass();
Parameter[] parameters = expression.getParameters();
if (parameters == null) {
parameters = Parameter.EMPTY_ARRAY;
} else if (parameters.length == 0) {
// let's create a default 'it' parameter
Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
parameters = new Parameter[] { it };
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
if (ref != null)
it.setClosureSharedVariable(ref.isClosureSharedVariable());
}
Parameter[] localVariableParams = getClosureSharedVariables(expression);
removeInitialValues(localVariableParams);
InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
answer.setEnclosingMethod(controller.getMethodNode());
answer.setSynthetic(true);
answer.setUsingGenerics(outerClass.isUsingGenerics());
answer.setSourcePosition(expression);
if (staticMethodOrInStaticClass) {
answer.setStaticClass(true);
}
if (controller.isInScriptBody()) {
answer.setScriptBody(true);
}
MethodNode method = answer.addMethod("doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode());
method.setSourcePosition(expression);
VariableScope varScope = expression.getVariableScope();
if (varScope == null) {
throw new RuntimeException("Must have a VariableScope by now! for expression: " + expression + " class: " + name);
} else {
method.setVariableScope(varScope.copy());
}
if (parameters.length > 1 || (parameters.length == 1 && parameters[0].getType() != null && parameters[0].getType() != ClassHelper.OBJECT_TYPE && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType()))) {
// let's add a typesafe call method
MethodNode call = answer.addMethod("call", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, new ReturnStatement(new MethodCallExpression(VariableExpression.THIS_EXPRESSION, "doCall", new ArgumentListExpression(parameters))));
call.setSourcePosition(expression);
}
// let's make the constructor
BlockStatement block = new BlockStatement();
// this block does not get a source position, because we don't
// want this synthetic constructor to show up in corbertura reports
VariableExpression outer = new VariableExpression("_outerInstance");
outer.setSourcePosition(expression);
block.getVariableScope().putReferencedLocalVariable(outer);
VariableExpression thisObject = new VariableExpression("_thisObject");
thisObject.setSourcePosition(expression);
block.getVariableScope().putReferencedLocalVariable(thisObject);
TupleExpression conArgs = new TupleExpression(outer, thisObject);
block.addStatement(new ExpressionStatement(new ConstructorCallExpression(ClassNode.SUPER, conArgs)));
// let's assign all the parameter fields from the outer context
for (Parameter param : localVariableParams) {
String paramName = param.getName();
ClassNode type = param.getType();
if (true) {
VariableExpression initialValue = new VariableExpression(paramName);
initialValue.setAccessedVariable(param);
initialValue.setUseReferenceDirectly(true);
ClassNode realType = type;
type = ClassHelper.makeReference();
param.setType(ClassHelper.makeReference());
FieldNode paramField = answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue);
paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType()));
paramField.setHolder(true);
String methodName = Verifier.capitalize(paramName);
// let's add a getter & setter
Expression fieldExp = new FieldExpression(paramField);
answer.addMethod("get" + methodName, ACC_PUBLIC, realType.getPlainNodeReference(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new ReturnStatement(fieldExp));
}
}
Parameter[] params = new Parameter[2 + localVariableParams.length];
params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance");
params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject");
System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
sn.setSourcePosition(expression);
correctAccessedVariable(answer, expression);
return answer;
}
use of org.codehaus.groovy.ast.stmt.BlockStatement in project groovy by apache.
the class Verifier method addDefaultConstructor.
protected void addDefaultConstructor(ClassNode node) {
if (!node.getDeclaredConstructors().isEmpty())
return;
BlockStatement empty = new BlockStatement();
empty.setSourcePosition(node);
ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, empty);
constructor.setSourcePosition(node);
constructor.setHasNoRealSourcePosition(true);
node.addConstructor(constructor);
}
use of org.codehaus.groovy.ast.stmt.BlockStatement in project groovy by apache.
the class AsmClassGenerator method visitClosureListExpression.
public void visitClosureListExpression(ClosureListExpression expression) {
MethodVisitor mv = controller.getMethodVisitor();
controller.getCompileStack().pushVariableScope(expression.getVariableScope());
List<Expression> expressions = expression.getExpressions();
final int size = expressions.size();
// init declarations
LinkedList<DeclarationExpression> declarations = new LinkedList<DeclarationExpression>();
for (int i = 0; i < size; i++) {
Expression expr = expressions.get(i);
if (expr instanceof DeclarationExpression) {
declarations.add((DeclarationExpression) expr);
DeclarationExpression de = (DeclarationExpression) expr;
BinaryExpression be = new BinaryExpression(de.getLeftExpression(), de.getOperation(), de.getRightExpression());
expressions.set(i, be);
de.setRightExpression(ConstantExpression.NULL);
visitDeclarationExpression(de);
}
}
LinkedList instructions = new LinkedList();
BytecodeSequence seq = new BytecodeSequence(instructions);
BlockStatement bs = new BlockStatement();
bs.addStatement(seq);
Parameter closureIndex = new Parameter(ClassHelper.int_TYPE, "__closureIndex");
ClosureExpression ce = new ClosureExpression(new Parameter[] { closureIndex }, bs);
ce.setVariableScope(expression.getVariableScope());
// to keep stack height put a null on stack
instructions.add(ConstantExpression.NULL);
// init table
final Label dflt = new Label();
final Label tableEnd = new Label();
final Label[] labels = new Label[size];
instructions.add(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
mv.visitVarInsn(ILOAD, 1);
mv.visitTableSwitchInsn(0, size - 1, dflt, labels);
}
});
// visit cases
for (int i = 0; i < size; i++) {
final Label label = new Label();
Object expr = expressions.get(i);
final boolean isStatement = expr instanceof Statement;
labels[i] = label;
instructions.add(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
mv.visitLabel(label);
// so expressions need to pop the alibi null
if (!isStatement)
mv.visitInsn(POP);
}
});
instructions.add(expr);
instructions.add(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
mv.visitJumpInsn(GOTO, tableEnd);
}
});
}
// default case
{
instructions.add(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
mv.visitLabel(dflt);
}
});
ConstantExpression text = new ConstantExpression("invalid index for closure");
ConstructorCallExpression cce = new ConstructorCallExpression(ClassHelper.make(IllegalArgumentException.class), text);
ThrowStatement ts = new ThrowStatement(cce);
instructions.add(ts);
}
// return
instructions.add(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
mv.visitLabel(tableEnd);
mv.visitInsn(ARETURN);
}
});
// load main Closure
visitClosureExpression(ce);
// we need later an array to store the curried
// closures, so we create it here and ave it
// in a temporary variable
BytecodeHelper.pushConstant(mv, size);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int listArrayVar = controller.getCompileStack().defineTemporaryVariable("_listOfClosures", true);
// add curried versions
for (int i = 0; i < size; i++) {
// stack: closure
// we need to create a curried closure version
// so we store the type on stack
mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/CurriedClosure");
// stack: closure, type
// for a constructor call we need the type two times
// and the closure after them
mv.visitInsn(DUP2);
mv.visitInsn(SWAP);
// stack: closure,type,type,closure
// so we can create the curried closure
mv.visitInsn(ICONST_1);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
mv.visitInsn(DUP);
mv.visitInsn(ICONST_0);
mv.visitLdcInsn(i);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
mv.visitInsn(AASTORE);
mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/CurriedClosure", "<init>", "(Lgroovy/lang/Closure;[Ljava/lang/Object;)V", false);
// stack: closure,curriedClosure
// we need to save the result
mv.visitVarInsn(ALOAD, listArrayVar);
mv.visitInsn(SWAP);
BytecodeHelper.pushConstant(mv, i);
mv.visitInsn(SWAP);
mv.visitInsn(AASTORE);
// stack: closure
}
// we don't need the closure any longer, so remove it
mv.visitInsn(POP);
// we load the array and create a list from it
mv.visitVarInsn(ALOAD, listArrayVar);
createListMethod.call(mv);
// remove the temporary variable to keep the
// stack clean
controller.getCompileStack().removeVar(listArrayVar);
controller.getOperandStack().pop();
}
use of org.codehaus.groovy.ast.stmt.BlockStatement in project groovy by apache.
the class MethodTest method testMethods.
public void testMethods() throws Exception {
ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
Statement statementA = new ReturnStatement(new ConstantExpression("calledA"));
Statement statementB = new ReturnStatement(new ConstantExpression("calledB"));
Statement emptyStatement = new BlockStatement();
classNode.addMethod(new MethodNode("a", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementA));
classNode.addMethod(new MethodNode("b", ACC_PUBLIC, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementB));
classNode.addMethod(new MethodNode("noReturnMethodA", ACC_PUBLIC, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, emptyStatement));
classNode.addMethod(new MethodNode("noReturnMethodB", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, emptyStatement));
classNode.addMethod(new MethodNode("c", ACC_PUBLIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, emptyStatement));
Class fooClass = loadClass(classNode);
assertTrue("Loaded a new class", fooClass != null);
Object bean = fooClass.newInstance();
assertTrue("Created instance of class: " + bean, bean != null);
assertCallMethod(bean, "a", "calledA");
assertCallMethod(bean, "b", "calledB");
assertCallMethod(bean, "noReturnMethodA", null);
assertCallMethod(bean, "noReturnMethodB", null);
assertCallMethod(bean, "c", null);
}
Aggregations