private void evaluateElvisOperatorExpression(ElvisOperatorExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); CompileStack compileStack = controller.getCompileStack(); OperandStack operandStack = controller.getOperandStack(); TypeChooser typeChooser = controller.getTypeChooser(); Expression boolPart = expression.getBooleanExpression().getExpression(); Expression falsePart = expression.getFalseExpression(); ClassNode truePartType = typeChooser.resolveType(boolPart, controller.getClassNode()); ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode()); ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType); // x?:y is equal to x?x:y, which evals to // var t=x; boolean(t)?t:y // first we load x, dup it, convert the dupped to boolean, then // jump depending on the value. For true we are done, for false we // have to load y, thus we first remove x and then load y. // But since x and y may have different stack lengths, this cannot work // Thus we have to have to do the following: // Be X the type of x, Y the type of y and S the common supertype of // X and Y, then we have to see x?:y as // var t=x;boolean(t)?S(t):S(y) // so we load x, dup it, store the value in a local variable (t), then // do boolean conversion. In the true part load t and cast it to S, // in the false part load y and cast y to S // load x, dup it, store one in $t and cast the remaining one to boolean int mark = operandStack.getStackLength(); boolPart.visit(controller.getAcg()); operandStack.dup(); if (ClassHelper.isPrimitiveType(truePartType) && !ClassHelper.isPrimitiveType(operandStack.getTopOperand())) { truePartType = ClassHelper.getWrapper(truePartType); } int retValueId = compileStack.defineTemporaryVariable("$t", truePartType, true); operandStack.castToBool(mark, true); Label l0 = operandStack.jump(IFEQ); // true part: load $t and cast to S operandStack.load(truePartType, retValueId); operandStack.doGroovyCast(common); Label l1 = new Label(); mv.visitJumpInsn(GOTO, l1); // false part: load false expression and cast to S mv.visitLabel(l0); falsePart.visit(controller.getAcg()); operandStack.doGroovyCast(common); // finish and cleanup mv.visitLabel(l1); compileStack.removeVar(retValueId); controller.getOperandStack().replace(common, 2); }
private void evaluateLogicalAndExpression(BinaryExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); AsmClassGenerator acg = controller.getAcg(); OperandStack operandStack = controller.getOperandStack(); expression.getLeftExpression().visit(acg); operandStack.doGroovyCast(ClassHelper.boolean_TYPE); Label falseCase = operandStack.jump(IFEQ); expression.getRightExpression().visit(acg); operandStack.doGroovyCast(ClassHelper.boolean_TYPE); operandStack.jump(IFEQ, falseCase); ConstantExpression.PRIM_TRUE.visit(acg); Label trueCase = new Label(); mv.visitJumpInsn(GOTO, trueCase); mv.visitLabel(falseCase); ConstantExpression.PRIM_FALSE.visit(acg); mv.visitLabel(trueCase); operandStack.remove(1); // have to remove 1 because of the GOTO }
private void evaluateLogicalOrExpression(BinaryExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); AsmClassGenerator acg = controller.getAcg(); OperandStack operandStack = controller.getOperandStack(); Label end = new Label(); expression.getLeftExpression().visit(acg); operandStack.doGroovyCast(ClassHelper.boolean_TYPE); Label trueCase = operandStack.jump(IFNE); expression.getRightExpression().visit(acg); operandStack.doGroovyCast(ClassHelper.boolean_TYPE); Label falseCase = operandStack.jump(IFEQ); mv.visitLabel(trueCase); ConstantExpression.PRIM_TRUE.visit(acg); operandStack.jump(GOTO, end); mv.visitLabel(falseCase); ConstantExpression.PRIM_FALSE.visit(acg); mv.visitLabel(end); }
private void evaluateNormalTernary(TernaryExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); OperandStack operandStack = controller.getOperandStack(); TypeChooser typeChooser = controller.getTypeChooser(); Expression boolPart = expression.getBooleanExpression(); Expression truePart = expression.getTrueExpression(); Expression falsePart = expression.getFalseExpression(); ClassNode truePartType = typeChooser.resolveType(truePart, controller.getClassNode()); ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode()); ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType); // we compile b?x:y as // boolean(b)?S(x):S(y), S = common super type of x,y // so we load b, do boolean conversion. // In the true part load x and cast it to S, // in the false part load y and cast y to S // load b and convert to boolean int mark = operandStack.getStackLength(); boolPart.visit(controller.getAcg()); operandStack.castToBool(mark, true); Label l0 = operandStack.jump(IFEQ); // true part: load x and cast to S truePart.visit(controller.getAcg()); operandStack.doGroovyCast(common); Label l1 = new Label(); mv.visitJumpInsn(GOTO, l1); // false part: load y and cast to S mv.visitLabel(l0); falsePart.visit(controller.getAcg()); operandStack.doGroovyCast(common); // finish and cleanup mv.visitLabel(l1); controller.getOperandStack().replace(common, 2); }
public Label jump(int ifIns) { Label label = new Label(); jump(ifIns, label); return label; }