public void writeClosure(ClosureExpression expression) {
CompileStack compileStack = controller.getCompileStack();
MethodVisitor mv = controller.getMethodVisitor();
ClassNode classNode = controller.getClassNode();
AsmClassGenerator acg = controller.getAcg();
ClassNode closureClass = getOrAddClosureClass(expression, 0);
String closureClassinternalName = BytecodeHelper.getClassInternalName(closureClass);
List constructors = closureClass.getDeclaredConstructors();
ConstructorNode node = (ConstructorNode) constructors.get(0);
Parameter[] localVariableParams = node.getParameters();
mv.visitTypeInsn(NEW, closureClassinternalName);
mv.visitInsn(DUP);
if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall()) {
(new ClassExpression(classNode)).visit(acg);
(new ClassExpression(controller.getOutermostClass())).visit(acg);
} else {
mv.visitVarInsn(ALOAD, 0);
controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
loadThis();
}
// now let's load the various parameters we're passing
// we start at index 2 because the first variable we pass
// is the owner instance and at this point it is already
// on the stack
for (int i = 2; i < localVariableParams.length; i++) {
Parameter param = localVariableParams[i];
String name = param.getName();
// compileStack.containsVariable(name) means to ask if the variable is already declared
// compileStack.getScope().isReferencedClassVariable(name) means to ask if the variable is a field
// If it is no field and is not yet declared, then it is either a closure shared variable or
// 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());
if (v == null) {
// variable is not on stack because we are
// inside a nested Closure and this variable