generate === and !==
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user