JS backend: added identityEquals support.

This commit is contained in:
Erokhin Stanislav
2013-08-12 16:59:24 +04:00
parent 48cd8f4df4
commit 3b5d5a4a95
6 changed files with 126 additions and 6 deletions
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.test.semantics;
public class IdentityEqualsTest extends AbstractExpressionTest {
public IdentityEqualsTest() {
super("identityEquals/");
}
public void testIdentityEqualsMethod() throws Exception {
checkFooBoxIsOk();
}
public void testIdentityEqualsMethodForPrimitives() throws Exception {
checkFooBoxIsOk();
}
}
@@ -16,9 +16,7 @@
package org.jetbrains.k2js.translate.intrinsic.functions.factories;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -53,6 +51,17 @@ public final class TopLevelFIF extends CompositeFIF {
@NotNull
public static final KotlinFunctionIntrinsic EQUALS = new KotlinFunctionIntrinsic("equals");
@NotNull
public static final FunctionIntrinsic IDENTITY_EQUALS = new FunctionIntrinsic() {
@NotNull
@Override
public JsExpression apply(
@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments, @NotNull TranslationContext context
) {
assert arguments.size() == 1 : "Unexpected argument size for jet.identityEquals: " + arguments.size();
return new JsBinaryOperation(JsBinaryOperator.REF_EQ, receiver, arguments.get(0));
}
};
@NotNull
private static final FunctionIntrinsic RETURN_RECEIVER_INTRINSIC = new FunctionIntrinsic() {
@NotNull
@Override
@@ -120,6 +129,7 @@ public final class TopLevelFIF extends CompositeFIF {
private TopLevelFIF() {
add(pattern("jet", "toString").receiverExists(), new KotlinFunctionIntrinsic("toString"));
add(pattern("jet", "equals").receiverExists(), EQUALS);
add(pattern("jet", "identityEquals").receiverExists(), IDENTITY_EQUALS);
add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), EQUALS);
add(pattern("String|Boolean|Char|Number.equals"), EQUALS);
add(pattern("jet", "arrayOfNulls"), new KotlinFunctionIntrinsic("nullArray"));
@@ -16,6 +16,7 @@
package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
@@ -31,7 +32,9 @@ import static org.jetbrains.k2js.translate.general.Translation.translateAsExpres
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getBaseExpression;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isEqualLikeOperator;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.sure;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateExclForBinaryEqualLikeExpr;
public final class UnaryOperationTranslator {
private UnaryOperationTranslator() {
@@ -46,7 +49,12 @@ public final class UnaryOperationTranslator {
if (IncrementTranslator.isIncrement(expression)) {
return IncrementTranslator.translate(expression, context);
}
return translateAsCall(expression, context);
JsExpression baseExpression = TranslationUtils.translateBaseExpression(context, expression);
if (isExclForBinaryEqualLikeExpr(expression, baseExpression)) {
return translateExclForBinaryEqualLikeExpr((JsBinaryOperation) baseExpression);
}
return translateAsCall(expression, context, baseExpression);
}
private static boolean isExclExcl(@NotNull JetUnaryExpression expression) {
@@ -58,11 +66,21 @@ public final class UnaryOperationTranslator {
return sure(translateAsExpression(getBaseExpression(expression), context), context);
}
private static boolean isExclForBinaryEqualLikeExpr(@NotNull JetUnaryExpression expression, @NotNull JsExpression baseExpression) {
if (getOperationToken(expression).equals(JetTokens.EXCL)) {
if (baseExpression instanceof JsBinaryOperation) {
return isEqualLikeOperator(((JsBinaryOperation) baseExpression).getOperator());
}
}
return false;
}
@NotNull
private static JsExpression translateAsCall(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
@NotNull TranslationContext context,
@NotNull JsExpression baseExpression) {
return CallBuilder.build(context)
.receiver(TranslationUtils.translateBaseExpression(context, expression))
.receiver(baseExpression)
.args(Collections.<JsExpression>emptyList())
.resolvedCall(getResolvedCall(context.bindingContext(), expression.getOperationReference()))
.type(CallType.NORMAL).translate();
@@ -34,6 +34,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.google.dart.compiler.backend.js.ast.JsBinaryOperator.*;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor;
@@ -62,6 +63,31 @@ public final class TranslationUtils {
return new JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), meta);
}
@NotNull
public static JsExpression translateExclForBinaryEqualLikeExpr(@NotNull JsBinaryOperation baseBinaryExpression) {
return new JsBinaryOperation(notOperator(baseBinaryExpression.getOperator()), baseBinaryExpression.getArg1(), baseBinaryExpression.getArg2());
}
public static boolean isEqualLikeOperator(@NotNull JsBinaryOperator operator) {
return notOperator(operator) != null;
}
@Nullable
private static JsBinaryOperator notOperator(@NotNull JsBinaryOperator operator) {
switch (operator) {
case REF_EQ:
return REF_NEQ;
case REF_NEQ:
return REF_EQ;
case EQ:
return NEQ;
case NEQ:
return EQ;
default:
return null;
}
}
@NotNull
public static JsBinaryOperation isNullCheck(@NotNull JsExpression expressionToCheck) {
return nullCheck(expressionToCheck, false);
@@ -0,0 +1,21 @@
package foo
class X
fun box(): String {
val a = X()
val b = X()
if (!a.identityEquals(a)) return "a !== a"
if (a.identityEquals(b)) return "X() === X()"
val c = a
if (!c.identityEquals(a)) return "c = a; c !== a"
if (X() identityEquals a) return "X() identityEquals a"
val t = !(X() identityEquals a)
if (!t) return "t = !(X() identityEquals a); t == false"
val f = !!(X() identityEquals a)
if (f) return "f = !!(X() identityEquals null); f == true"
return "OK";
}
@@ -0,0 +1,14 @@
package foo
fun box(): String {
if (!null.identityEquals(null)) return "null !== null"
if (!("ab" identityEquals "ab")) return "ab !== ab"
if (("ab" identityEquals "a")) return "ab === a"
if ("0" identityEquals 0) return "'0' === 0"
if (!(0 identityEquals 0)) return "0 !== 0"
if (0 identityEquals 1) return "0 === 1"
return "OK";
}