diff --git a/js/js.libraries/src/core/javalang.kt b/js/js.libraries/src/core/javalang.kt index 212a58b4527..36468b475e7 100644 --- a/js/js.libraries/src/core/javalang.kt +++ b/js/js.libraries/src/core/javalang.kt @@ -31,11 +31,6 @@ public trait Runnable { public open fun run() : Unit; } -library -public trait Comparable { - public fun compareTo(that: T): Int -} - library public trait Appendable { public open fun append(csq: CharSequence?): Appendable diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java index c113e269947..d95f56fbd5a 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java @@ -101,6 +101,8 @@ public final class StandardClasses { .methods("iterator", "contains").properties("start", "end", "increment"); standardClasses.declare().forFQ("kotlin.Enum").kotlinClass("Enum"); + + standardClasses.declare().forFQ("kotlin.Comparable").kotlinClass("Comparable"); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java index ab3fbb8dab6..bc86c1fc8b5 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java @@ -31,6 +31,7 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate; import org.jetbrains.k2js.translate.utils.BindingUtils; +import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; import static org.jetbrains.k2js.translate.utils.BindingUtils.getTypeByReference; @@ -92,6 +93,9 @@ public final class PatternTranslator extends AbstractTranslator { if (NamePredicate.STRING.apply(typeName)) { jsSTypeName = "string"; } + else if (NamePredicate.NUMBER.apply(typeName)) { + return JsAstUtils.isNumber(expressionToMatch); + } else if (NamePredicate.PRIMITIVE_NUMBERS.apply(typeName)) { jsSTypeName = "number"; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java index cf3defa0e64..6bc1d794963 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java @@ -34,11 +34,12 @@ import org.jetbrains.k2js.translate.intrinsic.functions.patterns.DescriptorPredi import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate; import org.jetbrains.k2js.translate.operation.OperatorTable; import org.jetbrains.k2js.translate.utils.JsAstUtils; +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; import java.util.List; import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.setArguments; public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { INSTANCE; @@ -76,7 +77,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { }; @NotNull - private static final FunctionIntrinsic NUMBER_COMPARE_TO_INTRINSIC = new FunctionIntrinsic() { + private static final FunctionIntrinsic BUILTINS_COMPARE_TO_INTRINSIC = new FunctionIntrinsic() { @NotNull @Override public JsExpression apply( @@ -90,6 +91,21 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { } }; + @NotNull + private static final FunctionIntrinsic PRIMITIVE_NUMBER_COMPARE_TO_INTRINSIC = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply( + @Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context + ) { + assert receiver != null; + assert arguments.size() == 1; + return JsAstUtils.primitiveCompareTo(receiver, arguments.get(0)); + } + }; + @NotNull private static final NamePredicate BINARY_OPERATIONS = new NamePredicate(OperatorConventions.BINARY_OPERATION_NAMES.values()); private static final DescriptorPredicate PRIMITIVE_NUMBERS_BINARY_OPERATIONS = pattern(NamePredicate.PRIMITIVE_NUMBERS, BINARY_OPERATIONS); @@ -115,13 +131,18 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { @Nullable @Override public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + if (PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS.apply(descriptor)) { + return PRIMITIVE_NUMBER_COMPARE_TO_INTRINSIC; + } + + if (JsDescriptorUtils.isBuiltin(descriptor) && descriptor.getName().equals(OperatorConventions.COMPARE_TO)) { + return BUILTINS_COMPARE_TO_INTRINSIC; + } + if (!PREDICATE.apply(descriptor)) { return null; } - if (PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS.apply(descriptor)) { - return NUMBER_COMPARE_TO_INTRINSIC; - } if (pattern("Int|Short|Byte.div").apply(descriptor)) { JetType resultType = descriptor.getReturnType(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java index d234251f85a..2b99f495ff7 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java @@ -45,6 +45,9 @@ public final class NamePredicate implements Predicate { @NotNull public static final NamePredicate STRING = new NamePredicate("String"); + @NotNull + public static final NamePredicate NUMBER = new NamePredicate("Number"); + @NotNull private final Set validNames = Sets.newHashSet(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt index 4ab2708910e..79ec2693635 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/operation/CompareToBOIF.kt @@ -16,18 +16,18 @@ package org.jetbrains.k2js.translate.intrinsic.operation +import com.google.common.collect.ImmutableSet import com.google.dart.compiler.backend.js.ast.* +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor import org.jetbrains.jet.lang.psi.JetBinaryExpression import org.jetbrains.jet.lang.types.expressions.OperatorConventions -import org.jetbrains.k2js.translate.context.TranslationContext -import org.jetbrains.k2js.translate.operation.OperatorTable -import org.jetbrains.k2js.translate.utils.JsDescriptorUtils - -import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken - -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor import org.jetbrains.jet.lexer.JetToken -import com.google.common.collect.ImmutableSet +import org.jetbrains.k2js.translate.context.TranslationContext +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern +import org.jetbrains.k2js.translate.operation.OperatorTable +import org.jetbrains.k2js.translate.utils.JsAstUtils +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils +import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken object CompareToBOIF : BinaryOperationIntrinsicFactory { @@ -39,9 +39,24 @@ object CompareToBOIF : BinaryOperationIntrinsicFactory { } } + private object CompareToFunctionIntrinsic : AbstractBinaryOperationIntrinsic() { + override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression { + val operator = OperatorTable.getBinaryOperator(getOperationToken(expression)) + val compareTo = JsAstUtils.compareTo(left, right) + return JsBinaryOperation(operator, compareTo, context.program().getNumberLiteral(0)) + } + } + override public fun getSupportTokens(): ImmutableSet = OperatorConventions.COMPARISON_OPERATIONS override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? { - return if (JsDescriptorUtils.isBuiltin(descriptor)) CompareToIntrinsic else null + if (JsDescriptorUtils.isBuiltin(descriptor)) + when { + pattern("Int|Short|Byte|Double|Float|Char|String|Long.compareTo").apply(descriptor) -> + return CompareToIntrinsic + else -> + return CompareToFunctionIntrinsic + } + return null } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java index e46ea9a8e7f..9ad5ee75940 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsAstUtils.java @@ -138,6 +138,16 @@ public final class JsAstUtils { return new JsInvocation(new JsNameRef(OperatorConventions.COMPARE_TO.getIdentifier(), Namer.KOTLIN_OBJECT_REF), left, right); } + @NotNull + public static JsExpression primitiveCompareTo(@NotNull JsExpression left, @NotNull JsExpression right) { + return new JsInvocation(new JsNameRef("primitiveCompareTo", Namer.KOTLIN_OBJECT_REF), left, right); + } + + @NotNull + public static JsExpression isNumber(@NotNull JsExpression expression) { + return new JsInvocation(new JsNameRef("isNumber", Namer.KOTLIN_OBJECT_REF), expression); + } + @NotNull public static JsPrefixOperation negated(@NotNull JsExpression expression) { return new JsPrefixOperation(JsUnaryOperator.NOT, expression); diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index d03e407a868..2c4318aa248 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -86,9 +86,21 @@ }; Kotlin.compareTo = function(a, b) { + var type = typeof a; + if (type == "number" || type == "string") { + return a < b ? -1 : a > b ? 1 : 0; + } + return a.compareTo_za3rmp$(b); + }; + + Kotlin.primitiveCompareTo = function(a, b) { return a < b ? -1 : a > b ? 1 : 0; }; + Kotlin.isNumber = function (a) { + return typeof a == "number"; + }; + Kotlin.toShort = function(a) { return (a & 0xFFFF) << 16 >> 16; };