From 8e551399a1862e62aa7c45c2ce66a20ccc5cfa3c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 14 Apr 2011 20:24:22 +0200 Subject: [PATCH] generate === and !== --- .../jet/codegen/ExpressionCodegen.java | 62 +++++++++++-------- .../org/jetbrains/jet/codegen/StackValue.java | 25 +++++++- .../jet/codegen/NamespaceGenTest.java | 18 ++++++ 3 files changed, 77 insertions(+), 28 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 690b92d50aa..8ebd1b22c2c 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -503,7 +503,8 @@ public class ExpressionCodegen extends JetVisitor { else if (opToken == JetTokens.OROR) { generateBooleanOr(expression); } - else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ) { + else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ || + opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { generateEquals(expression, opToken); } else { @@ -562,37 +563,46 @@ public class ExpressionCodegen extends JetVisitor { else { gen(expression.getLeft(), leftType); gen(expression.getRight(), rightType); - v.dup2(); // left right left right - Label rightNull = new Label(); - v.ifnull(rightNull); - Label leftNull = new Label(); - v.ifnull(leftNull); - v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z"); - Label end = new Label(); - v.goTo(end); - v.mark(rightNull); - // left right left - Label bothNull = new Label(); - v.ifnull(bothNull); - v.mark(leftNull); - v.pop2(); - v.aconst(Boolean.FALSE); - v.goTo(end); - v.mark(bothNull); - v.pop2(); - v.aconst(Boolean.TRUE); - v.mark(end); - - final StackValue onStack = StackValue.onStack(Type.BOOLEAN_TYPE); - if (opToken == JetTokens.EXCLEQ) { - myStack.push(StackValue.not(onStack)); + if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) { + myStack.push(StackValue.cmp(opToken, leftType)); } else { - myStack.push(onStack); + generateNullSafeEquals(opToken); } } } + private void generateNullSafeEquals(IElementType opToken) { + v.dup2(); // left right left right + Label rightNull = new Label(); + v.ifnull(rightNull); + Label leftNull = new Label(); + v.ifnull(leftNull); + v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z"); + Label end = new Label(); + v.goTo(end); + v.mark(rightNull); + // left right left + Label bothNull = new Label(); + v.ifnull(bothNull); + v.mark(leftNull); + v.pop2(); + v.aconst(Boolean.FALSE); + v.goTo(end); + v.mark(bothNull); + v.pop2(); + v.aconst(Boolean.TRUE); + v.mark(end); + + final StackValue onStack = StackValue.onStack(Type.BOOLEAN_TYPE); + if (opToken == JetTokens.EXCLEQ) { + myStack.push(StackValue.not(onStack)); + } + else { + myStack.push(onStack); + } + } + private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) { if (!(descriptor instanceof ClassDescriptor)) { return false; diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index a9ade7a3ccf..9ddd16fe1f2 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -33,7 +33,7 @@ public abstract class StackValue { } public static StackValue cmp(IElementType opToken, Type type) { - return new NumberCompare(opToken, type); + return type.getSort() == Type.OBJECT ? new ObjectCompare(opToken, type) : new NumberCompare(opToken, type); } public static StackValue not(StackValue stackValue) { @@ -171,7 +171,7 @@ public abstract class StackValue { } private static class NumberCompare extends StackValue { - private final IElementType opToken; + protected final IElementType opToken; private final Type operandType; public NumberCompare(IElementType opToken, Type operandType) { @@ -230,6 +230,27 @@ public abstract class StackValue { } } + private static class ObjectCompare extends NumberCompare { + public ObjectCompare(IElementType opToken, Type operandType) { + super(opToken, operandType); + } + + @Override + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { + int opcode; + if (opToken == JetTokens.EQEQEQ) { + opcode = jumpIfFalse ? Opcodes.IF_ACMPNE : Opcodes.IF_ACMPEQ; + } + else if (opToken == JetTokens.EXCLEQEQEQ) { + opcode = jumpIfFalse ? Opcodes.IF_ACMPEQ : Opcodes.IF_ACMPNE; + } + else { + throw new UnsupportedOperationException("don't know how to generate this condjump"); + } + v.visitJumpInsn(opcode, label); + } + } + private static class Invert extends StackValue { private StackValue myOperand; diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index a0c46ba5907..f339e97a948 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -537,6 +537,24 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals(Boolean.FALSE, main.invoke(null, "jet")); } + public void testTripleEq() throws Exception { + loadText("fun foo(s1: String?, s2: String?) = s1 === s2"); + final Method main = generateFunction(); + String s1 = new String("jet"); + String s2 = new String("jet"); + assertEquals(Boolean.TRUE, main.invoke(null, s1, s1)); + assertEquals(Boolean.FALSE, main.invoke(null, s1, s2)); + } + + public void testTripleNotEq() throws Exception { + loadText("fun foo(s1: String?, s2: String?) = s1 !== s2"); + final Method main = generateFunction(); + String s1 = new String("jet"); + String s2 = new String("jet"); + assertEquals(Boolean.FALSE, main.invoke(null, s1, s1)); + assertEquals(Boolean.TRUE, main.invoke(null, s1, s2)); + } + public void testFunctionCall() throws Exception { loadFile("functionCall.jet"); System.out.println(generateToText());