use of org.codehaus.groovy.ast.expr.ElvisOperatorExpression in project groovy by apache.
the class BinaryExpressionHelper method evaluateElvisOperatorExpression.
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);
}
use of org.codehaus.groovy.ast.expr.ElvisOperatorExpression in project groovy-core by groovy.
the class BinaryExpressionHelper method evaluateElvisOperatorExpression.
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);
}
Aggregations