diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index d97cdbaee13..90a0df7fd23 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -643,6 +643,10 @@ public class ExpressionCodegen extends JetVisitor { if (isNumberPrimitive(cls)) { if (generateUnaryOp(op, asmType, expression.getBaseExpression())) return; } + else if (isClass(cls, "Boolean") && op.getName().equals("not")) { + generateNot(expression); + return; + } } throw new UnsupportedOperationException("Don't know how to generate this prefix expression"); } @@ -680,6 +684,13 @@ public class ExpressionCodegen extends JetVisitor { return false; } + private void generateNot(JetPrefixExpression expression) { + int oldStackSize = myStack.size(); + gen(expression.getBaseExpression()); + assert myStack.size() == oldStackSize+1; + myStack.set(myStack.size()-1, StackValue.not(myStack.get(myStack.size() - 1))); + } + private int generateIncrement(DeclarationDescriptor op, Type asmType, JetExpression operand) { if (!(operand instanceof JetReferenceExpression)) { throw new UnsupportedOperationException("cannot increment or decrement a non-lvalue"); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 0e7380ce1fa..fb3ae926cbb 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -36,6 +36,10 @@ public abstract class StackValue { return new NumberCompare(opToken); } + public static StackValue not(StackValue stackValue) { + return new Invert(stackValue); + } + public abstract void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v); private static void box(final Type type, InstructionAdapter v) { @@ -74,6 +78,17 @@ public abstract class StackValue { } } + protected void putAsBoolean(InstructionAdapter v) { + Label ifTrue = new Label(); + Label end = new Label(); + condJump(ifTrue, false, v); + v.iconst(0); + v.goTo(end); + v.mark(ifTrue); + v.iconst(1); + v.mark(end); + } + public static class Local extends StackValue { private final int index; @@ -168,14 +183,7 @@ public abstract class StackValue { if (type != Type.BOOLEAN_TYPE) { throw new UnsupportedOperationException("don't know how to put a compare as a non-boolean type"); } - Label ifTrue = new Label(); - Label end = new Label(); - condJump(ifTrue, false, v); - v.iconst(0); - v.goTo(end); - v.mark(ifTrue); - v.iconst(1); - v.mark(end); + putAsBoolean(v); } @Override @@ -219,4 +227,26 @@ public abstract class StackValue { v.visitJumpInsn(opcode, label); } } + + private static class Invert extends StackValue { + private StackValue myOperand; + + private Invert(StackValue operand) { + super(operand.type); + myOperand = operand; + } + + @Override + public void put(Type type, InstructionAdapter v) { + if (type != Type.BOOLEAN_TYPE) { + throw new UnsupportedOperationException("don't know how to put a compare as a non-boolean type"); + } + putAsBoolean(v); + } + + @Override + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + myOperand.condJump(label, !jumpIfFalse, v); + } + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 33e69e03163..51b8c0e2002 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -437,6 +437,20 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals(6L, main.invoke(null, 2L)); } + public void testBooleanNot() throws Exception { + loadText("fun foo(b: Boolean): Boolean = !b"); + final Method main = generateFunction(); + assertEquals(true, main.invoke(null, false)); + assertEquals(false, main.invoke(null, true)); + } + + public void testBooleanNotJump() throws Exception { + loadText("fun foo(a: Int) : Int = if (!(a < 5)) a else 0"); + final Method main = generateFunction(); + assertEquals(6, main.invoke(null, 6)); + assertEquals(0, main.invoke(null, 4)); + } + private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception { loadText(text); System.out.println(generateToText());