JS backend: add support for Long type

This commit is contained in:
Michael Nedzelsky
2014-09-23 19:00:16 +04:00
parent d1d722546e
commit dca6e31519
24 changed files with 643 additions and 134 deletions
@@ -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 {
@@ -40,6 +40,7 @@ public final class FunctionIntrinsics {
}
private void registerFactories() {
register(LongOperationFIF.INSTANCE$);
register(PrimitiveUnaryOperationFIF.INSTANCE);
register(PrimitiveBinaryOperationFIF.INSTANCE);
register(StringOperationFIF.INSTANCE);
@@ -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);
}
}
@@ -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
}
}
}
@@ -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)
}
}
}
@@ -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);
}
}
}
@@ -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 {
}
};
}
}
@@ -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);
}
@@ -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();
@@ -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) {
@@ -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
@@ -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
}
}
@@ -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
}
}
@@ -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 }
+97 -10
View File
@@ -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++) {
+11
View File
@@ -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) {