[JS IR BE] hashCode, toString, number conversion support

This commit is contained in:
Svyatoslav Kuzmich
2018-06-13 15:54:34 +03:00
parent a7a695f203
commit 83f8cfaa66
73 changed files with 602 additions and 108 deletions
@@ -0,0 +1,43 @@
/*
* 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.js
// Adopted from misc.js
fun compareTo(a: dynamic, b: dynamic): Int {
var typeA = typeOf(a)
if (typeA == "number") {
if (typeOf(b) == "number") {
return doubleCompareTo(a, b)
}
return primitiveCompareTo(a, b)
}
if (typeA == "string" || typeA == "boolean") {
return primitiveCompareTo(a, b)
}
// TODO: Replace to a.unsafeCast<Comparable<*>>().compareTo(b) when bridge is implemented
return js("a.compareTo(b)").unsafeCast<Int>()
}
fun primitiveCompareTo(a: dynamic, b: dynamic): Int =
js("a < b ? -1 : a > b ? 1 : 0").unsafeCast<Int>()
fun doubleCompareTo(a: dynamic, b: dynamic): Int =
js("""
if (a < b) return -1;
if (a > b) return 1;
if (a === b) {
if (a !== 0) return 0;
var ia = 1 / a;
return ia === 1 / b ? 0 : (ia < 0 ? -1 : 1);
}
return a !== a ? (b !== b ? 0 : 1) : -1
""").unsafeCast<Int>()
+101
View File
@@ -0,0 +1,101 @@
/*
* 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.js
fun equals(obj1: dynamic, obj2: dynamic): Boolean {
if (obj1 == null) {
return obj2 == null
}
if (obj2 == null) {
return false
}
return js("""
if (typeof obj1 === "object" && typeof obj1.equals === "function") {
return obj1.equals(obj2);
}
if (obj1 !== obj1) {
return obj2 !== obj2;
}
if (typeof obj1 === "number" && typeof obj2 === "number") {
return obj1 === obj2 && (obj1 !== 0 || 1 / obj1 === 1 / obj2)
}
return obj1 === obj2;
""").unsafeCast<Boolean>()
}
fun toString(o: dynamic): String = when {
o == null -> "null"
isArrayish(o) -> "[...]"
else -> js("o.toString()").unsafeCast<String>()
}
// TODO: Simplify, extract kotlin declarations for inner helper functions
fun hashCode(obj: dynamic): Int {
return js(
"""
function hashCode(obj) {
if (obj == null) {
return 0;
}
var objType = typeof obj;
if ("object" === objType) {
return "function" === typeof obj.hashCode ? obj.hashCode() : getObjectHashCode(obj);
}
if ("function" === objType) {
return getObjectHashCode(obj);
}
if ("number" === objType) {
return getNumberHashCode(obj);
}
if ("boolean" === objType) {
return Number(obj)
}
var str = String(obj);
return getStringHashCode(str);
};
/** @const */
var POW_2_32 = 4294967296;
// TODO: consider switching to Symbol type once we are on ES6.
/** @const */
var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue${'$'}";
function getObjectHashCode(obj) {
if (!(OBJECT_HASH_CODE_PROPERTY_NAME in obj)) {
var hash = (Math.random() * POW_2_32) | 0; // Make 32-bit singed integer.
Object.defineProperty(obj, OBJECT_HASH_CODE_PROPERTY_NAME, { value: hash, enumerable: false });
}
return obj[OBJECT_HASH_CODE_PROPERTY_NAME];
}
function getStringHashCode(str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i);
hash = (hash * 31 + code) | 0; // Keep it 32-bit.
}
return hash;
}
function getNumberHashCode(obj) {
if ((obj | 0) === obj) {
return obj | 0;
}
else {
bufFloat64[0] = obj;
return (bufInt32[highIndex] * 31 | 0) + bufInt32[lowIndex] | 0;
}
}
return hashCode(obj);
"""
).unsafeCast<Int>()
}
@@ -0,0 +1,26 @@
/*
* 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.js
fun asIs(a: dynamic) = a
fun numberToByte(a: dynamic): Byte = toByte(numberToInt(a))
fun numberToDouble(a: dynamic): Double = js("+a").unsafeCast<Double>()
fun numberToInt(a: dynamic): Int = doubleToInt(a)
fun numberToShort(a: dynamic): Short = toShort(numberToInt(a))
// << and >> shifts are used to preserve sign of the number
fun toByte(a: dynamic): Byte = js("a << 24 >> 24").unsafeCast<Byte>()
fun toShort(a: dynamic): Short = js("a << 16 >> 16").unsafeCast<Short>()
fun doubleToInt(a: dynamic) = js("""
if (a > 2147483647) return 2147483647;
if (a < -2147483648) return -2147483648;
return a | 0;
""").unsafeCast<Int>()
@@ -75,7 +75,7 @@ public fun isInterface(ctor: dynamic, IType: dynamic): Boolean {
}
*/
inline private fun typeOf(obj: dynamic) = js("typeof obj").unsafeCast<String>()
fun typeOf(obj: dynamic) = js("typeof obj").unsafeCast<String>()
fun isObject(obj: dynamic): Boolean {
val objTypeOf = typeOf(obj)
@@ -93,6 +93,10 @@ public fun isArray(obj: Any): Boolean {
return js("Array.isArray(obj)").unsafeCast<Boolean>()
}
public fun isArrayish(o: dynamic) =
isArray(o) || js("ArrayBuffer.isView(o)").unsafeCast<Boolean>()
public fun isChar(c: Any): Boolean {
return js("throw Error(\"isChar is not implemented\")").unsafeCast<Boolean>()
}