diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java index d5f1681cf79..bf5c08c6754 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NumberTest.java @@ -41,4 +41,8 @@ public final class NumberTest extends SingleFileTranslationTest { public void testByteAndShortConversions() throws Exception { fooBoxTest(); } + + public void testDivision() throws Exception { + fooBoxIsValue("SUCCESS"); + } } 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 13a2ffdad77..a1a5a399c68 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 @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lexer.JetToken; +import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic; import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate; @@ -33,6 +34,7 @@ import org.jetbrains.k2js.translate.operation.OperatorTable; import java.util.List; +import static org.jetbrains.k2js.translate.intrinsic.functions.factories.NumberConversionFIF.INTEGER_NUMBER_TYPES; import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; @@ -62,6 +64,25 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { return (JsExpression) numberRangeConstructorInvocation; } }; + + @NotNull + private static final FunctionIntrinsic INTEGER_DIVISION_INTRINSIC = new FunctionIntrinsic() { + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert receiver != null; + TemporaryVariable left = context.declareTemporary(receiver); + assert arguments.size() == 1; + TemporaryVariable right = context.declareTemporary(arguments.get(0)); + JsBinaryOperation divRes = new JsBinaryOperation(JsBinaryOperator.DIV, left.reference(), right.reference()); + JsBinaryOperation modRes = new JsBinaryOperation(JsBinaryOperator.MOD, left.reference(), right.reference()); + JsBinaryOperation fractionalPart = new JsBinaryOperation(JsBinaryOperator.DIV, modRes, right.reference()); + return AstUtil.newSequence(left.assignmentExpression(), right.assignmentExpression(), subtract(divRes, fractionalPart)); + } + }; + @NotNull private static final NamePredicate BINARY_OPERATIONS = new NamePredicate(OperatorConventions.BINARY_OPERATION_NAMES.values()); @@ -77,20 +98,14 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { @NotNull @Override public FunctionIntrinsic getIntrinsic(@NotNull FunctionDescriptor descriptor) { + if (pattern(INTEGER_NUMBER_TYPES + ".div").apply(descriptor)) { + return INTEGER_DIVISION_INTRINSIC; + } if (descriptor.getName().equals(Name.identifier("rangeTo"))) { return RANGE_TO_INTRINSIC; } final JsBinaryOperator operator = getOperator(descriptor); - return new FunctionIntrinsic() { - @NotNull - @Override - public JsExpression apply(@Nullable JsExpression receiver, - @NotNull List arguments, - @NotNull TranslationContext context) { - assert arguments.size() == 1 : "Binary operator should have a receiver and one argument"; - return new JsBinaryOperation(operator, receiver, arguments.get(0)); - } - }; + return new PrimitiveBinaryOperationFunctionIntrinsic(operator); } @NotNull @@ -105,4 +120,24 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { } return OperatorTable.getBinaryOperator(token); } + + private static class PrimitiveBinaryOperationFunctionIntrinsic extends FunctionIntrinsic { + + @NotNull + private final JsBinaryOperator operator; + + private PrimitiveBinaryOperationFunctionIntrinsic(@NotNull JsBinaryOperator operator) { + this.operator = operator; + } + + @NotNull + @Override + public JsExpression apply(@Nullable JsExpression receiver, + @NotNull List arguments, + @NotNull TranslationContext context) { + assert receiver != null; + assert arguments.size() == 1 : "Binary operator should have a receiver and one argument"; + return new JsBinaryOperation(operator, receiver, arguments.get(0)); + } + } } diff --git a/js/js.translator/testFiles/number/cases/division.kt b/js/js.translator/testFiles/number/cases/division.kt new file mode 100644 index 00000000000..88db0e4fec5 --- /dev/null +++ b/js/js.translator/testFiles/number/cases/division.kt @@ -0,0 +1,44 @@ +package foo + +fun box(): Any? { + if (3 / 4 != 0) { + return "1" + } + if (-5 / 4 != -1) { + return -5 / 4 + } + if ((3.0 / 4.0 - 0.75) > 0.01) { + return "3" + } + if ((-10.0 / 4.0 + 2.5) > 0.01) { + return "4" + } + val i1: Int = 5 + val i2: Int = 2 + if (i1 / i2 != 2) { + return "5" + } + val i3: Short = 5 + val i4: Short = 2 + if (i3 / i4 != 2) { + return "6" + } + val i5: Byte = 5 + val i6: Byte = 2 + if (i5 / i6 != 2) { + return "7" + } + + val f1: Double = 5.0 + val f2: Double = 2.0 + if ((f1 / f2 - 2.5) > 0.01) { + return "8" + } + + val f3: Float = 5.0.toFloat() + val f4: Float = 2.0.toFloat() + if ((f3 / f4 - 2.5.toFloat()) > 0.01) { + return "9" + } + return "SUCCESS" +} \ No newline at end of file