From fc2d29b85be276391e694ba3e6ce271e9ecb2e89 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 8 Apr 2011 20:23:01 +0200 Subject: [PATCH] simple way to generate short-circuit boolean && and || --- .../jet/codegen/ExpressionCodegen.java | 86 +++++++++++++------ .../jet/codegen/NamespaceGenTest.java | 30 +++++++ 2 files changed, 89 insertions(+), 27 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 726b82d7c04..e2a6d90cfc1 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -497,42 +497,74 @@ public class ExpressionCodegen extends JetVisitor { final IElementType opToken = expression.getOperationReference().getReferencedNameElementType(); if (opToken == JetTokens.EQ) { generateAssignmentExpression(expression); - return; } - if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { + else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) { generateAugmentedAssignment(expression); - return; } - DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); - if (op instanceof FunctionDescriptor) { - JetType returnType = bindingContext.getExpressionType(expression); - final Type asmType = typeMapper.mapType(returnType); - DeclarationDescriptor cls = op.getContainingDeclaration(); - if (isNumberPrimitive(cls)) { - if (op.getName().equals("compareTo")) { - generateCompareOp(expression, opToken, asmType); - } - else { - int opcode = opcodeForMethod(op.getName()); - generateBinaryOp(expression, (FunctionDescriptor) op, opcode); - } - return; - } - else if (isClass(cls, "Hashable")) { - if (op.getName().equals("equals")) { - final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft())); - final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight())); - if (isNumberPrimitive(leftType) && leftType == rightType) { - generateCompareOp(expression, opToken, leftType); - return; + else if (opToken == JetTokens.ANDAND) { + generateBooleanAnd(expression); + } + else if (opToken == JetTokens.OROR) { + generateBooleanOr(expression); + } + else { + DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); + if (op instanceof FunctionDescriptor) { + JetType returnType = bindingContext.getExpressionType(expression); + final Type asmType = typeMapper.mapType(returnType); + DeclarationDescriptor cls = op.getContainingDeclaration(); + if (isNumberPrimitive(cls)) { + if (op.getName().equals("compareTo")) { + generateCompareOp(expression, opToken, asmType); } else { - throw new UnsupportedOperationException("Don't know how to generate equality for these types"); + int opcode = opcodeForMethod(op.getName()); + generateBinaryOp(expression, (FunctionDescriptor) op, opcode); + } + return; + } + else if (isClass(cls, "Hashable")) { + if (op.getName().equals("equals")) { + final Type leftType = typeMapper.mapType(bindingContext.getExpressionType(expression.getLeft())); + final Type rightType = typeMapper.mapType(bindingContext.getExpressionType(expression.getRight())); + if (isNumberPrimitive(leftType) && leftType == rightType) { + generateCompareOp(expression, opToken, leftType); + return; + } + else { + throw new UnsupportedOperationException("Don't know how to generate equality for these types"); + } } } } + throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); } - throw new UnsupportedOperationException("Don't know how to generate binary op " + expression); + } + + private void generateBooleanAnd(JetBinaryExpression expression) { + gen(expression.getLeft(), Type.BOOLEAN_TYPE); + Label ifFalse = new Label(); + v.ifeq(ifFalse); + gen(expression.getRight(), Type.BOOLEAN_TYPE); + Label end = new Label(); + v.goTo(end); + v.mark(ifFalse); + v.aconst(false); + v.mark(end); + myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE)); + } + + private void generateBooleanOr(JetBinaryExpression expression) { + gen(expression.getLeft(), Type.BOOLEAN_TYPE); + Label ifTrue = new Label(); + v.ifne(ifTrue); + gen(expression.getRight(), Type.BOOLEAN_TYPE); + Label end = new Label(); + v.goTo(end); + v.mark(ifTrue); + v.aconst(true); + v.mark(end); + myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE)); } private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) { diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 5bbb6107ac5..da92859e461 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -451,6 +451,36 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals(0, main.invoke(null, 4)); } + public void testAnd() throws Exception { + loadText("fun foo(a : Int): Boolean = a > 0 && a/0 > 0"); + final Method main = generateFunction(); + assertEquals(false, main.invoke(null, 0)); + boolean hadException = false; + try { + main.invoke(null, 5); + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof ArithmeticException) { + hadException = true; + } + } + assertTrue(hadException); + } + + public void testOr() throws Exception { + loadText("fun foo(a : Int): Boolean = a > 0 || a/0 > 0"); + final Method main = generateFunction(); + assertEquals(true, main.invoke(null, 5)); + boolean hadException = false; + try { + main.invoke(null, 0); + } catch (InvocationTargetException e) { + if (e.getTargetException() instanceof ArithmeticException) { + hadException = true; + } + } + assertTrue(hadException); + } + private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception { loadText(text); System.out.println(generateToText());