use of org.codehaus.groovy.ast.FieldNode 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.FieldNode in project groovy by apache.
the class ClosureWriter method loadReference.
public static void loadReference(String name, WriterController controller) {
CompileStack compileStack = controller.getCompileStack();
MethodVisitor mv = controller.getMethodVisitor();
ClassNode classNode = controller.getClassNode();
AsmClassGenerator acg = controller.getAcg();
// an already declared variable.
if (!compileStack.containsVariable(name) && compileStack.getScope().isReferencedClassVariable(name)) {
acg.visitFieldExpression(new FieldExpression(classNode.getDeclaredField(name)));
} else {
BytecodeVariable v = compileStack.getVariable(name, !classNodeUsesReferences(controller.getClassNode()));
if (v == null) {
// variable is not on stack because we are
// inside a nested Closure and this variable
// was not used before
// then load it from the Closure field
FieldNode field = classNode.getDeclaredField(name);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, controller.getInternalClassName(), name, BytecodeHelper.getTypeDescription(field.getType()));
} else {
mv.visitVarInsn(ALOAD, v.getIndex());
}
controller.getOperandStack().push(ClassHelper.REFERENCE_TYPE);
}
}
use of org.codehaus.groovy.ast.FieldNode in project groovy by apache.
the class ClosureWriter method correctAccessedVariable.
private static void correctAccessedVariable(final InnerClassNode closureClass, ClosureExpression ce) {
CodeVisitorSupport visitor = new CodeVisitorSupport() {
@Override
public void visitVariableExpression(VariableExpression expression) {
Variable v = expression.getAccessedVariable();
if (v == null)
return;
if (!(v instanceof FieldNode))
return;
String name = expression.getName();
FieldNode fn = closureClass.getDeclaredField(name);
if (fn != null) {
// only overwrite if we find something more specific
expression.setAccessedVariable(fn);
}
}
};
visitor.visitClosureExpression(ce);
}
use of org.codehaus.groovy.ast.FieldNode in project groovy by apache.
the class AsmClassGenerator method storeThisInstanceField.
private void storeThisInstanceField(FieldExpression expression) {
MethodVisitor mv = controller.getMethodVisitor();
FieldNode field = expression.getField();
boolean setReferenceFromReference = field.isHolder() && expression.isUseReferenceDirectly();
String ownerName = (field.getOwner().equals(controller.getClassNode())) ? controller.getInternalClassName() : BytecodeHelper.getClassInternalName(field.getOwner());
OperandStack operandStack = controller.getOperandStack();
if (setReferenceFromReference) {
// rhs is ready to use reference, just put it in the field
mv.visitVarInsn(ALOAD, 0);
operandStack.push(controller.getClassNode());
operandStack.swap();
mv.visitFieldInsn(PUTFIELD, ownerName, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
} else if (field.isHolder()) {
// rhs is normal value, set the value in the Reference
operandStack.doGroovyCast(field.getOriginType());
operandStack.box();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V", false);
} else {
// rhs is normal value, set normal value
operandStack.doGroovyCast(field.getOriginType());
mv.visitVarInsn(ALOAD, 0);
operandStack.push(controller.getClassNode());
operandStack.swap();
mv.visitFieldInsn(PUTFIELD, ownerName, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
}
}
use of org.codehaus.groovy.ast.FieldNode in project groovy by apache.
the class AsmClassGenerator method storeStaticField.
private void storeStaticField(FieldExpression expression) {
MethodVisitor mv = controller.getMethodVisitor();
FieldNode field = expression.getField();
boolean holder = field.isHolder() && !controller.isInClosureConstructor();
controller.getOperandStack().doGroovyCast(field);
String ownerName = (field.getOwner().equals(controller.getClassNode())) ? controller.getInternalClassName() : BytecodeHelper.getClassInternalName(field.getOwner());
if (holder) {
controller.getOperandStack().box();
mv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V", false);
} else {
mv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
}
controller.getOperandStack().remove(1);
}
Aggregations