JS IR: char (always boxed for now)

This commit is contained in:
Anton Bannykh
2018-07-09 22:15:42 +03:00
committed by Anton Bannykh
parent d709b03160
commit 9233e6c176
9 changed files with 140 additions and 10 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
@@ -128,6 +129,8 @@ class JsIntrinsics(
)
)
val charConstructor = context.symbolTable.referenceConstructor(context.getClass(KotlinBuiltIns.FQ_NAMES._char.toSafe()).constructors.single())
// Helpers:
private fun getInternalFunction(name: String) =
@@ -152,6 +152,27 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
op(type, OperatorNames.MOD, withLongCoercion(intrinsics.jsMod))
op(type, OperatorNames.REM, withLongCoercion(intrinsics.jsMod))
}
for (type in arrayOf(irBuiltIns.byteType, irBuiltIns.intType)) {
op(type, ConversionNames.TO_CHAR) {
irCall(it, intrinsics.charConstructor, dispatchReceiverAsFirstArgument = true)
}
}
for (type in arrayOf(irBuiltIns.floatType, irBuiltIns.doubleType)) {
op(type, ConversionNames.TO_CHAR) {
IrCallImpl(
it.startOffset,
it.endOffset,
irBuiltIns.charType,
intrinsics.charConstructor
).apply {
putValueArgument(0, irCall(it, intrinsics.jsNumberToInt, dispatchReceiverAsFirstArgument = true))
}
}
}
op(irBuiltIns.charType, ConversionNames.TO_CHAR) { it.dispatchReceiver!! }
}
nameToTransformer.run {
@@ -210,12 +231,21 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
return IrCallImpl(
expression.startOffset,
expression.endOffset,
context.intrinsics.longConstructor.owner.returnType,
irBuiltIns.longType,
context.intrinsics.longConstructor
).apply {
putValueArgument(0, JsIrBuilder.buildInt(context.irBuiltIns.intType, low))
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, high))
}
} else if (expression.kind is IrConstKind.Char) {
return IrCallImpl(
expression.startOffset,
expression.endOffset,
irBuiltIns.charType,
context.intrinsics.charConstructor
).apply {
putValueArgument(0, JsIrBuilder.buildInt(context.irBuiltIns.intType, IrConstKind.Char.valueOf(expression).toInt()))
}
}
return super.visitConst(expression)
}
@@ -490,9 +520,9 @@ fun translateEqualsForNullableBoolean(rhs: IrType): EqualityLoweringType = when
}
private fun IrType.isNullableJsNumber(): Boolean = isNullablePrimitiveType() && !isNullableLong()
private fun IrType.isNullableJsNumber(): Boolean = isNullablePrimitiveType() && !isNullableLong() && !isNullableChar()
private fun IrType.isJsNumber(): Boolean = isPrimitiveType() && !isLong()
private fun IrType.isJsNumber(): Boolean = isPrimitiveType() && !isLong() && !isChar()
// TODO extract to common place?
@@ -45,7 +45,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private val isInterfaceSymbol = getInternalFunction("isInterface")
private val isArraySymbol = getInternalFunction("isArray")
private val isCharSymbol = getInternalFunction("isChar")
// private val isCharSymbol = getInternalFunction("isChar")
private val isObjectSymbol = getInternalFunction("isObject")
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol
@@ -199,7 +199,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
return when {
toType.isAny() -> generateIsObjectCheck(argument)
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
toType.isChar() -> generateCheckForChar(argument)
// toType.isChar() -> generateCheckForChar(argument)
toType.isArray() -> generateGenericArrayCheck(argument)
toType.isPrimitiveArray() -> generatePrimitiveArrayTypeCheck(argument, toType)
toType.isTypeParameter() -> generateTypeCheckWithTypeParameter(argument, toType)
@@ -224,8 +224,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
}
}
private fun generateCheckForChar(argument: IrExpression) =
JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
// private fun generateCheckForChar(argument: IrExpression) =
// JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
private fun generateTypeOfCheck(argument: IrExpression, toType: IrType): IrExpression {
val marker = when {
@@ -83,7 +83,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
is IrConstKind.Short -> JsIntLiteral(kind.valueOf(expression).toInt())
is IrConstKind.Int -> JsIntLiteral(kind.valueOf(expression))
is IrConstKind.Long -> throw IllegalStateException("Long const should have been lowered at this point")
is IrConstKind.Char -> TODO("Char const")
is IrConstKind.Char -> throw IllegalStateException("Char const should have been lowered at this point")
is IrConstKind.Float -> JsDoubleLiteral(kind.valueOf(expression).toDouble())
is IrConstKind.Double -> JsDoubleLiteral(kind.valueOf(expression))
}
@@ -62,3 +62,4 @@ fun IrType.isNumber(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.numb
fun IrType.isNullableBoolean(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._boolean)
fun IrType.isNullableLong(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._long)
fun IrType.isNullableChar(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES._char)
@@ -51,6 +51,7 @@ abstract class BasicIrBoxTest(
"libraries/stdlib/js/irRuntime/numberConversion.kt",
"libraries/stdlib/js/irRuntime/compareTo.kt",
"libraries/stdlib/js/irRuntime/annotations.kt",
"libraries/stdlib/js/irRuntime/char.kt",
"libraries/stdlib/js/irRuntime/DefaultConstructorMarker.kt",
"libraries/stdlib/js/irRuntime/exceptions.kt",
"libraries/stdlib/js/irRuntime/internalAnnotations.kt",
+95
View File
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin
/**
* Represents a 16-bit Unicode character.
* On the JVM, non-nullable values of this type are represented as values of the primitive type `char`.
*/
public class Char(value: Int) : Comparable<Char> {
private val value = value and 0xFFFF
/**
* Compares this value with the specified value for order.
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
* or a positive number if it's greater than other.
*/
public override fun compareTo(other: Char): Int = value - other.value
/** Adds the other Int value to this value resulting a Char. */
public operator fun plus(other: Int): Char = Char(value + other)
/** Subtracts the other Char value from this value resulting an Int. */
public operator fun minus(other: Char): Int = value - other.value
/** Subtracts the other Int value from this value resulting a Char. */
public operator fun minus(other: Int): Char = Char(value - other)
/** Increments this value. */
public operator fun inc(): Char = Char(value + 1)
/** Decrements this value. */
public operator fun dec(): Char = Char(value - 1)
/** Creates a range from this value to the specified [other] value. */
public operator fun rangeTo(other: Char): CharRange = null!! // TODO
/** Returns the value of this character as a `Byte`. */
public fun toByte(): Byte = value.toByte()
/** Returns the value of this character as a `Char`. */
public fun toChar(): Char = this
/** Returns the value of this character as a `Short`. */
public fun toShort(): Short = value.toShort()
/** Returns the value of this character as a `Int`. */
public fun toInt(): Int = value
/** Returns the value of this character as a `Long`. */
public fun toLong(): Long = value.toLong()
/** Returns the value of this character as a `Float`. */
public fun toFloat(): Float = value.toFloat()
/** Returns the value of this character as a `Double`. */
public fun toDouble(): Double = value.toDouble()
override fun equals(other: Any?): Boolean = other is Char && value == other.value
override fun hashCode(): Int = value
override fun toString(): String {
val value = value
return js("String.fromCharCode(value)").unsafeCast<String>()
}
companion object {
/**
* The minimum value of a Unicode high-surrogate code unit.
*/
public const val MIN_HIGH_SURROGATE: Char = '\uD800'
/**
* The maximum value of a Unicode high-surrogate code unit.
*/
public const val MAX_HIGH_SURROGATE: Char = '\uDBFF'
/**
* The minimum value of a Unicode low-surrogate code unit.
*/
public const val MIN_LOW_SURROGATE: Char = '\uDC00'
/**
* The maximum value of a Unicode low-surrogate code unit.
*/
public const val MAX_LOW_SURROGATE: Char = '\uDFFF'
/**
* The minimum value of a Unicode surrogate code unit.
*/
public const val MIN_SURROGATE: Char = MIN_HIGH_SURROGATE
/**
* The maximum value of a Unicode surrogate code unit.
*/
public const val MAX_SURROGATE: Char = MAX_LOW_SURROGATE
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ fun hashCode(obj: dynamic): Int {
var POW_2_32 = 4294967296;
// TODO: consider switching to Symbol type once we are on ES6.
/** @const */
var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue${'$'}";
var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue${"$"}";
function getObjectHashCode(obj) {
if (!(OBJECT_HASH_CODE_PROPERTY_NAME in obj)) {
@@ -14,7 +14,7 @@ private fun isInterfaceImpl(ctor: dynamic, iface: dynamic): Boolean {
val self = ::isInterfaceImpl
return js(
"""
var metadata = ctor.${'$'}metadata${'$'};
var metadata = ctor.${"$"}metadata${"$"};
if (metadata != null) {
var interfaces = metadata.interfaces;
for (var i = 0; i < interfaces.length; i++) {