JS backend: add support for Long type
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
package com.google.dart.compiler.backend.js.ast;
|
||||
|
||||
public abstract class JsNumberLiteral extends JsLiteral.JsValueLiteral {
|
||||
public static final JsIntLiteral ZERO = new JsIntLiteral(0);
|
||||
|
||||
public static final class JsDoubleLiteral extends JsNumberLiteral {
|
||||
public final double value;
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
|
||||
import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getStableMangledNameForDescriptor;
|
||||
|
||||
/**
|
||||
* Encapuslates different types of constants and naming conventions.
|
||||
@@ -33,6 +35,15 @@ public final class Namer {
|
||||
public static final String KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase();
|
||||
public static final JsNameRef KOTLIN_OBJECT_REF = new JsNameRef(KOTLIN_NAME);
|
||||
|
||||
public static final String EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getAny(), "equals");
|
||||
public static final String COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getComparable(), "compareTo");
|
||||
public static final String NUMBER_RANGE = "NumberRange";
|
||||
public static final String LONG_FROM_NUMBER = "fromNumber";
|
||||
public static final String LONG_TO_NUMBER = "toNumber";
|
||||
public static final String LONG_FROM_INT = "fromInt";
|
||||
public static final String PRIMITIVE_COMPARE_TO = "primitiveCompareTo";
|
||||
public static final String IS_NUMBER = "isNumber";
|
||||
|
||||
public static final String CALLEE_NAME = "$fun";
|
||||
|
||||
private static final String CALL_FUNCTION = "call";
|
||||
|
||||
@@ -98,9 +98,15 @@ public final class StandardClasses {
|
||||
standardClasses.declare().forFQ("kotlin.IntRange").kotlinClass("NumberRange")
|
||||
.methods("iterator", "contains").properties("start", "end", "increment");
|
||||
|
||||
standardClasses.declare().forFQ("kotlin.LongRange").kotlinClass("LongRange")
|
||||
.methods("iterator", "contains").properties("start", "end", "increment");
|
||||
|
||||
standardClasses.declare().forFQ("kotlin.IntProgression").kotlinClass("NumberProgression")
|
||||
.methods("iterator", "contains").properties("start", "end", "increment");
|
||||
|
||||
standardClasses.declare().forFQ("kotlin.LongProgression").kotlinClass("LongProgression")
|
||||
.methods("iterator", "contains").properties("start", "end", "increment");
|
||||
|
||||
standardClasses.declare().forFQ("kotlin.Enum").kotlinClass("Enum");
|
||||
|
||||
standardClasses.declare().forFQ("kotlin.Comparable").kotlinClass("Comparable");
|
||||
|
||||
@@ -77,6 +77,9 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
|
||||
return context.program().getNumberLiteral(((Number) value).intValue());
|
||||
}
|
||||
else if (value instanceof Long) {
|
||||
return JsAstUtils.newLong((Long) value, context);
|
||||
}
|
||||
else if (value instanceof Number) {
|
||||
return context.program().getNumberLiteral(((Number) value).doubleValue());
|
||||
}
|
||||
|
||||
@@ -93,10 +93,13 @@ public final class PatternTranslator extends AbstractTranslator {
|
||||
if (NamePredicate.STRING.apply(typeName)) {
|
||||
jsSTypeName = "string";
|
||||
}
|
||||
else if (NamePredicate.LONG.apply(typeName)) {
|
||||
return JsAstUtils.isLong(expressionToMatch);
|
||||
}
|
||||
else if (NamePredicate.NUMBER.apply(typeName)) {
|
||||
return JsAstUtils.isNumber(expressionToMatch);
|
||||
}
|
||||
else if (NamePredicate.PRIMITIVE_NUMBERS.apply(typeName)) {
|
||||
else if (NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS.apply(typeName)) {
|
||||
jsSTypeName = "number";
|
||||
}
|
||||
else {
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ public final class FunctionIntrinsics {
|
||||
}
|
||||
|
||||
private void registerFactories() {
|
||||
register(LongOperationFIF.INSTANCE$);
|
||||
register(PrimitiveUnaryOperationFIF.INSTANCE);
|
||||
register(PrimitiveBinaryOperationFIF.INSTANCE);
|
||||
register(StringOperationFIF.INSTANCE);
|
||||
|
||||
+8
-1
@@ -46,6 +46,9 @@ public final class ArrayFIF extends CompositeFIF {
|
||||
@NotNull
|
||||
private static final NamePredicate BOOLEAN_ARRAY;
|
||||
|
||||
@NotNull
|
||||
private static final NamePredicate LONG_ARRAY;
|
||||
|
||||
@NotNull
|
||||
private static final NamePredicate ARRAY;
|
||||
|
||||
@@ -60,7 +63,7 @@ public final class ArrayFIF extends CompositeFIF {
|
||||
List<Name> arrayFactoryMethodNames = Lists.newArrayList(Name.identifier("array"));
|
||||
for (PrimitiveType type : PrimitiveType.values()) {
|
||||
Name arrayTypeName = type.getArrayTypeName();
|
||||
if (type != PrimitiveType.CHAR && type != PrimitiveType.BOOLEAN) {
|
||||
if (type != PrimitiveType.CHAR && type != PrimitiveType.BOOLEAN && type != PrimitiveType.LONG) {
|
||||
arrayTypeNames.add(arrayTypeName);
|
||||
}
|
||||
arrayFactoryMethodNames.add(Name.identifier(decapitalize(arrayTypeName.asString())));
|
||||
@@ -69,14 +72,17 @@ public final class ArrayFIF extends CompositeFIF {
|
||||
Name arrayName = Name.identifier("Array");
|
||||
Name booleanArrayName = PrimitiveType.BOOLEAN.getArrayTypeName();
|
||||
Name charArrayName = PrimitiveType.CHAR.getArrayTypeName();
|
||||
Name longArrayName = PrimitiveType.LONG.getArrayTypeName();
|
||||
|
||||
NUMBER_ARRAY = new NamePredicate(arrayTypeNames);
|
||||
CHAR_ARRAY = new NamePredicate(charArrayName);
|
||||
BOOLEAN_ARRAY = new NamePredicate(booleanArrayName);
|
||||
LONG_ARRAY = new NamePredicate(longArrayName);
|
||||
ARRAY = new NamePredicate(arrayName);
|
||||
|
||||
arrayTypeNames.add(charArrayName);
|
||||
arrayTypeNames.add(booleanArrayName);
|
||||
arrayTypeNames.add(longArrayName);
|
||||
arrayTypeNames.add(arrayName);
|
||||
ARRAYS = new NamePredicate(arrayTypeNames);
|
||||
ARRAY_FACTORY_METHODS = pattern(Namer.KOTLIN_LOWER_NAME, new NamePredicate(arrayFactoryMethodNames));
|
||||
@@ -138,6 +144,7 @@ public final class ArrayFIF extends CompositeFIF {
|
||||
add(pattern(NUMBER_ARRAY, "<init>"),new KotlinFunctionIntrinsic("numberArrayOfSize"));
|
||||
add(pattern(CHAR_ARRAY, "<init>"), new KotlinFunctionIntrinsic("charArrayOfSize"));
|
||||
add(pattern(BOOLEAN_ARRAY, "<init>"), new KotlinFunctionIntrinsic("booleanArrayOfSize"));
|
||||
add(pattern(LONG_ARRAY, "<init>"), new KotlinFunctionIntrinsic("longArrayOfSize"));
|
||||
add(ARRAY_FACTORY_METHODS, ARRAY_INTRINSIC);
|
||||
}
|
||||
}
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.translate.intrinsic.functions.factories
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.k2js.translate.context.Namer
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern
|
||||
import org.jetbrains.k2js.translate.utils.ID
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils.*
|
||||
|
||||
// TODO Move to FunctionCallCases
|
||||
public object LongOperationFIF : FunctionIntrinsicFactory {
|
||||
|
||||
val LONG_EQUALS_ANY = pattern("Long.equals")
|
||||
val LONG_BINARY_OPERATION_LONG = pattern("Long.compareTo|rangeTo|plus|minus|times|div|mod|and|or|xor(Long)")
|
||||
val LONG_BIT_SHIFTS = pattern("Long.shl|shr|ushr(Int)")
|
||||
val LONG_BINARY_OPERATION_INTEGER = pattern("Long.compareTo|rangeTo|plus|minus|times|div|mod(Int|Short|Byte)")
|
||||
val LONG_BINARY_OPERATION_FLOATING_POINT = pattern("Long.compareTo|rangeTo|plus|minus|times|div|mod(Double|Float)")
|
||||
val INTEGER_BINARY_OPERATION_LONG = pattern("Int|Short|Byte.compareTo|rangeTo|plus|minus|times|div|mod(Long)")
|
||||
val FLOATING_POINT_BINARY_OPERATION_LONG = pattern("Double|Float.compareTo|rangeTo|plus|minus|times|div|mod(Long)")
|
||||
|
||||
private val longBinaryIntrinsics =
|
||||
(
|
||||
listOf(
|
||||
"equals" to Namer.EQUALS_METHOD_NAME,
|
||||
"compareTo" to Namer.COMPARE_TO_METHOD_NAME,
|
||||
"rangeTo" to "rangeTo",
|
||||
"plus" to "add",
|
||||
"minus" to "subtract",
|
||||
"times" to "multiply",
|
||||
"div" to "div",
|
||||
"mod" to "modulo",
|
||||
"shl" to "shiftLeft",
|
||||
"shr" to "shiftRight",
|
||||
"ushr" to "shiftRightUnsigned",
|
||||
"and" to "and",
|
||||
"or" to "or",
|
||||
"xor" to "xor"
|
||||
).map { it.first to methodIntrinsic(it.second) }).toMap()
|
||||
|
||||
private val floatBinaryIntrinsics: Map<String, BaseBinaryIntrinsic> =
|
||||
mapOf(
|
||||
"compareTo" to BaseBinaryIntrinsic(::primitiveCompareTo),
|
||||
"rangeTo" to BaseBinaryIntrinsic(::numberRangeTo),
|
||||
"plus" to BaseBinaryIntrinsic(::sum),
|
||||
"minus" to BaseBinaryIntrinsic(::subtract),
|
||||
"times" to BaseBinaryIntrinsic(::mul),
|
||||
"div" to BaseBinaryIntrinsic(::div),
|
||||
"mod" to BaseBinaryIntrinsic(::mod)
|
||||
);
|
||||
|
||||
class BaseBinaryIntrinsic(val applyFun: (left: JsExpression, right: JsExpression) -> JsExpression) : FunctionIntrinsic() {
|
||||
override fun apply(receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
||||
assert(receiver != null)
|
||||
assert(arguments.size() == 1)
|
||||
return applyFun(receiver!!, arguments.get(0))
|
||||
}
|
||||
}
|
||||
|
||||
fun methodIntrinsic(methodName: String): BaseBinaryIntrinsic =
|
||||
BaseBinaryIntrinsic() { left, right -> invokeMethod(left, methodName, right) }
|
||||
|
||||
fun wrapIntrinsicIfPresent(intrinsic: BaseBinaryIntrinsic?, toLeft: (JsExpression) -> JsExpression, toRight: (JsExpression) -> JsExpression): FunctionIntrinsic? =
|
||||
if (intrinsic != null) BaseBinaryIntrinsic() { left, right -> intrinsic.applyFun(toLeft(left), toRight(right)) } else null
|
||||
|
||||
override fun getIntrinsic(descriptor: FunctionDescriptor): FunctionIntrinsic? {
|
||||
val operationName = descriptor.getName().asString()
|
||||
return when {
|
||||
LONG_EQUALS_ANY.apply(descriptor) || LONG_BINARY_OPERATION_LONG.apply(descriptor) || LONG_BIT_SHIFTS.apply(descriptor) ->
|
||||
longBinaryIntrinsics[operationName]
|
||||
INTEGER_BINARY_OPERATION_LONG.apply(descriptor) ->
|
||||
wrapIntrinsicIfPresent(longBinaryIntrinsics[operationName], { longFromInt(it) }, ID)
|
||||
LONG_BINARY_OPERATION_INTEGER.apply(descriptor) ->
|
||||
wrapIntrinsicIfPresent(longBinaryIntrinsics[operationName], ID, { longFromInt(it) })
|
||||
FLOATING_POINT_BINARY_OPERATION_LONG.apply(descriptor) ->
|
||||
wrapIntrinsicIfPresent(floatBinaryIntrinsics[operationName], ID, { invokeMethod(it, Namer.LONG_TO_NUMBER) })
|
||||
LONG_BINARY_OPERATION_FLOATING_POINT.apply(descriptor) ->
|
||||
wrapIntrinsicIfPresent(floatBinaryIntrinsics[operationName], { invokeMethod(it, Namer.LONG_TO_NUMBER) }, ID)
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
-22
@@ -16,41 +16,54 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.intrinsic.functions.factories
|
||||
|
||||
import com.google.common.base.Predicates
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern
|
||||
import org.jetbrains.k2js.translate.utils.ID
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils.*
|
||||
|
||||
//TODO: support longs and chars
|
||||
public object NumberConversionFIF : CompositeFIF() {
|
||||
val USE_AS_IS = Predicates.or(
|
||||
pattern("Int.toInt|toFloat|toDouble"), pattern("Short.toShort|toInt|toFloat|toDouble"),
|
||||
pattern("Byte.toByte|toShort|toInt|toFloat|toDouble"), pattern("Float|Double.toFloat|toDouble"),
|
||||
pattern("Long.toLong"), pattern("Char.toChar")
|
||||
);
|
||||
|
||||
//NOTE: treat Number as if it is floating point type
|
||||
private val convertOperations: Map<String, (receiver: JsExpression, context: TranslationContext) ->JsExpression> =
|
||||
private val convertOperations: Map<String, ConversionUnaryIntrinsic> =
|
||||
mapOf(
|
||||
"Int.toInt|toFloat|toDouble" to { (receiver, context) -> receiver },
|
||||
"Short.toShort|toInt|toFloat|toDouble" to { (receiver, context) -> receiver },
|
||||
"Byte.toByte|toShort|toInt|toFloat|toDouble" to { (receiver, context) -> receiver },
|
||||
"Float|Double|Number.toFloat|toDouble" to { (receiver, context) -> receiver },
|
||||
"Float|Double.toInt" to ConversionUnaryIntrinsic { toInt32(it) },
|
||||
"Int|Float|Double.toShort" to ConversionUnaryIntrinsic { toShort(it) },
|
||||
"Short|Int|Float|Double.toByte" to ConversionUnaryIntrinsic { toByte(it) },
|
||||
|
||||
"Float|Double|Number.toInt" to { (receiver, context) -> JsAstUtils.toInt32(receiver, context) },
|
||||
"Int|Float|Double|Number.toShort" to { (receiver, context) -> JsAstUtils.toShort(receiver) },
|
||||
"Short|Int|Float|Double|Number.toByte" to { (receiver, context) -> JsAstUtils.toByte(receiver) }
|
||||
"Int|Short|Byte.toLong" to ConversionUnaryIntrinsic { longFromInt(it) },
|
||||
"Float|Double.toLong" to ConversionUnaryIntrinsic { longFromNumber(it) },
|
||||
|
||||
"Number.toInt" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToInt", it) },
|
||||
"Number.toShort" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToShort", it) },
|
||||
"Number.toByte" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToByte", it) },
|
||||
"Number.toFloat|toDouble" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToDouble", it) },
|
||||
"Number.toLong" to ConversionUnaryIntrinsic { invokeKotlinFunction("numberToLong", it) },
|
||||
|
||||
"Long.toFloat|toDouble" to ConversionUnaryIntrinsic { invokeMethod(it, "toNumber") },
|
||||
"Long.toInt" to ConversionUnaryIntrinsic { invokeMethod(it, "toInt") },
|
||||
"Long.toShort" to ConversionUnaryIntrinsic { toShort(invokeMethod(it, "toInt")) },
|
||||
"Long.toByte" to ConversionUnaryIntrinsic { toByte(invokeMethod(it, "toInt")) }
|
||||
)
|
||||
|
||||
fun newUnaryIntrinsic(applyFun: (receiver: JsExpression, context: TranslationContext) -> JsExpression): FunctionIntrinsic =
|
||||
object : FunctionIntrinsic() {
|
||||
override fun apply(receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
||||
assert(receiver != null)
|
||||
assert(arguments.size() == 0)
|
||||
return applyFun(receiver!!, context)
|
||||
}
|
||||
}
|
||||
class ConversionUnaryIntrinsic(val applyFun: (receiver: JsExpression) -> JsExpression) : FunctionIntrinsic() {
|
||||
override fun apply(receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
||||
assert(receiver != null)
|
||||
assert(arguments.size() == 0)
|
||||
return applyFun(receiver!!)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for((stringPattern, applyFun) in convertOperations) {
|
||||
add(pattern(stringPattern), newUnaryIntrinsic(applyFun))
|
||||
add(USE_AS_IS!!, ConversionUnaryIntrinsic(ID))
|
||||
for((stringPattern, intrinsic) in convertOperations) {
|
||||
add(pattern(stringPattern), intrinsic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-53
@@ -19,14 +19,14 @@ package org.jetbrains.k2js.translate.intrinsic.functions.factories;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic;
|
||||
@@ -39,78 +39,71 @@ 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.setArguments;
|
||||
|
||||
public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
INSTANCE;
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic RANGE_TO_INTRINSIC = new FunctionIntrinsic() {
|
||||
private static abstract class BinaryOperationInstrinsicBase extends FunctionIntrinsic {
|
||||
@NotNull
|
||||
public abstract JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression rangeStart, @NotNull List<JsExpression> arguments,
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.size() == 1 : "RangeTo must have one argument.";
|
||||
assert rangeStart != null;
|
||||
JsExpression rangeEnd = arguments.get(0);
|
||||
JsNameRef expr = new JsNameRef("NumberRange", "Kotlin");
|
||||
HasArguments numberRangeConstructorInvocation = new JsNew(expr);
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1;
|
||||
return doApply(receiver, arguments.get(0), context);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static final BinaryOperationInstrinsicBase RANGE_TO_INTRINSIC = new BinaryOperationInstrinsicBase() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
|
||||
//TODO: add tests and correct expression for reversed ranges.
|
||||
setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd);
|
||||
return numberRangeConstructorInvocation;
|
||||
return JsAstUtils.numberRangeTo(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic INTEGER_DIVISION_INTRINSIC = new FunctionIntrinsic() {
|
||||
private static final BinaryOperationInstrinsicBase INTEGER_DIVISION_INTRINSIC = new BinaryOperationInstrinsicBase() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1;
|
||||
JsBinaryOperation div = new JsBinaryOperation(JsBinaryOperator.DIV, receiver, arguments.get(0));
|
||||
return JsAstUtils.toInt32(div, context);
|
||||
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
|
||||
JsBinaryOperation div = new JsBinaryOperation(JsBinaryOperator.DIV, left, right);
|
||||
return JsAstUtils.toInt32(div);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic BUILTINS_COMPARE_TO_INTRINSIC = new FunctionIntrinsic() {
|
||||
private static final BinaryOperationInstrinsicBase BUILTINS_COMPARE_TO_INTRINSIC = new BinaryOperationInstrinsicBase() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1;
|
||||
return JsAstUtils.compareTo(receiver, arguments.get(0));
|
||||
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
|
||||
return JsAstUtils.compareTo(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static final FunctionIntrinsic PRIMITIVE_NUMBER_COMPARE_TO_INTRINSIC = new FunctionIntrinsic() {
|
||||
private static final BinaryOperationInstrinsicBase PRIMITIVE_NUMBER_COMPARE_TO_INTRINSIC = new BinaryOperationInstrinsicBase() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1;
|
||||
return JsAstUtils.primitiveCompareTo(receiver, arguments.get(0));
|
||||
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
|
||||
return JsAstUtils.primitiveCompareTo(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
@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);
|
||||
private static final DescriptorPredicate PRIMITIVE_NUMBERS_BINARY_OPERATIONS =
|
||||
pattern(NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS, BINARY_OPERATIONS);
|
||||
|
||||
private static final DescriptorPredicate PRIMITIVE_NUMBERS_COMPARE_TO_OPERATIONS =
|
||||
pattern(NamePredicate.PRIMITIVE_NUMBERS, "compareTo");
|
||||
pattern(NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS, "compareTo");
|
||||
private static final DescriptorPredicate INT_WITH_BIT_OPERATIONS = pattern("Int.or|and|xor|shl|shr|ushr");
|
||||
private static final DescriptorPredicate BOOLEAN_OPERATIONS = pattern("Boolean.or|and|xor");
|
||||
private static final DescriptorPredicate STRING_PLUS = pattern("String.plus");
|
||||
@@ -135,6 +128,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
return PRIMITIVE_NUMBER_COMPARE_TO_INTRINSIC;
|
||||
}
|
||||
|
||||
|
||||
if (JsDescriptorUtils.isBuiltin(descriptor) && descriptor.getName().equals(OperatorConventions.COMPARE_TO)) {
|
||||
return BUILTINS_COMPARE_TO_INTRINSIC;
|
||||
}
|
||||
@@ -144,10 +138,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
}
|
||||
|
||||
|
||||
if (pattern("Int|Short|Byte.div").apply(descriptor)) {
|
||||
JetType resultType = descriptor.getReturnType();
|
||||
if (!KotlinBuiltIns.getInstance().getFloatType().equals(resultType) &&
|
||||
!KotlinBuiltIns.getInstance().getDoubleType().equals(resultType))
|
||||
if (pattern("Int|Short|Byte.div(Int|Short|Byte)").apply(descriptor)) {
|
||||
return INTEGER_DIVISION_INTRINSIC;
|
||||
}
|
||||
if (descriptor.getName().equals(Name.identifier("rangeTo"))) {
|
||||
@@ -176,7 +167,7 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
return OperatorTable.getBinaryOperator(token);
|
||||
}
|
||||
|
||||
private static class PrimitiveBinaryOperationFunctionIntrinsic extends FunctionIntrinsic {
|
||||
private static class PrimitiveBinaryOperationFunctionIntrinsic extends BinaryOperationInstrinsicBase {
|
||||
|
||||
@NotNull
|
||||
private final JsBinaryOperator operator;
|
||||
@@ -187,12 +178,8 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> 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));
|
||||
public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) {
|
||||
return new JsBinaryOperation(operator, left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -34,7 +34,6 @@ import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate.PRIMITIVE_NUMBERS;
|
||||
import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern;
|
||||
|
||||
public enum PrimitiveUnaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
@@ -44,7 +43,7 @@ public enum PrimitiveUnaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
private static final NamePredicate UNARY_OPERATIONS = new NamePredicate(OperatorConventions.UNARY_OPERATION_NAMES.values());
|
||||
@NotNull
|
||||
private static final DescriptorPredicate UNARY_OPERATION_FOR_PRIMITIVE_NUMBER =
|
||||
pattern(PRIMITIVE_NUMBERS, UNARY_OPERATIONS);
|
||||
pattern(NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS, UNARY_OPERATIONS);
|
||||
@NotNull
|
||||
private static final Predicate<FunctionDescriptor> PRIMITIVE_UNARY_OPERATION_NAMES =
|
||||
Predicates.or(UNARY_OPERATION_FOR_PRIMITIVE_NUMBER, pattern("Boolean.not"), pattern("Int.inv"));
|
||||
@@ -134,5 +133,4 @@ public enum PrimitiveUnaryOperationFIF implements FunctionIntrinsicFactory {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-12
@@ -19,9 +19,7 @@ package org.jetbrains.k2js.translate.intrinsic.functions.factories;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
@@ -42,13 +40,12 @@ import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate;
|
||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic.CallParametersAwareFunctionIntrinsic;
|
||||
import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getStableMangledNameForDescriptor;
|
||||
|
||||
public final class TopLevelFIF extends CompositeFIF {
|
||||
public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals");
|
||||
@@ -133,13 +130,6 @@ public final class TopLevelFIF extends CompositeFIF {
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
private static String getStableMangledBuiltInName(@NotNull ClassDescriptor descriptor, @NotNull String functionName) {
|
||||
Collection<FunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier(functionName));
|
||||
assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor;
|
||||
return TranslationUtils.getSuggestedName(functions.iterator().next());
|
||||
}
|
||||
|
||||
private static final FunctionIntrinsic PROPERTY_METADATA_IMPL = new FunctionIntrinsic() {
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -220,7 +210,7 @@ public final class TopLevelFIF extends CompositeFIF {
|
||||
}
|
||||
}
|
||||
|
||||
String mangledName = getStableMangledBuiltInName(KotlinBuiltIns.getInstance().getMutableMap(), operationName());
|
||||
String mangledName = getStableMangledNameForDescriptor(KotlinBuiltIns.getInstance().getMutableMap(), operationName());
|
||||
|
||||
return new JsInvocation(new JsNameRef(mangledName, thisOrReceiver), arguments);
|
||||
}
|
||||
|
||||
+20
-6
@@ -35,12 +35,23 @@ public final class NamePredicate implements Predicate<Name> {
|
||||
|
||||
@NotNull
|
||||
public static final NamePredicate PRIMITIVE_NUMBERS = new NamePredicate(
|
||||
ContainerUtil.map(PrimitiveType.NUMBER_TYPES, new Function<PrimitiveType, String>() {
|
||||
@Override
|
||||
public String fun(PrimitiveType type) {
|
||||
return type.getTypeName().asString();
|
||||
}
|
||||
}));
|
||||
ContainerUtil.map(PrimitiveType.NUMBER_TYPES,
|
||||
new Function<PrimitiveType, String>() {
|
||||
@Override
|
||||
public String fun(PrimitiveType type) {
|
||||
return type.getTypeName().asString();
|
||||
}
|
||||
}));
|
||||
|
||||
@NotNull
|
||||
public static final NamePredicate PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS = new NamePredicate(
|
||||
ContainerUtil.mapNotNull(PrimitiveType.NUMBER_TYPES,
|
||||
new Function<PrimitiveType, String>() {
|
||||
@Override
|
||||
public String fun(PrimitiveType type) {
|
||||
return type != PrimitiveType.LONG ? type.getTypeName().asString() : null;
|
||||
}
|
||||
}));
|
||||
|
||||
@NotNull
|
||||
public static final NamePredicate STRING = new NamePredicate("String");
|
||||
@@ -48,6 +59,9 @@ public final class NamePredicate implements Predicate<Name> {
|
||||
@NotNull
|
||||
public static final NamePredicate NUMBER = new NamePredicate("Number");
|
||||
|
||||
@NotNull
|
||||
public static final NamePredicate LONG = new NamePredicate(PrimitiveType.LONG.getTypeName());
|
||||
|
||||
@NotNull
|
||||
private final Set<Name> validNames = Sets.newHashSet();
|
||||
|
||||
|
||||
+75
-10
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.OverrideResolver;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -43,25 +44,25 @@ public final class PatternBuilder {
|
||||
@NotNull
|
||||
public static DescriptorPredicate pattern(@NotNull NamePredicate checker, @NotNull String stringWithPattern) {
|
||||
List<NamePredicate> checkers = Lists.newArrayList(checker);
|
||||
checkers.addAll(parseStringAsCheckerList(stringWithPattern));
|
||||
return pattern(checkers);
|
||||
checkers.addAll(parseFqNamesFromString(stringWithPattern));
|
||||
return pattern(checkers, parseArgumentsFromString(stringWithPattern));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DescriptorPredicate pattern(@NotNull String stringWithPattern, @NotNull NamePredicate checker) {
|
||||
List<NamePredicate> checkers = Lists.newArrayList(parseStringAsCheckerList(stringWithPattern));
|
||||
List<NamePredicate> checkers = Lists.newArrayList(parseFqNamesFromString(stringWithPattern));
|
||||
checkers.add(checker);
|
||||
return pattern(checkers);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DescriptorPredicate pattern(@NotNull String string) {
|
||||
List<NamePredicate> checkers = parseStringAsCheckerList(string);
|
||||
return pattern(checkers);
|
||||
public static DescriptorPredicate pattern(@NotNull String stringWithPattern) {
|
||||
return pattern(parseFqNamesFromString(stringWithPattern), parseArgumentsFromString(stringWithPattern));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<NamePredicate> parseStringAsCheckerList(@NotNull String stringWithPattern) {
|
||||
private static List<NamePredicate> parseFqNamesFromString(@NotNull String stringWithPattern) {
|
||||
stringWithPattern = getNamePatternFromString(stringWithPattern);
|
||||
String[] subPatterns = stringWithPattern.split("\\.");
|
||||
List<NamePredicate> checkers = Lists.newArrayList();
|
||||
for (String subPattern : subPatterns) {
|
||||
@@ -71,8 +72,55 @@ public final class PatternBuilder {
|
||||
return checkers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<NamePredicate> parseArgumentsFromString(@NotNull String stringWithPattern) {
|
||||
stringWithPattern = getArgumentsPatternFromString(stringWithPattern);
|
||||
if (stringWithPattern == null) return null;
|
||||
|
||||
List<NamePredicate> checkers = Lists.newArrayList();
|
||||
if (stringWithPattern.isEmpty()) {
|
||||
return checkers;
|
||||
}
|
||||
|
||||
String[] subPatterns = stringWithPattern.split("\\,");
|
||||
for (String subPattern : subPatterns) {
|
||||
String[] validNames = subPattern.split("\\|");
|
||||
checkers.add(new NamePredicate(validNames));
|
||||
}
|
||||
return checkers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getNamePatternFromString(@NotNull String stringWithPattern) {
|
||||
int left = stringWithPattern.indexOf("(");
|
||||
if (left < 0) {
|
||||
return stringWithPattern;
|
||||
}
|
||||
else {
|
||||
return stringWithPattern.substring(0, left);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getArgumentsPatternFromString(@NotNull String stringWithPattern) {
|
||||
int left = stringWithPattern.indexOf("(");
|
||||
if (left < 0) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
int right = stringWithPattern.indexOf(")");
|
||||
assert right == stringWithPattern.length() - 1 : "expected ')' at the end: " + stringWithPattern;
|
||||
return stringWithPattern.substring(left + 1, right);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static DescriptorPredicate pattern(@NotNull List<NamePredicate> checkers) {
|
||||
return pattern(checkers, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static DescriptorPredicate pattern(@NotNull List<NamePredicate> checkers, @Nullable List<NamePredicate> arguments) {
|
||||
assert !checkers.isEmpty();
|
||||
final List<NamePredicate> checkersWithPrefixChecker = Lists.newArrayList();
|
||||
if (!checkers.get(0).apply(KOTLIN_NAME)) {
|
||||
@@ -83,6 +131,8 @@ public final class PatternBuilder {
|
||||
|
||||
assert checkersWithPrefixChecker.size() > 1;
|
||||
|
||||
final List<NamePredicate> argumentCheckers = arguments != null ? Lists.newArrayList(arguments) : null;
|
||||
|
||||
return new DescriptorPredicate() {
|
||||
@Override
|
||||
public boolean apply(@Nullable FunctionDescriptor descriptor) {
|
||||
@@ -98,10 +148,25 @@ public final class PatternBuilder {
|
||||
|
||||
private boolean doApply(@NotNull FunctionDescriptor descriptor) {
|
||||
List<Name> nameParts = DescriptorUtils.getFqName(descriptor).pathSegments();
|
||||
if (nameParts.size() != checkersWithPrefixChecker.size()) {
|
||||
return false;
|
||||
if (nameParts.size() != checkersWithPrefixChecker.size()) return false;
|
||||
|
||||
return allNamePartsValid(nameParts) && checkAllArgumentsValidIfNeeded(descriptor);
|
||||
}
|
||||
|
||||
private boolean checkAllArgumentsValidIfNeeded(@NotNull FunctionDescriptor descriptor) {
|
||||
if (argumentCheckers != null) {
|
||||
List<ValueParameterDescriptor> valueParameterDescriptors = descriptor.getValueParameters();
|
||||
if (valueParameterDescriptors.size() != argumentCheckers.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < valueParameterDescriptors.size(); i++) {
|
||||
ValueParameterDescriptor valueParameterDescriptor = valueParameterDescriptors.get(i);
|
||||
Name name = JsDescriptorUtils.getNameIfStandardType(valueParameterDescriptor.getType());
|
||||
NamePredicate namePredicate = argumentCheckers.get(i);
|
||||
if (!namePredicate.apply(name)) return false;
|
||||
}
|
||||
}
|
||||
return allNamePartsValid(nameParts);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean allNamePartsValid(@NotNull List<Name> nameParts) {
|
||||
|
||||
+3
-2
@@ -31,6 +31,7 @@ import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
|
||||
|
||||
object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
val PRIMITIVE_COMPARE_TO = pattern("Int|Short|Byte|Double|Float|Char|String.compareTo")
|
||||
|
||||
private object CompareToIntrinsic : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
@@ -43,7 +44,7 @@ object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
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))
|
||||
return JsBinaryOperation(operator, compareTo, JsNumberLiteral.ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ object CompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||
if (JsDescriptorUtils.isBuiltin(descriptor))
|
||||
when {
|
||||
pattern("Int|Short|Byte|Double|Float|Char|String|Long.compareTo").apply(descriptor) ->
|
||||
PRIMITIVE_COMPARE_TO.apply(descriptor) ->
|
||||
return CompareToIntrinsic
|
||||
else ->
|
||||
return CompareToFunctionIntrinsic
|
||||
|
||||
+13
-3
@@ -33,9 +33,20 @@ import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
import org.jetbrains.jet.lexer.JetToken
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern
|
||||
|
||||
object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
val LONG_EQUALS_ANY = pattern("Long.equals")
|
||||
|
||||
private object LONG_EQUALS_ANY_INTRINSIC : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val isNegated = getOperationToken(expression) == JetTokens.EXCLEQ
|
||||
val invokeEquals = JsAstUtils.equalsForObject(left, right)
|
||||
return if (isNegated) JsAstUtils.not(invokeEquals) else invokeEquals
|
||||
}
|
||||
}
|
||||
|
||||
private object EqualsIntrinsic : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val isNegated = getOperationToken(expression) == JetTokens.EXCLEQ
|
||||
@@ -54,7 +65,7 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
val left = expression.getLeft()
|
||||
assert(left != null) { "No left-hand side: " + expression.getText() }
|
||||
val typeName = JsDescriptorUtils.getNameIfStandardType(left!!, context)
|
||||
return typeName != null && NamePredicate.PRIMITIVE_NUMBERS.apply(typeName)
|
||||
return typeName != null && NamePredicate.PRIMITIVE_NUMBERS_MAPPED_TO_PRIMITIVE_JS.apply(typeName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +73,8 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||
if (JsDescriptorUtils.isBuiltin(descriptor) || TopLevelFIF.EQUALS_IN_ANY.apply(descriptor)) {
|
||||
return EqualsIntrinsic
|
||||
return if (LONG_EQUALS_ANY.apply(descriptor)) LONG_EQUALS_ANY_INTRINSIC else EqualsIntrinsic
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.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.jet.lexer.JetToken
|
||||
import org.jetbrains.k2js.translate.context.Namer
|
||||
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.ID
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils.*
|
||||
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken
|
||||
|
||||
public object LongCompareToBOIF : BinaryOperationIntrinsicFactory {
|
||||
|
||||
val FLOATING_POINT_COMPARE_TO_LONG_PATTERN = pattern("Double|Float.compareTo(Long)")
|
||||
val LONG_COMPARE_TO_FLOATING_POINT_PATTERN = pattern("Long.compareTo(Float|Double)")
|
||||
val INTEGER_COMPARE_TO_LONG_PATTERN = pattern("Int|Short|Byte.compareTo(Long)")
|
||||
val LONG_COMPARE_TO_INTEGER_PATTERN = pattern("Long.compareTo(Int|Short|Byte)")
|
||||
val LONG_COMPARE_TO_LONG_PATTERN = pattern("Long.compareTo(Long)")
|
||||
|
||||
private object FLOATING_POINT_COMPARE_TO_LONG : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
|
||||
return JsBinaryOperation(operator, left, invokeMethod(right, Namer.LONG_TO_NUMBER))
|
||||
}
|
||||
}
|
||||
|
||||
private object LONG_COMPARE_TO_FLOATING_POINT : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
|
||||
return JsBinaryOperation(operator, invokeMethod(left, Namer.LONG_TO_NUMBER), right)
|
||||
}
|
||||
}
|
||||
|
||||
private class CompareToBinaryIntrinsic(val toLeft: (JsExpression) -> JsExpression, val toRight: (JsExpression) -> JsExpression) : AbstractBinaryOperationIntrinsic() {
|
||||
override fun apply(expression: JetBinaryExpression, left: JsExpression, right: JsExpression, context: TranslationContext): JsExpression {
|
||||
val operator = OperatorTable.getBinaryOperator(getOperationToken(expression))
|
||||
val compareInvocation = compareForObject(toLeft(left), toRight(right))
|
||||
return JsBinaryOperation(operator, compareInvocation, JsNumberLiteral.ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
private val INTEGER_COMPARE_TO_LONG = CompareToBinaryIntrinsic( { longFromInt(it) }, ID)
|
||||
private val LONG_COMPARE_TO_INTEGER = CompareToBinaryIntrinsic( ID, { longFromInt(it) })
|
||||
private val LONG_COMPARE_TO_LONG = CompareToBinaryIntrinsic( ID, ID )
|
||||
|
||||
override public fun getSupportTokens(): ImmutableSet<JetToken> = OperatorConventions.COMPARISON_OPERATIONS
|
||||
|
||||
override public fun getIntrinsic(descriptor: FunctionDescriptor): BinaryOperationIntrinsic? {
|
||||
if (JsDescriptorUtils.isBuiltin(descriptor)) {
|
||||
return when {
|
||||
FLOATING_POINT_COMPARE_TO_LONG_PATTERN.apply(descriptor) -> FLOATING_POINT_COMPARE_TO_LONG
|
||||
LONG_COMPARE_TO_FLOATING_POINT_PATTERN.apply(descriptor) -> LONG_COMPARE_TO_FLOATING_POINT
|
||||
INTEGER_COMPARE_TO_LONG_PATTERN.apply(descriptor) -> INTEGER_COMPARE_TO_LONG
|
||||
LONG_COMPARE_TO_INTEGER_PATTERN.apply(descriptor) -> LONG_COMPARE_TO_INTEGER
|
||||
LONG_COMPARE_TO_LONG_PATTERN.apply(descriptor) -> LONG_COMPARE_TO_LONG
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -38,7 +38,7 @@ public class BinaryOperationIntrinsics {
|
||||
|
||||
private val intrinsicCache = THashMap<Pair<JetToken, FunctionDescriptor>, BinaryOperationIntrinsic>()
|
||||
|
||||
private val factories = listOf(EqualsBOIF, CompareToBOIF)
|
||||
private val factories = listOf(LongCompareToBOIF, EqualsBOIF, CompareToBOIF)
|
||||
|
||||
public fun getIntrinsic(expression: JetBinaryExpression, context: TranslationContext): BinaryOperationIntrinsic {
|
||||
val token = getOperationToken(expression)
|
||||
|
||||
@@ -119,33 +119,103 @@ public final class JsAstUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toInt32(@NotNull JsExpression expression, @NotNull TranslationContext context) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.BIT_OR, expression, context.program().getNumberLiteral(0));
|
||||
public static JsInvocation invokeKotlinFunction(@NotNull String name, @NotNull JsExpression... argument) {
|
||||
return new JsInvocation(new JsNameRef(name, Namer.KOTLIN_OBJECT_REF), argument);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsInvocation invokeMethod(@NotNull JsExpression thisObject, @NotNull String name, @NotNull JsExpression... arguments) {
|
||||
return new JsInvocation(new JsNameRef(name, thisObject), arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toInt32(@NotNull JsExpression expression) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.BIT_OR, expression, JsNumberLiteral.ZERO);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toShort(@NotNull JsExpression expression) {
|
||||
return new JsInvocation(new JsNameRef(OperatorConventions.SHORT.getIdentifier(), Namer.KOTLIN_OBJECT_REF), expression);
|
||||
return invokeKotlinFunction(OperatorConventions.SHORT.getIdentifier(), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toByte(@NotNull JsExpression expression) {
|
||||
return new JsInvocation(new JsNameRef(OperatorConventions.BYTE.getIdentifier(), Namer.KOTLIN_OBJECT_REF), expression);
|
||||
return invokeKotlinFunction(OperatorConventions.BYTE.getIdentifier(), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression toLong(@NotNull JsExpression expression) {
|
||||
return invokeKotlinFunction(OperatorConventions.LONG.getIdentifier(), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression compareTo(@NotNull JsExpression left, @NotNull JsExpression right) {
|
||||
return new JsInvocation(new JsNameRef(OperatorConventions.COMPARE_TO.getIdentifier(), Namer.KOTLIN_OBJECT_REF), left, right);
|
||||
return invokeKotlinFunction(OperatorConventions.COMPARE_TO.getIdentifier(), 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);
|
||||
return invokeKotlinFunction(Namer.PRIMITIVE_COMPARE_TO, left, right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression isNumber(@NotNull JsExpression expression) {
|
||||
return new JsInvocation(new JsNameRef("isNumber", Namer.KOTLIN_OBJECT_REF), expression);
|
||||
return invokeKotlinFunction(Namer.IS_NUMBER, expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression rangeTo(@NotNull String rangeClassName, @NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) {
|
||||
JsNameRef expr = new JsNameRef(rangeClassName, Namer.KOTLIN_NAME);
|
||||
JsNew numberRangeConstructorInvocation = new JsNew(expr);
|
||||
setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd);
|
||||
return numberRangeConstructorInvocation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression numberRangeTo(@NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) {
|
||||
return rangeTo(Namer.NUMBER_RANGE, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static final JsNameRef kotlinLongNameRef = new JsNameRef("Long", Namer.KOTLIN_OBJECT_REF);
|
||||
|
||||
@NotNull
|
||||
public static JsExpression isLong(@NotNull JsExpression expression) {
|
||||
return instanceOf(expression, kotlinLongNameRef);
|
||||
}
|
||||
|
||||
public static JsExpression newLong(long value, @NotNull TranslationContext context) {
|
||||
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
|
||||
int low = (int) value;
|
||||
int high = (int) (value >> 32);
|
||||
List<JsExpression> args = new SmartList<JsExpression>();
|
||||
args.add(context.program().getNumberLiteral(low));
|
||||
args.add(context.program().getNumberLiteral(high));
|
||||
return new JsNew(kotlinLongNameRef, args);
|
||||
}
|
||||
else {
|
||||
return longFromInt(context.program().getNumberLiteral((int) value));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression longFromInt(@NotNull JsExpression expression) {
|
||||
return invokeMethod(kotlinLongNameRef, Namer.LONG_FROM_INT, expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression longFromNumber(@NotNull JsExpression expression) {
|
||||
return invokeMethod(kotlinLongNameRef, Namer.LONG_FROM_NUMBER, expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression equalsForObject(@NotNull JsExpression left, @NotNull JsExpression right) {
|
||||
return invokeMethod(left, Namer.EQUALS_METHOD_NAME, right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression compareForObject(@NotNull JsExpression left, @NotNull JsExpression right) {
|
||||
return invokeMethod(left, Namer.COMPARE_TO_METHOD_NAME, right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -163,6 +233,11 @@ public final class JsAstUtils {
|
||||
return new JsBinaryOperation(JsBinaryOperator.OR, op1, op2);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsBinaryOperation instanceOf(@NotNull JsExpression op1, @NotNull JsExpression op2) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.INSTANCEOF, op1, op2);
|
||||
}
|
||||
|
||||
public static void setQualifier(@NotNull JsExpression selector, @Nullable JsExpression receiver) {
|
||||
assert (selector instanceof JsInvocation || selector instanceof JsNameRef);
|
||||
if (selector instanceof JsInvocation) {
|
||||
@@ -232,6 +307,16 @@ public final class JsAstUtils {
|
||||
return new JsBinaryOperation(JsBinaryOperator.MUL, left, right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsBinaryOperation div(@NotNull JsExpression left, @NotNull JsExpression right) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.DIV, left, right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsBinaryOperation mod(@NotNull JsExpression left, @NotNull JsExpression right) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.MOD, left, right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsPrefixOperation not(@NotNull JsExpression expression) {
|
||||
return new JsPrefixOperation(JsUnaryOperator.NOT, expression);
|
||||
|
||||
@@ -28,8 +28,10 @@ import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.OverrideResolver;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryConstVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
@@ -385,6 +387,10 @@ public final class TranslationUtils {
|
||||
CallableDescriptor operationDescriptor = getCallableDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
|
||||
if (operationDescriptor == null || !(operationDescriptor instanceof FunctionDescriptor)) return true;
|
||||
|
||||
JetType returnType = operationDescriptor.getReturnType();
|
||||
if (returnType != null && returnType.equals(KotlinBuiltIns.getInstance().getLongType())) return false;
|
||||
|
||||
if (context.intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) operationDescriptor).exists()) return true;
|
||||
|
||||
return false;
|
||||
@@ -423,6 +429,13 @@ public final class TranslationUtils {
|
||||
return ensureNotNull;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) {
|
||||
Collection<FunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier(functionName));
|
||||
assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor;
|
||||
return getSuggestedName(functions.iterator().next());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getSuggestedNameForInnerDeclaration(TranslationContext context, DeclarationDescriptor descriptor) {
|
||||
String suggestedName = "";
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.translate.utils
|
||||
|
||||
public val <T> ID: (T) -> T = { it }
|
||||
@@ -85,7 +85,7 @@
|
||||
return "[" + a.join(", ") + "]";
|
||||
};
|
||||
|
||||
Kotlin.compareTo = function(a, b) {
|
||||
Kotlin.compareTo = function (a, b) {
|
||||
var type = typeof a;
|
||||
if (type == "number" || type == "string") {
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
@@ -93,22 +93,46 @@
|
||||
return a.compareTo_za3rmp$(b);
|
||||
};
|
||||
|
||||
Kotlin.primitiveCompareTo = function(a, b) {
|
||||
Kotlin.primitiveCompareTo = function (a, b) {
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
};
|
||||
|
||||
Kotlin.isNumber = function (a) {
|
||||
return typeof a == "number";
|
||||
return typeof a == "number" || a instanceof Kotlin.Long;
|
||||
};
|
||||
|
||||
Kotlin.toShort = function(a) {
|
||||
Kotlin.toInt = function (a) {
|
||||
return a | 0;
|
||||
};
|
||||
|
||||
Kotlin.toShort = function (a) {
|
||||
return (a & 0xFFFF) << 16 >> 16;
|
||||
};
|
||||
|
||||
Kotlin.toByte = function(a) {
|
||||
Kotlin.toByte = function (a) {
|
||||
return (a & 0xFF) << 24 >> 24;
|
||||
};
|
||||
|
||||
Kotlin.numberToLong = function (a) {
|
||||
return a instanceof Kotlin.Long ? a : Kotlin.Long.fromNumber(a);
|
||||
};
|
||||
|
||||
Kotlin.numberToInt = function (a) {
|
||||
return a instanceof Kotlin.Long ? a.toInt() : (a | 0);
|
||||
};
|
||||
|
||||
Kotlin.numberToShort = function (a) {
|
||||
return Kotlin.toShort(Kotlin.numberToInt(a));
|
||||
};
|
||||
|
||||
Kotlin.numberToByte = function (a) {
|
||||
return Kotlin.toByte(Kotlin.numberToInt(a));
|
||||
};
|
||||
|
||||
Kotlin.numberToDouble = function (a) {
|
||||
return +a;
|
||||
};
|
||||
|
||||
Kotlin.intUpto = function (from, to) {
|
||||
return new Kotlin.NumberRange(from, to);
|
||||
};
|
||||
@@ -530,6 +554,15 @@
|
||||
}
|
||||
});
|
||||
|
||||
function isSameNotNullRanges(other) {
|
||||
var classObject = this.constructor;
|
||||
if (this instanceof classObject && other instanceof classObject) {
|
||||
return this.isEmpty() && other.isEmpty() ||
|
||||
(this.start === other.start && this.end === other.end && this.increment === other.increment);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Kotlin.NumberRange = Kotlin.createClassNow(null,
|
||||
function (start, end) {
|
||||
this.start = start;
|
||||
@@ -545,11 +578,7 @@
|
||||
isEmpty: function () {
|
||||
return this.start > this.end;
|
||||
},
|
||||
equals_za3rmp$: function(other) {
|
||||
if (other == null)
|
||||
return false;
|
||||
return this.start === other.start && this.end === other.end && this.increment === other.increment;
|
||||
}
|
||||
equals_za3rmp$: isSameNotNullRanges
|
||||
});
|
||||
|
||||
Kotlin.NumberProgression = Kotlin.createClassNow(null,
|
||||
@@ -566,6 +595,58 @@
|
||||
}
|
||||
});
|
||||
|
||||
Kotlin.LongRangeIterator = Kotlin.createClassNow(Kotlin.Iterator,
|
||||
function (start, end, increment) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.increment = increment;
|
||||
this.i = start;
|
||||
}, {
|
||||
next: function () {
|
||||
var value = this.i;
|
||||
this.i = this.i.add(this.increment);
|
||||
return value;
|
||||
},
|
||||
hasNext: function () {
|
||||
if (this.increment.isNegative())
|
||||
return this.i.compare(this.end) >= 0;
|
||||
else
|
||||
return this.i.compare(this.end) <= 0;
|
||||
}
|
||||
});
|
||||
|
||||
Kotlin.LongRange = Kotlin.createClassNow(null,
|
||||
function (start, end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.increment = Kotlin.Long.ONE;
|
||||
}, {
|
||||
contains: function (number) {
|
||||
return this.start.compare(number) <= 0 && number.compare(this.end) <= 0;
|
||||
},
|
||||
iterator: function () {
|
||||
return new Kotlin.LongRangeIterator(this.start, this.end, this.increment);
|
||||
},
|
||||
isEmpty: function () {
|
||||
return this.start.compare(this.end) > 0;
|
||||
},
|
||||
equals_za3rmp$: isSameNotNullRanges
|
||||
});
|
||||
|
||||
Kotlin.LongProgression = Kotlin.createClassNow(null,
|
||||
function (start, end, increment) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.increment = increment;
|
||||
}, {
|
||||
iterator: function () {
|
||||
return new Kotlin.LongRangeIterator(this.start, this.end, this.increment);
|
||||
},
|
||||
isEmpty: function() {
|
||||
return this.increment.isNegative() ? this.start.compare(this.end) < 0 : this.start.compare(this.end) > 0;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @template T
|
||||
@@ -703,6 +784,12 @@
|
||||
});
|
||||
};
|
||||
|
||||
Kotlin.longArrayOfSize = function (size) {
|
||||
return Kotlin.arrayFromFun(size, function () {
|
||||
return Kotlin.Long.ZERO;
|
||||
});
|
||||
};
|
||||
|
||||
Kotlin.arrayFromFun = function (size, initFun) {
|
||||
var result = new Array(size);
|
||||
for (var i = 0; i < size; i++) {
|
||||
|
||||
@@ -826,4 +826,15 @@
|
||||
Kotlin.Long.prototype.valueOf = function() {
|
||||
return this.toNumber();
|
||||
};
|
||||
|
||||
Kotlin.Long.prototype.plus = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
Kotlin.Long.prototype.minus = Kotlin.Long.prototype.negate;
|
||||
Kotlin.Long.prototype.inv = Kotlin.Long.prototype.not;
|
||||
|
||||
Kotlin.Long.prototype.rangeTo = function (other) {
|
||||
return new Kotlin.LongRange(this, other);
|
||||
};
|
||||
}(Kotlin));
|
||||
@@ -5,7 +5,7 @@ native fun eval(arg: String): Any? = noImpl
|
||||
|
||||
fun test(testName: String, actual: Any, expectedAsString: String) {
|
||||
val expected = eval("[$expectedAsString]")
|
||||
if (actual != expected) throw Fail("Wrong result for '$testName' function. Expected: $expected | Actual: $actual")
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
@@ -16,8 +16,8 @@ fun box(): String {
|
||||
test("byteArray", byteArray(0, 1, 2, 3, 4), "0, 1, 2, 3, 4")
|
||||
test("shortArray", shortArray(0, 1, 2, 3, 4), "0, 1, 2, 3, 4")
|
||||
test("intArray,", intArray(0, 1, 2, 3, 4), "0, 1, 2, 3, 4")
|
||||
test("longArray", longArray(0, 1, 2, 3, 4), "0, 1, 2, 3, 4")
|
||||
test("floatArray", floatArray(0.0.toFloat(), 1.0.toFloat(), 2.0.toFloat(), 3.0.toFloat(), 4.0.toFloat()), "0.0, 1.0, 2.0, 3.0, 4.0")
|
||||
test("longArray", longArray(0, 1, 2, 3, 4), "Kotlin.Long.fromInt(0), Kotlin.Long.fromInt(1), Kotlin.Long.fromInt(2), Kotlin.Long.fromInt(3), Kotlin.Long.fromInt(4)")
|
||||
test("floatArray", floatArray(0.0f, 1.0f, 2.0f, 3.0f, 4.0f), "0.0, 1.0, 2.0, 3.0, 4.0")
|
||||
test("doubleArray", doubleArray(0.0, 1.1, 2.2, 3.3, 4.4), "0.0, 1.1, 2.2, 3.3, 4.4")
|
||||
}
|
||||
catch (e: Fail) {
|
||||
|
||||
Reference in New Issue
Block a user