From e6254b51e163af995fc4c0aed11063eb134431c0 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 11 Jan 2021 20:36:02 +0300 Subject: [PATCH] Rewrite generator for IrBuiltInsMapGenerated Similarly to 742fef90421 with OperationsMapGenerated, use optimized `when` over strings instead of lambdas because lambdas lead to a lot of bytecode. The change in `IrConst.toPrimitive` is needed because for operations like `Byte.plus(Int)` the IrConst instance would have the IR type for kotlin.Byte, but the actual runtime value of type Int (java.lang.Integer), which would lead to CCE from `interpretBinaryFunction`. Previously it didn't fail because of unchecked cast before calling the lambda, which allowed a value of runtime type java.lang.Integer to sneak through to the lambda parameter and be "unboxed" to the correct type via the `(... as Number).toByte()` conversion which backend generates. The main benefit of this change is that it reduces the size of the proguarded compiler jar by ~0.69%. --- .../kotlin/ir/interpreter/IrInterpreter.kt | 35 +- .../jetbrains/kotlin/ir/interpreter/Utils.kt | 7 +- .../interpreter/builtins/CompileTimeUtils.kt | 25 - .../builtins/IrBuiltInsMapGenerated.kt | 1073 ++++++++++------- .../interpreter/GenerateInterpreterMap.kt | 234 ++-- .../interpreter/GenerateInterpreterMapTest.kt | 2 +- 6 files changed, 800 insertions(+), 576 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index 5f338ff6186..e68eaa71ba9 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -189,29 +189,20 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map { - val function = unaryFunctions[signature] - ?: throw InterpreterMethodNotFoundError("For given function $signature there is no entry in unary map") - function.invoke(argsValues.first()) - } - 2 -> { - val function = binaryFunctions[signature] - ?: throw InterpreterMethodNotFoundError("For given function $signature there is no entry in binary map") - when (methodName) { - "rangeTo" -> return calculateRangeTo(irFunction.returnType) - else -> function.invoke(argsValues[0], argsValues[1]) - } - } - 3 -> { - val function = ternaryFunctions[signature] - ?: throw InterpreterMethodNotFoundError("For given function $signature there is no entry in ternary map") - function.invoke(argsValues[0], argsValues[1], argsValues[2]) + 1 -> interpretUnaryFunction(methodName, argsType[0].getOnlyName(), argsValues[0]) + 2 -> when (methodName) { + "rangeTo" -> return calculateRangeTo(irFunction.returnType) + else -> interpretBinaryFunction( + methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsValues[0], argsValues[1] + ) } + 3 -> interpretTernaryFunction( + methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(), + argsValues[0], argsValues[1], argsValues[2] + ) else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions") } } @@ -222,14 +213,14 @@ class IrInterpreter(val irBuiltIns: IrBuiltIns, private val bodyMap: Map } primitiveValueParameters.forEachIndexed { index, primitive -> - constructorCall.putValueArgument(index, primitive.value.toIrConst(primitive.type)) + constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type)) } - val constructorValueParameters = constructor.valueParameters.map { it.symbol }.zip(primitiveValueParameters) - return stack.newFrame(initPool = constructorValueParameters.map { Variable(it.first, it.second) }) { + return stack.newFrame(initPool = constructorValueParameters.zip(primitiveValueParameters).map { Variable(it.first, it.second) }) { constructorCall.interpret() } } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 9eba505f6fb..52b350fab98 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -104,8 +104,11 @@ fun Any?.toIrConst(irType: IrType, startOffset: Int = UNDEFINED_OFFSET, endOffse } } -internal fun IrConst.toPrimitive(): Primitive { - return Primitive(this.value, this.type) +@Suppress("UNCHECKED_CAST") +internal fun IrConst.toPrimitive(): Primitive = when { + type.isByte() -> Primitive((value as Number).toByte() as T, type) + type.isShort() -> Primitive((value as Number).toShort() as T, type) + else -> Primitive(value, type) } fun IrAnnotationContainer?.hasAnnotation(annotation: FqName): Boolean { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/CompileTimeUtils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/CompileTimeUtils.kt index f41099998bb..3d97e04a4ed 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/CompileTimeUtils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/CompileTimeUtils.kt @@ -10,28 +10,3 @@ import org.jetbrains.kotlin.name.FqName val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation") val evaluateIntrinsicAnnotation = FqName("kotlin.EvaluateIntrinsic") val contractsDslAnnotation = FqName("kotlin.internal.ContractsDsl") - -data class CompileTimeFunction(val methodName: String, val args: List) - -@Suppress("UNCHECKED_CAST") -fun unaryOperation( - methodName: String, receiverType: String, function: (T) -> Any? -): Pair> { - return CompileTimeFunction(methodName, listOf(receiverType)) to function as Function1 -} - -@Suppress("UNCHECKED_CAST") -fun binaryOperation( - methodName: String, receiverType: String, parameterType: String, function: (T, E) -> Any? -): Pair> { - return CompileTimeFunction(methodName, listOfNotNull(receiverType, parameterType)) to function as Function2 -} - -@Suppress("UNCHECKED_CAST") -fun ternaryOperation( - methodName: String, receiverType: String, firstParameterType: String, secondParameterType: String, function: (T, E, R) -> Any? -): Pair> { - return CompileTimeFunction( - methodName, listOfNotNull(receiverType, firstParameterType, secondParameterType) - ) to function as Function3 -} diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt index b15f31ad8bb..79c367818f3 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt @@ -14,456 +14,639 @@ * limitations under the License. */ +@file:Suppress("DEPRECATION", "DEPRECATION_ERROR", "UNCHECKED_CAST") + package org.jetbrains.kotlin.ir.interpreter.builtins +import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterMethodNotFoundError import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy -/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */ +/** This file is generated by `./gradlew generateInterpreterMap`. DO NOT MODIFY MANUALLY */ -@Suppress("DEPRECATION", "DEPRECATION_ERROR") -val unaryFunctions = mapOf>( - unaryOperation("hashCode", "Boolean") { a -> a.hashCode() }, - unaryOperation("not", "Boolean") { a -> a.not() }, - unaryOperation("toString", "Boolean") { a -> a.toString() }, - unaryOperation("dec", "Char") { a -> a.dec() }, - unaryOperation("hashCode", "Char") { a -> a.hashCode() }, - unaryOperation("inc", "Char") { a -> a.inc() }, - unaryOperation("toByte", "Char") { a -> a.toByte() }, - unaryOperation("toChar", "Char") { a -> a.toChar() }, - unaryOperation("toDouble", "Char") { a -> a.toDouble() }, - unaryOperation("toFloat", "Char") { a -> a.toFloat() }, - unaryOperation("toInt", "Char") { a -> a.toInt() }, - unaryOperation("toLong", "Char") { a -> a.toLong() }, - unaryOperation("toShort", "Char") { a -> a.toShort() }, - unaryOperation("toString", "Char") { a -> a.toString() }, - unaryOperation("dec", "Byte") { a -> a.dec() }, - unaryOperation("hashCode", "Byte") { a -> a.hashCode() }, - unaryOperation("inc", "Byte") { a -> a.inc() }, - unaryOperation("toByte", "Byte") { a -> a.toByte() }, - unaryOperation("toChar", "Byte") { a -> a.toChar() }, - unaryOperation("toDouble", "Byte") { a -> a.toDouble() }, - unaryOperation("toFloat", "Byte") { a -> a.toFloat() }, - unaryOperation("toInt", "Byte") { a -> a.toInt() }, - unaryOperation("toLong", "Byte") { a -> a.toLong() }, - unaryOperation("toShort", "Byte") { a -> a.toShort() }, - unaryOperation("toString", "Byte") { a -> a.toString() }, - unaryOperation("unaryMinus", "Byte") { a -> a.unaryMinus() }, - unaryOperation("unaryPlus", "Byte") { a -> a.unaryPlus() }, - unaryOperation("dec", "Short") { a -> a.dec() }, - unaryOperation("hashCode", "Short") { a -> a.hashCode() }, - unaryOperation("inc", "Short") { a -> a.inc() }, - unaryOperation("toByte", "Short") { a -> a.toByte() }, - unaryOperation("toChar", "Short") { a -> a.toChar() }, - unaryOperation("toDouble", "Short") { a -> a.toDouble() }, - unaryOperation("toFloat", "Short") { a -> a.toFloat() }, - unaryOperation("toInt", "Short") { a -> a.toInt() }, - unaryOperation("toLong", "Short") { a -> a.toLong() }, - unaryOperation("toShort", "Short") { a -> a.toShort() }, - unaryOperation("toString", "Short") { a -> a.toString() }, - unaryOperation("unaryMinus", "Short") { a -> a.unaryMinus() }, - unaryOperation("unaryPlus", "Short") { a -> a.unaryPlus() }, - unaryOperation("dec", "Int") { a -> a.dec() }, - unaryOperation("hashCode", "Int") { a -> a.hashCode() }, - unaryOperation("inc", "Int") { a -> a.inc() }, - unaryOperation("inv", "Int") { a -> a.inv() }, - unaryOperation("toByte", "Int") { a -> a.toByte() }, - unaryOperation("toChar", "Int") { a -> a.toChar() }, - unaryOperation("toDouble", "Int") { a -> a.toDouble() }, - unaryOperation("toFloat", "Int") { a -> a.toFloat() }, - unaryOperation("toInt", "Int") { a -> a.toInt() }, - unaryOperation("toLong", "Int") { a -> a.toLong() }, - unaryOperation("toShort", "Int") { a -> a.toShort() }, - unaryOperation("toString", "Int") { a -> a.toString() }, - unaryOperation("unaryMinus", "Int") { a -> a.unaryMinus() }, - unaryOperation("unaryPlus", "Int") { a -> a.unaryPlus() }, - unaryOperation("dec", "Float") { a -> a.dec() }, - unaryOperation("hashCode", "Float") { a -> a.hashCode() }, - unaryOperation("inc", "Float") { a -> a.inc() }, - unaryOperation("toByte", "Float") { a -> a.toByte() }, - unaryOperation("toChar", "Float") { a -> a.toChar() }, - unaryOperation("toDouble", "Float") { a -> a.toDouble() }, - unaryOperation("toFloat", "Float") { a -> a.toFloat() }, - unaryOperation("toInt", "Float") { a -> a.toInt() }, - unaryOperation("toLong", "Float") { a -> a.toLong() }, - unaryOperation("toShort", "Float") { a -> a.toShort() }, - unaryOperation("toString", "Float") { a -> a.toString() }, - unaryOperation("unaryMinus", "Float") { a -> a.unaryMinus() }, - unaryOperation("unaryPlus", "Float") { a -> a.unaryPlus() }, - unaryOperation("dec", "Long") { a -> a.dec() }, - unaryOperation("hashCode", "Long") { a -> a.hashCode() }, - unaryOperation("inc", "Long") { a -> a.inc() }, - unaryOperation("inv", "Long") { a -> a.inv() }, - unaryOperation("toByte", "Long") { a -> a.toByte() }, - unaryOperation("toChar", "Long") { a -> a.toChar() }, - unaryOperation("toDouble", "Long") { a -> a.toDouble() }, - unaryOperation("toFloat", "Long") { a -> a.toFloat() }, - unaryOperation("toInt", "Long") { a -> a.toInt() }, - unaryOperation("toLong", "Long") { a -> a.toLong() }, - unaryOperation("toShort", "Long") { a -> a.toShort() }, - unaryOperation("toString", "Long") { a -> a.toString() }, - unaryOperation("unaryMinus", "Long") { a -> a.unaryMinus() }, - unaryOperation("unaryPlus", "Long") { a -> a.unaryPlus() }, - unaryOperation("dec", "Double") { a -> a.dec() }, - unaryOperation("hashCode", "Double") { a -> a.hashCode() }, - unaryOperation("inc", "Double") { a -> a.inc() }, - unaryOperation("toByte", "Double") { a -> a.toByte() }, - unaryOperation("toChar", "Double") { a -> a.toChar() }, - unaryOperation("toDouble", "Double") { a -> a.toDouble() }, - unaryOperation("toFloat", "Double") { a -> a.toFloat() }, - unaryOperation("toInt", "Double") { a -> a.toInt() }, - unaryOperation("toLong", "Double") { a -> a.toLong() }, - unaryOperation("toShort", "Double") { a -> a.toShort() }, - unaryOperation("toString", "Double") { a -> a.toString() }, - unaryOperation("unaryMinus", "Double") { a -> a.unaryMinus() }, - unaryOperation("unaryPlus", "Double") { a -> a.unaryPlus() }, - unaryOperation("length", "String") { a -> a.length }, - unaryOperation("hashCode", "String") { a -> a.hashCode() }, - unaryOperation("toString", "String") { a -> a.toString() }, - unaryOperation("size", "BooleanArray") { a -> a.size }, - unaryOperation("iterator", "BooleanArray") { a -> a.iterator() }, - unaryOperation("size", "CharArray") { a -> a.size }, - unaryOperation("iterator", "CharArray") { a -> a.iterator() }, - unaryOperation("size", "ByteArray") { a -> a.size }, - unaryOperation("iterator", "ByteArray") { a -> a.iterator() }, - unaryOperation("size", "ShortArray") { a -> a.size }, - unaryOperation("iterator", "ShortArray") { a -> a.iterator() }, - unaryOperation("size", "IntArray") { a -> a.size }, - unaryOperation("iterator", "IntArray") { a -> a.iterator() }, - unaryOperation("size", "FloatArray") { a -> a.size }, - unaryOperation("iterator", "FloatArray") { a -> a.iterator() }, - unaryOperation("size", "LongArray") { a -> a.size }, - unaryOperation("iterator", "LongArray") { a -> a.iterator() }, - unaryOperation("size", "DoubleArray") { a -> a.size }, - unaryOperation("iterator", "DoubleArray") { a -> a.iterator() }, - unaryOperation>("size", "Array") { a -> a.size }, - unaryOperation>("iterator", "Array") { a -> a.iterator() }, - unaryOperation("hashCode", "Any") { a -> a.hashCode() }, - unaryOperation("toString", "Any") { a -> a.toString() }, - unaryOperation("CHECK_NOT_NULL", "T0?") { a -> a!! } -) +internal fun interpretUnaryFunction(name: String, type: String, a: Any?): Any? { + when (name) { + "hashCode" -> when (type) { + "Boolean" -> return (a as Boolean).hashCode() + "Char" -> return (a as Char).hashCode() + "Byte" -> return (a as Byte).hashCode() + "Short" -> return (a as Short).hashCode() + "Int" -> return (a as Int).hashCode() + "Float" -> return (a as Float).hashCode() + "Long" -> return (a as Long).hashCode() + "Double" -> return (a as Double).hashCode() + "String" -> return (a as String).hashCode() + "Any" -> return (a as Any).hashCode() + } + "not" -> when (type) { + "Boolean" -> return (a as Boolean).not() + } + "toString" -> when (type) { + "Boolean" -> return (a as Boolean).toString() + "Char" -> return (a as Char).toString() + "Byte" -> return (a as Byte).toString() + "Short" -> return (a as Short).toString() + "Int" -> return (a as Int).toString() + "Float" -> return (a as Float).toString() + "Long" -> return (a as Long).toString() + "Double" -> return (a as Double).toString() + "String" -> return (a as String).toString() + "Any" -> return (a as Any).toString() + } + "dec" -> when (type) { + "Char" -> return (a as Char).dec() + "Byte" -> return (a as Byte).dec() + "Short" -> return (a as Short).dec() + "Int" -> return (a as Int).dec() + "Float" -> return (a as Float).dec() + "Long" -> return (a as Long).dec() + "Double" -> return (a as Double).dec() + } + "inc" -> when (type) { + "Char" -> return (a as Char).inc() + "Byte" -> return (a as Byte).inc() + "Short" -> return (a as Short).inc() + "Int" -> return (a as Int).inc() + "Float" -> return (a as Float).inc() + "Long" -> return (a as Long).inc() + "Double" -> return (a as Double).inc() + } + "toByte" -> when (type) { + "Char" -> return (a as Char).toByte() + "Byte" -> return (a as Byte).toByte() + "Short" -> return (a as Short).toByte() + "Int" -> return (a as Int).toByte() + "Float" -> return (a as Float).toByte() + "Long" -> return (a as Long).toByte() + "Double" -> return (a as Double).toByte() + } + "toChar" -> when (type) { + "Char" -> return (a as Char).toChar() + "Byte" -> return (a as Byte).toChar() + "Short" -> return (a as Short).toChar() + "Int" -> return (a as Int).toChar() + "Float" -> return (a as Float).toChar() + "Long" -> return (a as Long).toChar() + "Double" -> return (a as Double).toChar() + } + "toDouble" -> when (type) { + "Char" -> return (a as Char).toDouble() + "Byte" -> return (a as Byte).toDouble() + "Short" -> return (a as Short).toDouble() + "Int" -> return (a as Int).toDouble() + "Float" -> return (a as Float).toDouble() + "Long" -> return (a as Long).toDouble() + "Double" -> return (a as Double).toDouble() + } + "toFloat" -> when (type) { + "Char" -> return (a as Char).toFloat() + "Byte" -> return (a as Byte).toFloat() + "Short" -> return (a as Short).toFloat() + "Int" -> return (a as Int).toFloat() + "Float" -> return (a as Float).toFloat() + "Long" -> return (a as Long).toFloat() + "Double" -> return (a as Double).toFloat() + } + "toInt" -> when (type) { + "Char" -> return (a as Char).toInt() + "Byte" -> return (a as Byte).toInt() + "Short" -> return (a as Short).toInt() + "Int" -> return (a as Int).toInt() + "Float" -> return (a as Float).toInt() + "Long" -> return (a as Long).toInt() + "Double" -> return (a as Double).toInt() + } + "toLong" -> when (type) { + "Char" -> return (a as Char).toLong() + "Byte" -> return (a as Byte).toLong() + "Short" -> return (a as Short).toLong() + "Int" -> return (a as Int).toLong() + "Float" -> return (a as Float).toLong() + "Long" -> return (a as Long).toLong() + "Double" -> return (a as Double).toLong() + } + "toShort" -> when (type) { + "Char" -> return (a as Char).toShort() + "Byte" -> return (a as Byte).toShort() + "Short" -> return (a as Short).toShort() + "Int" -> return (a as Int).toShort() + "Float" -> return (a as Float).toShort() + "Long" -> return (a as Long).toShort() + "Double" -> return (a as Double).toShort() + } + "unaryMinus" -> when (type) { + "Byte" -> return (a as Byte).unaryMinus() + "Short" -> return (a as Short).unaryMinus() + "Int" -> return (a as Int).unaryMinus() + "Float" -> return (a as Float).unaryMinus() + "Long" -> return (a as Long).unaryMinus() + "Double" -> return (a as Double).unaryMinus() + } + "unaryPlus" -> when (type) { + "Byte" -> return (a as Byte).unaryPlus() + "Short" -> return (a as Short).unaryPlus() + "Int" -> return (a as Int).unaryPlus() + "Float" -> return (a as Float).unaryPlus() + "Long" -> return (a as Long).unaryPlus() + "Double" -> return (a as Double).unaryPlus() + } + "inv" -> when (type) { + "Int" -> return (a as Int).inv() + "Long" -> return (a as Long).inv() + } + "length" -> when (type) { + "String" -> return (a as String).length + } + "size" -> when (type) { + "BooleanArray" -> return (a as BooleanArray).size + "CharArray" -> return (a as CharArray).size + "ByteArray" -> return (a as ByteArray).size + "ShortArray" -> return (a as ShortArray).size + "IntArray" -> return (a as IntArray).size + "FloatArray" -> return (a as FloatArray).size + "LongArray" -> return (a as LongArray).size + "DoubleArray" -> return (a as DoubleArray).size + "Array" -> return (a as Array).size + } + "iterator" -> when (type) { + "BooleanArray" -> return (a as BooleanArray).iterator() + "CharArray" -> return (a as CharArray).iterator() + "ByteArray" -> return (a as ByteArray).iterator() + "ShortArray" -> return (a as ShortArray).iterator() + "IntArray" -> return (a as IntArray).iterator() + "FloatArray" -> return (a as FloatArray).iterator() + "LongArray" -> return (a as LongArray).iterator() + "DoubleArray" -> return (a as DoubleArray).iterator() + "Array" -> return (a as Array).iterator() + } + "CHECK_NOT_NULL" -> when (type) { + "T0?" -> return a!! + } + } + throw InterpreterMethodNotFoundError("Unknown function: $name($type)") +} -val binaryFunctions = mapOf>( - binaryOperation("and", "Boolean", "Boolean") { a, b -> a.and(b) }, - binaryOperation("compareTo", "Boolean", "Boolean") { a, b -> a.compareTo(b) }, - binaryOperation("equals", "Boolean", "Any?") { a, b -> a.equals(b) }, - binaryOperation("or", "Boolean", "Boolean") { a, b -> a.or(b) }, - binaryOperation("xor", "Boolean", "Boolean") { a, b -> a.xor(b) }, - binaryOperation("compareTo", "Char", "Char") { a, b -> a.compareTo(b) }, - binaryOperation("equals", "Char", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Char", "Char") { a, b -> a.minus(b) }, - binaryOperation("minus", "Char", "Int") { a, b -> a.minus(b) }, - binaryOperation("plus", "Char", "Int") { a, b -> a.plus(b) }, - binaryOperation("rangeTo", "Char", "Char") { a, b -> a.rangeTo(b) }, - binaryOperation("compareTo", "Byte", "Byte") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Byte", "Double") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Byte", "Float") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Byte", "Int") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Byte", "Long") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Byte", "Short") { a, b -> a.compareTo(b) }, - binaryOperation("div", "Byte", "Byte") { a, b -> a.div(b) }, - binaryOperation("div", "Byte", "Double") { a, b -> a.div(b) }, - binaryOperation("div", "Byte", "Float") { a, b -> a.div(b) }, - binaryOperation("div", "Byte", "Int") { a, b -> a.div(b) }, - binaryOperation("div", "Byte", "Long") { a, b -> a.div(b) }, - binaryOperation("div", "Byte", "Short") { a, b -> a.div(b) }, - binaryOperation("equals", "Byte", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Byte", "Byte") { a, b -> a.minus(b) }, - binaryOperation("minus", "Byte", "Double") { a, b -> a.minus(b) }, - binaryOperation("minus", "Byte", "Float") { a, b -> a.minus(b) }, - binaryOperation("minus", "Byte", "Int") { a, b -> a.minus(b) }, - binaryOperation("minus", "Byte", "Long") { a, b -> a.minus(b) }, - binaryOperation("minus", "Byte", "Short") { a, b -> a.minus(b) }, - binaryOperation("plus", "Byte", "Byte") { a, b -> a.plus(b) }, - binaryOperation("plus", "Byte", "Double") { a, b -> a.plus(b) }, - binaryOperation("plus", "Byte", "Float") { a, b -> a.plus(b) }, - binaryOperation("plus", "Byte", "Int") { a, b -> a.plus(b) }, - binaryOperation("plus", "Byte", "Long") { a, b -> a.plus(b) }, - binaryOperation("plus", "Byte", "Short") { a, b -> a.plus(b) }, - binaryOperation("rangeTo", "Byte", "Byte") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Byte", "Int") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Byte", "Long") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Byte", "Short") { a, b -> a.rangeTo(b) }, - binaryOperation("rem", "Byte", "Byte") { a, b -> a.rem(b) }, - binaryOperation("rem", "Byte", "Double") { a, b -> a.rem(b) }, - binaryOperation("rem", "Byte", "Float") { a, b -> a.rem(b) }, - binaryOperation("rem", "Byte", "Int") { a, b -> a.rem(b) }, - binaryOperation("rem", "Byte", "Long") { a, b -> a.rem(b) }, - binaryOperation("rem", "Byte", "Short") { a, b -> a.rem(b) }, - binaryOperation("times", "Byte", "Byte") { a, b -> a.times(b) }, - binaryOperation("times", "Byte", "Double") { a, b -> a.times(b) }, - binaryOperation("times", "Byte", "Float") { a, b -> a.times(b) }, - binaryOperation("times", "Byte", "Int") { a, b -> a.times(b) }, - binaryOperation("times", "Byte", "Long") { a, b -> a.times(b) }, - binaryOperation("times", "Byte", "Short") { a, b -> a.times(b) }, - binaryOperation("compareTo", "Short", "Byte") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Short", "Double") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Short", "Float") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Short", "Int") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Short", "Long") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Short", "Short") { a, b -> a.compareTo(b) }, - binaryOperation("div", "Short", "Byte") { a, b -> a.div(b) }, - binaryOperation("div", "Short", "Double") { a, b -> a.div(b) }, - binaryOperation("div", "Short", "Float") { a, b -> a.div(b) }, - binaryOperation("div", "Short", "Int") { a, b -> a.div(b) }, - binaryOperation("div", "Short", "Long") { a, b -> a.div(b) }, - binaryOperation("div", "Short", "Short") { a, b -> a.div(b) }, - binaryOperation("equals", "Short", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Short", "Byte") { a, b -> a.minus(b) }, - binaryOperation("minus", "Short", "Double") { a, b -> a.minus(b) }, - binaryOperation("minus", "Short", "Float") { a, b -> a.minus(b) }, - binaryOperation("minus", "Short", "Int") { a, b -> a.minus(b) }, - binaryOperation("minus", "Short", "Long") { a, b -> a.minus(b) }, - binaryOperation("minus", "Short", "Short") { a, b -> a.minus(b) }, - binaryOperation("plus", "Short", "Byte") { a, b -> a.plus(b) }, - binaryOperation("plus", "Short", "Double") { a, b -> a.plus(b) }, - binaryOperation("plus", "Short", "Float") { a, b -> a.plus(b) }, - binaryOperation("plus", "Short", "Int") { a, b -> a.plus(b) }, - binaryOperation("plus", "Short", "Long") { a, b -> a.plus(b) }, - binaryOperation("plus", "Short", "Short") { a, b -> a.plus(b) }, - binaryOperation("rangeTo", "Short", "Byte") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Short", "Int") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Short", "Long") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Short", "Short") { a, b -> a.rangeTo(b) }, - binaryOperation("rem", "Short", "Byte") { a, b -> a.rem(b) }, - binaryOperation("rem", "Short", "Double") { a, b -> a.rem(b) }, - binaryOperation("rem", "Short", "Float") { a, b -> a.rem(b) }, - binaryOperation("rem", "Short", "Int") { a, b -> a.rem(b) }, - binaryOperation("rem", "Short", "Long") { a, b -> a.rem(b) }, - binaryOperation("rem", "Short", "Short") { a, b -> a.rem(b) }, - binaryOperation("times", "Short", "Byte") { a, b -> a.times(b) }, - binaryOperation("times", "Short", "Double") { a, b -> a.times(b) }, - binaryOperation("times", "Short", "Float") { a, b -> a.times(b) }, - binaryOperation("times", "Short", "Int") { a, b -> a.times(b) }, - binaryOperation("times", "Short", "Long") { a, b -> a.times(b) }, - binaryOperation("times", "Short", "Short") { a, b -> a.times(b) }, - binaryOperation("and", "Int", "Int") { a, b -> a.and(b) }, - binaryOperation("compareTo", "Int", "Byte") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Int", "Double") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Int", "Float") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Int", "Int") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Int", "Long") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Int", "Short") { a, b -> a.compareTo(b) }, - binaryOperation("div", "Int", "Byte") { a, b -> a.div(b) }, - binaryOperation("div", "Int", "Double") { a, b -> a.div(b) }, - binaryOperation("div", "Int", "Float") { a, b -> a.div(b) }, - binaryOperation("div", "Int", "Int") { a, b -> a.div(b) }, - binaryOperation("div", "Int", "Long") { a, b -> a.div(b) }, - binaryOperation("div", "Int", "Short") { a, b -> a.div(b) }, - binaryOperation("equals", "Int", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Int", "Byte") { a, b -> a.minus(b) }, - binaryOperation("minus", "Int", "Double") { a, b -> a.minus(b) }, - binaryOperation("minus", "Int", "Float") { a, b -> a.minus(b) }, - binaryOperation("minus", "Int", "Int") { a, b -> a.minus(b) }, - binaryOperation("minus", "Int", "Long") { a, b -> a.minus(b) }, - binaryOperation("minus", "Int", "Short") { a, b -> a.minus(b) }, - binaryOperation("or", "Int", "Int") { a, b -> a.or(b) }, - binaryOperation("plus", "Int", "Byte") { a, b -> a.plus(b) }, - binaryOperation("plus", "Int", "Double") { a, b -> a.plus(b) }, - binaryOperation("plus", "Int", "Float") { a, b -> a.plus(b) }, - binaryOperation("plus", "Int", "Int") { a, b -> a.plus(b) }, - binaryOperation("plus", "Int", "Long") { a, b -> a.plus(b) }, - binaryOperation("plus", "Int", "Short") { a, b -> a.plus(b) }, - binaryOperation("rangeTo", "Int", "Byte") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Int", "Int") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Int", "Long") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Int", "Short") { a, b -> a.rangeTo(b) }, - binaryOperation("rem", "Int", "Byte") { a, b -> a.rem(b) }, - binaryOperation("rem", "Int", "Double") { a, b -> a.rem(b) }, - binaryOperation("rem", "Int", "Float") { a, b -> a.rem(b) }, - binaryOperation("rem", "Int", "Int") { a, b -> a.rem(b) }, - binaryOperation("rem", "Int", "Long") { a, b -> a.rem(b) }, - binaryOperation("rem", "Int", "Short") { a, b -> a.rem(b) }, - binaryOperation("shl", "Int", "Int") { a, b -> a.shl(b) }, - binaryOperation("shr", "Int", "Int") { a, b -> a.shr(b) }, - binaryOperation("times", "Int", "Byte") { a, b -> a.times(b) }, - binaryOperation("times", "Int", "Double") { a, b -> a.times(b) }, - binaryOperation("times", "Int", "Float") { a, b -> a.times(b) }, - binaryOperation("times", "Int", "Int") { a, b -> a.times(b) }, - binaryOperation("times", "Int", "Long") { a, b -> a.times(b) }, - binaryOperation("times", "Int", "Short") { a, b -> a.times(b) }, - binaryOperation("ushr", "Int", "Int") { a, b -> a.ushr(b) }, - binaryOperation("xor", "Int", "Int") { a, b -> a.xor(b) }, - binaryOperation("compareTo", "Float", "Byte") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Float", "Double") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Float", "Float") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Float", "Int") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Float", "Long") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Float", "Short") { a, b -> a.compareTo(b) }, - binaryOperation("div", "Float", "Byte") { a, b -> a.div(b) }, - binaryOperation("div", "Float", "Double") { a, b -> a.div(b) }, - binaryOperation("div", "Float", "Float") { a, b -> a.div(b) }, - binaryOperation("div", "Float", "Int") { a, b -> a.div(b) }, - binaryOperation("div", "Float", "Long") { a, b -> a.div(b) }, - binaryOperation("div", "Float", "Short") { a, b -> a.div(b) }, - binaryOperation("equals", "Float", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Float", "Byte") { a, b -> a.minus(b) }, - binaryOperation("minus", "Float", "Double") { a, b -> a.minus(b) }, - binaryOperation("minus", "Float", "Float") { a, b -> a.minus(b) }, - binaryOperation("minus", "Float", "Int") { a, b -> a.minus(b) }, - binaryOperation("minus", "Float", "Long") { a, b -> a.minus(b) }, - binaryOperation("minus", "Float", "Short") { a, b -> a.minus(b) }, - binaryOperation("plus", "Float", "Byte") { a, b -> a.plus(b) }, - binaryOperation("plus", "Float", "Double") { a, b -> a.plus(b) }, - binaryOperation("plus", "Float", "Float") { a, b -> a.plus(b) }, - binaryOperation("plus", "Float", "Int") { a, b -> a.plus(b) }, - binaryOperation("plus", "Float", "Long") { a, b -> a.plus(b) }, - binaryOperation("plus", "Float", "Short") { a, b -> a.plus(b) }, - binaryOperation("rem", "Float", "Byte") { a, b -> a.rem(b) }, - binaryOperation("rem", "Float", "Double") { a, b -> a.rem(b) }, - binaryOperation("rem", "Float", "Float") { a, b -> a.rem(b) }, - binaryOperation("rem", "Float", "Int") { a, b -> a.rem(b) }, - binaryOperation("rem", "Float", "Long") { a, b -> a.rem(b) }, - binaryOperation("rem", "Float", "Short") { a, b -> a.rem(b) }, - binaryOperation("times", "Float", "Byte") { a, b -> a.times(b) }, - binaryOperation("times", "Float", "Double") { a, b -> a.times(b) }, - binaryOperation("times", "Float", "Float") { a, b -> a.times(b) }, - binaryOperation("times", "Float", "Int") { a, b -> a.times(b) }, - binaryOperation("times", "Float", "Long") { a, b -> a.times(b) }, - binaryOperation("times", "Float", "Short") { a, b -> a.times(b) }, - binaryOperation("and", "Long", "Long") { a, b -> a.and(b) }, - binaryOperation("compareTo", "Long", "Byte") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Long", "Double") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Long", "Float") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Long", "Int") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Long", "Long") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Long", "Short") { a, b -> a.compareTo(b) }, - binaryOperation("div", "Long", "Byte") { a, b -> a.div(b) }, - binaryOperation("div", "Long", "Double") { a, b -> a.div(b) }, - binaryOperation("div", "Long", "Float") { a, b -> a.div(b) }, - binaryOperation("div", "Long", "Int") { a, b -> a.div(b) }, - binaryOperation("div", "Long", "Long") { a, b -> a.div(b) }, - binaryOperation("div", "Long", "Short") { a, b -> a.div(b) }, - binaryOperation("equals", "Long", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Long", "Byte") { a, b -> a.minus(b) }, - binaryOperation("minus", "Long", "Double") { a, b -> a.minus(b) }, - binaryOperation("minus", "Long", "Float") { a, b -> a.minus(b) }, - binaryOperation("minus", "Long", "Int") { a, b -> a.minus(b) }, - binaryOperation("minus", "Long", "Long") { a, b -> a.minus(b) }, - binaryOperation("minus", "Long", "Short") { a, b -> a.minus(b) }, - binaryOperation("or", "Long", "Long") { a, b -> a.or(b) }, - binaryOperation("plus", "Long", "Byte") { a, b -> a.plus(b) }, - binaryOperation("plus", "Long", "Double") { a, b -> a.plus(b) }, - binaryOperation("plus", "Long", "Float") { a, b -> a.plus(b) }, - binaryOperation("plus", "Long", "Int") { a, b -> a.plus(b) }, - binaryOperation("plus", "Long", "Long") { a, b -> a.plus(b) }, - binaryOperation("plus", "Long", "Short") { a, b -> a.plus(b) }, - binaryOperation("rangeTo", "Long", "Byte") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Long", "Int") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Long", "Long") { a, b -> a.rangeTo(b) }, - binaryOperation("rangeTo", "Long", "Short") { a, b -> a.rangeTo(b) }, - binaryOperation("rem", "Long", "Byte") { a, b -> a.rem(b) }, - binaryOperation("rem", "Long", "Double") { a, b -> a.rem(b) }, - binaryOperation("rem", "Long", "Float") { a, b -> a.rem(b) }, - binaryOperation("rem", "Long", "Int") { a, b -> a.rem(b) }, - binaryOperation("rem", "Long", "Long") { a, b -> a.rem(b) }, - binaryOperation("rem", "Long", "Short") { a, b -> a.rem(b) }, - binaryOperation("shl", "Long", "Int") { a, b -> a.shl(b) }, - binaryOperation("shr", "Long", "Int") { a, b -> a.shr(b) }, - binaryOperation("times", "Long", "Byte") { a, b -> a.times(b) }, - binaryOperation("times", "Long", "Double") { a, b -> a.times(b) }, - binaryOperation("times", "Long", "Float") { a, b -> a.times(b) }, - binaryOperation("times", "Long", "Int") { a, b -> a.times(b) }, - binaryOperation("times", "Long", "Long") { a, b -> a.times(b) }, - binaryOperation("times", "Long", "Short") { a, b -> a.times(b) }, - binaryOperation("ushr", "Long", "Int") { a, b -> a.ushr(b) }, - binaryOperation("xor", "Long", "Long") { a, b -> a.xor(b) }, - binaryOperation("compareTo", "Double", "Byte") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Double", "Double") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Double", "Float") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Double", "Int") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Double", "Long") { a, b -> a.compareTo(b) }, - binaryOperation("compareTo", "Double", "Short") { a, b -> a.compareTo(b) }, - binaryOperation("div", "Double", "Byte") { a, b -> a.div(b) }, - binaryOperation("div", "Double", "Double") { a, b -> a.div(b) }, - binaryOperation("div", "Double", "Float") { a, b -> a.div(b) }, - binaryOperation("div", "Double", "Int") { a, b -> a.div(b) }, - binaryOperation("div", "Double", "Long") { a, b -> a.div(b) }, - binaryOperation("div", "Double", "Short") { a, b -> a.div(b) }, - binaryOperation("equals", "Double", "Any?") { a, b -> a.equals(b) }, - binaryOperation("minus", "Double", "Byte") { a, b -> a.minus(b) }, - binaryOperation("minus", "Double", "Double") { a, b -> a.minus(b) }, - binaryOperation("minus", "Double", "Float") { a, b -> a.minus(b) }, - binaryOperation("minus", "Double", "Int") { a, b -> a.minus(b) }, - binaryOperation("minus", "Double", "Long") { a, b -> a.minus(b) }, - binaryOperation("minus", "Double", "Short") { a, b -> a.minus(b) }, - binaryOperation("plus", "Double", "Byte") { a, b -> a.plus(b) }, - binaryOperation("plus", "Double", "Double") { a, b -> a.plus(b) }, - binaryOperation("plus", "Double", "Float") { a, b -> a.plus(b) }, - binaryOperation("plus", "Double", "Int") { a, b -> a.plus(b) }, - binaryOperation("plus", "Double", "Long") { a, b -> a.plus(b) }, - binaryOperation("plus", "Double", "Short") { a, b -> a.plus(b) }, - binaryOperation("rem", "Double", "Byte") { a, b -> a.rem(b) }, - binaryOperation("rem", "Double", "Double") { a, b -> a.rem(b) }, - binaryOperation("rem", "Double", "Float") { a, b -> a.rem(b) }, - binaryOperation("rem", "Double", "Int") { a, b -> a.rem(b) }, - binaryOperation("rem", "Double", "Long") { a, b -> a.rem(b) }, - binaryOperation("rem", "Double", "Short") { a, b -> a.rem(b) }, - binaryOperation("times", "Double", "Byte") { a, b -> a.times(b) }, - binaryOperation("times", "Double", "Double") { a, b -> a.times(b) }, - binaryOperation("times", "Double", "Float") { a, b -> a.times(b) }, - binaryOperation("times", "Double", "Int") { a, b -> a.times(b) }, - binaryOperation("times", "Double", "Long") { a, b -> a.times(b) }, - binaryOperation("times", "Double", "Short") { a, b -> a.times(b) }, - binaryOperation("compareTo", "String", "String") { a, b -> a.compareTo(b) }, - binaryOperation("equals", "String", "Any?") { a, b -> a.equals(b) }, - binaryOperation("get", "String", "Int") { a, b -> a.get(b) }, - binaryOperation("plus", "String", "Any?") { a, b -> a.plus(b) }, - binaryOperation("get", "BooleanArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "CharArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "ByteArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "ShortArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "IntArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "FloatArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "LongArray", "Int") { a, b -> a.get(b) }, - binaryOperation("get", "DoubleArray", "Int") { a, b -> a.get(b) }, - binaryOperation, Int>("get", "Array", "Int") { a, b -> a.get(b) }, - binaryOperation("equals", "Any", "Any?") { a, b -> a.equals(b) }, - binaryOperation("less", "Char", "Char") { a, b -> a < b }, - binaryOperation("less", "Byte", "Byte") { a, b -> a < b }, - binaryOperation("less", "Short", "Short") { a, b -> a < b }, - binaryOperation("less", "Int", "Int") { a, b -> a < b }, - binaryOperation("less", "Float", "Float") { a, b -> a < b }, - binaryOperation("less", "Long", "Long") { a, b -> a < b }, - binaryOperation("less", "Double", "Double") { a, b -> a < b }, - binaryOperation("lessOrEqual", "Char", "Char") { a, b -> a <= b }, - binaryOperation("lessOrEqual", "Byte", "Byte") { a, b -> a <= b }, - binaryOperation("lessOrEqual", "Short", "Short") { a, b -> a <= b }, - binaryOperation("lessOrEqual", "Int", "Int") { a, b -> a <= b }, - binaryOperation("lessOrEqual", "Float", "Float") { a, b -> a <= b }, - binaryOperation("lessOrEqual", "Long", "Long") { a, b -> a <= b }, - binaryOperation("lessOrEqual", "Double", "Double") { a, b -> a <= b }, - binaryOperation("greater", "Char", "Char") { a, b -> a > b }, - binaryOperation("greater", "Byte", "Byte") { a, b -> a > b }, - binaryOperation("greater", "Short", "Short") { a, b -> a > b }, - binaryOperation("greater", "Int", "Int") { a, b -> a > b }, - binaryOperation("greater", "Float", "Float") { a, b -> a > b }, - binaryOperation("greater", "Long", "Long") { a, b -> a > b }, - binaryOperation("greater", "Double", "Double") { a, b -> a > b }, - binaryOperation("greaterOrEqual", "Char", "Char") { a, b -> a >= b }, - binaryOperation("greaterOrEqual", "Byte", "Byte") { a, b -> a >= b }, - binaryOperation("greaterOrEqual", "Short", "Short") { a, b -> a >= b }, - binaryOperation("greaterOrEqual", "Int", "Int") { a, b -> a >= b }, - binaryOperation("greaterOrEqual", "Float", "Float") { a, b -> a >= b }, - binaryOperation("greaterOrEqual", "Long", "Long") { a, b -> a >= b }, - binaryOperation("greaterOrEqual", "Double", "Double") { a, b -> a >= b }, - binaryOperation("EQEQ", "Any?", "Any?") { a, b -> a == b }, - binaryOperation("EQEQEQ", "Any?", "Any?") { a, b -> if (a is Proxy && b is Proxy) a.state === b.state else a === b }, - binaryOperation("ieee754equals", "Float?", "Float?") { a, b -> a == b }, - binaryOperation("ieee754equals", "Double?", "Double?") { a, b -> a == b }, - binaryOperation("ANDAND", "Boolean", "Boolean") { a, b -> a && b }, - binaryOperation("OROR", "Boolean", "Boolean") { a, b -> a || b } -) +internal fun interpretBinaryFunction(name: String, typeA: String, typeB: String, a: Any?, b: Any?): Any? { + when (name) { + "and" -> when (typeA) { + "Boolean" -> if (typeB == "Boolean") return (a as Boolean).and(b as Boolean) + "Int" -> if (typeB == "Int") return (a as Int).and(b as Int) + "Long" -> if (typeB == "Long") return (a as Long).and(b as Long) + } + "compareTo" -> when (typeA) { + "Boolean" -> if (typeB == "Boolean") return (a as Boolean).compareTo(b as Boolean) + "Char" -> if (typeB == "Char") return (a as Char).compareTo(b as Char) + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).compareTo(b as Byte) + "Double" -> return (a as Byte).compareTo(b as Double) + "Float" -> return (a as Byte).compareTo(b as Float) + "Int" -> return (a as Byte).compareTo(b as Int) + "Long" -> return (a as Byte).compareTo(b as Long) + "Short" -> return (a as Byte).compareTo(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).compareTo(b as Byte) + "Double" -> return (a as Short).compareTo(b as Double) + "Float" -> return (a as Short).compareTo(b as Float) + "Int" -> return (a as Short).compareTo(b as Int) + "Long" -> return (a as Short).compareTo(b as Long) + "Short" -> return (a as Short).compareTo(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).compareTo(b as Byte) + "Double" -> return (a as Int).compareTo(b as Double) + "Float" -> return (a as Int).compareTo(b as Float) + "Int" -> return (a as Int).compareTo(b as Int) + "Long" -> return (a as Int).compareTo(b as Long) + "Short" -> return (a as Int).compareTo(b as Short) + } + "Float" -> when (typeB) { + "Byte" -> return (a as Float).compareTo(b as Byte) + "Double" -> return (a as Float).compareTo(b as Double) + "Float" -> return (a as Float).compareTo(b as Float) + "Int" -> return (a as Float).compareTo(b as Int) + "Long" -> return (a as Float).compareTo(b as Long) + "Short" -> return (a as Float).compareTo(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).compareTo(b as Byte) + "Double" -> return (a as Long).compareTo(b as Double) + "Float" -> return (a as Long).compareTo(b as Float) + "Int" -> return (a as Long).compareTo(b as Int) + "Long" -> return (a as Long).compareTo(b as Long) + "Short" -> return (a as Long).compareTo(b as Short) + } + "Double" -> when (typeB) { + "Byte" -> return (a as Double).compareTo(b as Byte) + "Double" -> return (a as Double).compareTo(b as Double) + "Float" -> return (a as Double).compareTo(b as Float) + "Int" -> return (a as Double).compareTo(b as Int) + "Long" -> return (a as Double).compareTo(b as Long) + "Short" -> return (a as Double).compareTo(b as Short) + } + "String" -> if (typeB == "String") return (a as String).compareTo(b as String) + } + "equals" -> when (typeA) { + "Boolean" -> if (typeB == "Any?") return (a as Boolean).equals(b) + "Char" -> if (typeB == "Any?") return (a as Char).equals(b) + "Byte" -> if (typeB == "Any?") return (a as Byte).equals(b) + "Short" -> if (typeB == "Any?") return (a as Short).equals(b) + "Int" -> if (typeB == "Any?") return (a as Int).equals(b) + "Float" -> if (typeB == "Any?") return (a as Float).equals(b) + "Long" -> if (typeB == "Any?") return (a as Long).equals(b) + "Double" -> if (typeB == "Any?") return (a as Double).equals(b) + "String" -> if (typeB == "Any?") return (a as String).equals(b) + "Any" -> if (typeB == "Any?") return (a as Any).equals(b) + } + "or" -> when (typeA) { + "Boolean" -> if (typeB == "Boolean") return (a as Boolean).or(b as Boolean) + "Int" -> if (typeB == "Int") return (a as Int).or(b as Int) + "Long" -> if (typeB == "Long") return (a as Long).or(b as Long) + } + "xor" -> when (typeA) { + "Boolean" -> if (typeB == "Boolean") return (a as Boolean).xor(b as Boolean) + "Int" -> if (typeB == "Int") return (a as Int).xor(b as Int) + "Long" -> if (typeB == "Long") return (a as Long).xor(b as Long) + } + "minus" -> when (typeA) { + "Char" -> when (typeB) { + "Char" -> return (a as Char).minus(b as Char) + "Int" -> return (a as Char).minus(b as Int) + } + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).minus(b as Byte) + "Double" -> return (a as Byte).minus(b as Double) + "Float" -> return (a as Byte).minus(b as Float) + "Int" -> return (a as Byte).minus(b as Int) + "Long" -> return (a as Byte).minus(b as Long) + "Short" -> return (a as Byte).minus(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).minus(b as Byte) + "Double" -> return (a as Short).minus(b as Double) + "Float" -> return (a as Short).minus(b as Float) + "Int" -> return (a as Short).minus(b as Int) + "Long" -> return (a as Short).minus(b as Long) + "Short" -> return (a as Short).minus(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).minus(b as Byte) + "Double" -> return (a as Int).minus(b as Double) + "Float" -> return (a as Int).minus(b as Float) + "Int" -> return (a as Int).minus(b as Int) + "Long" -> return (a as Int).minus(b as Long) + "Short" -> return (a as Int).minus(b as Short) + } + "Float" -> when (typeB) { + "Byte" -> return (a as Float).minus(b as Byte) + "Double" -> return (a as Float).minus(b as Double) + "Float" -> return (a as Float).minus(b as Float) + "Int" -> return (a as Float).minus(b as Int) + "Long" -> return (a as Float).minus(b as Long) + "Short" -> return (a as Float).minus(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).minus(b as Byte) + "Double" -> return (a as Long).minus(b as Double) + "Float" -> return (a as Long).minus(b as Float) + "Int" -> return (a as Long).minus(b as Int) + "Long" -> return (a as Long).minus(b as Long) + "Short" -> return (a as Long).minus(b as Short) + } + "Double" -> when (typeB) { + "Byte" -> return (a as Double).minus(b as Byte) + "Double" -> return (a as Double).minus(b as Double) + "Float" -> return (a as Double).minus(b as Float) + "Int" -> return (a as Double).minus(b as Int) + "Long" -> return (a as Double).minus(b as Long) + "Short" -> return (a as Double).minus(b as Short) + } + } + "plus" -> when (typeA) { + "Char" -> if (typeB == "Int") return (a as Char).plus(b as Int) + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).plus(b as Byte) + "Double" -> return (a as Byte).plus(b as Double) + "Float" -> return (a as Byte).plus(b as Float) + "Int" -> return (a as Byte).plus(b as Int) + "Long" -> return (a as Byte).plus(b as Long) + "Short" -> return (a as Byte).plus(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).plus(b as Byte) + "Double" -> return (a as Short).plus(b as Double) + "Float" -> return (a as Short).plus(b as Float) + "Int" -> return (a as Short).plus(b as Int) + "Long" -> return (a as Short).plus(b as Long) + "Short" -> return (a as Short).plus(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).plus(b as Byte) + "Double" -> return (a as Int).plus(b as Double) + "Float" -> return (a as Int).plus(b as Float) + "Int" -> return (a as Int).plus(b as Int) + "Long" -> return (a as Int).plus(b as Long) + "Short" -> return (a as Int).plus(b as Short) + } + "Float" -> when (typeB) { + "Byte" -> return (a as Float).plus(b as Byte) + "Double" -> return (a as Float).plus(b as Double) + "Float" -> return (a as Float).plus(b as Float) + "Int" -> return (a as Float).plus(b as Int) + "Long" -> return (a as Float).plus(b as Long) + "Short" -> return (a as Float).plus(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).plus(b as Byte) + "Double" -> return (a as Long).plus(b as Double) + "Float" -> return (a as Long).plus(b as Float) + "Int" -> return (a as Long).plus(b as Int) + "Long" -> return (a as Long).plus(b as Long) + "Short" -> return (a as Long).plus(b as Short) + } + "Double" -> when (typeB) { + "Byte" -> return (a as Double).plus(b as Byte) + "Double" -> return (a as Double).plus(b as Double) + "Float" -> return (a as Double).plus(b as Float) + "Int" -> return (a as Double).plus(b as Int) + "Long" -> return (a as Double).plus(b as Long) + "Short" -> return (a as Double).plus(b as Short) + } + "String" -> if (typeB == "Any?") return (a as String).plus(b) + } + "rangeTo" -> when (typeA) { + "Char" -> if (typeB == "Char") return (a as Char).rangeTo(b as Char) + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).rangeTo(b as Byte) + "Int" -> return (a as Byte).rangeTo(b as Int) + "Long" -> return (a as Byte).rangeTo(b as Long) + "Short" -> return (a as Byte).rangeTo(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).rangeTo(b as Byte) + "Int" -> return (a as Short).rangeTo(b as Int) + "Long" -> return (a as Short).rangeTo(b as Long) + "Short" -> return (a as Short).rangeTo(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).rangeTo(b as Byte) + "Int" -> return (a as Int).rangeTo(b as Int) + "Long" -> return (a as Int).rangeTo(b as Long) + "Short" -> return (a as Int).rangeTo(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).rangeTo(b as Byte) + "Int" -> return (a as Long).rangeTo(b as Int) + "Long" -> return (a as Long).rangeTo(b as Long) + "Short" -> return (a as Long).rangeTo(b as Short) + } + } + "div" -> when (typeA) { + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).div(b as Byte) + "Double" -> return (a as Byte).div(b as Double) + "Float" -> return (a as Byte).div(b as Float) + "Int" -> return (a as Byte).div(b as Int) + "Long" -> return (a as Byte).div(b as Long) + "Short" -> return (a as Byte).div(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).div(b as Byte) + "Double" -> return (a as Short).div(b as Double) + "Float" -> return (a as Short).div(b as Float) + "Int" -> return (a as Short).div(b as Int) + "Long" -> return (a as Short).div(b as Long) + "Short" -> return (a as Short).div(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).div(b as Byte) + "Double" -> return (a as Int).div(b as Double) + "Float" -> return (a as Int).div(b as Float) + "Int" -> return (a as Int).div(b as Int) + "Long" -> return (a as Int).div(b as Long) + "Short" -> return (a as Int).div(b as Short) + } + "Float" -> when (typeB) { + "Byte" -> return (a as Float).div(b as Byte) + "Double" -> return (a as Float).div(b as Double) + "Float" -> return (a as Float).div(b as Float) + "Int" -> return (a as Float).div(b as Int) + "Long" -> return (a as Float).div(b as Long) + "Short" -> return (a as Float).div(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).div(b as Byte) + "Double" -> return (a as Long).div(b as Double) + "Float" -> return (a as Long).div(b as Float) + "Int" -> return (a as Long).div(b as Int) + "Long" -> return (a as Long).div(b as Long) + "Short" -> return (a as Long).div(b as Short) + } + "Double" -> when (typeB) { + "Byte" -> return (a as Double).div(b as Byte) + "Double" -> return (a as Double).div(b as Double) + "Float" -> return (a as Double).div(b as Float) + "Int" -> return (a as Double).div(b as Int) + "Long" -> return (a as Double).div(b as Long) + "Short" -> return (a as Double).div(b as Short) + } + } + "rem" -> when (typeA) { + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).rem(b as Byte) + "Double" -> return (a as Byte).rem(b as Double) + "Float" -> return (a as Byte).rem(b as Float) + "Int" -> return (a as Byte).rem(b as Int) + "Long" -> return (a as Byte).rem(b as Long) + "Short" -> return (a as Byte).rem(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).rem(b as Byte) + "Double" -> return (a as Short).rem(b as Double) + "Float" -> return (a as Short).rem(b as Float) + "Int" -> return (a as Short).rem(b as Int) + "Long" -> return (a as Short).rem(b as Long) + "Short" -> return (a as Short).rem(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).rem(b as Byte) + "Double" -> return (a as Int).rem(b as Double) + "Float" -> return (a as Int).rem(b as Float) + "Int" -> return (a as Int).rem(b as Int) + "Long" -> return (a as Int).rem(b as Long) + "Short" -> return (a as Int).rem(b as Short) + } + "Float" -> when (typeB) { + "Byte" -> return (a as Float).rem(b as Byte) + "Double" -> return (a as Float).rem(b as Double) + "Float" -> return (a as Float).rem(b as Float) + "Int" -> return (a as Float).rem(b as Int) + "Long" -> return (a as Float).rem(b as Long) + "Short" -> return (a as Float).rem(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).rem(b as Byte) + "Double" -> return (a as Long).rem(b as Double) + "Float" -> return (a as Long).rem(b as Float) + "Int" -> return (a as Long).rem(b as Int) + "Long" -> return (a as Long).rem(b as Long) + "Short" -> return (a as Long).rem(b as Short) + } + "Double" -> when (typeB) { + "Byte" -> return (a as Double).rem(b as Byte) + "Double" -> return (a as Double).rem(b as Double) + "Float" -> return (a as Double).rem(b as Float) + "Int" -> return (a as Double).rem(b as Int) + "Long" -> return (a as Double).rem(b as Long) + "Short" -> return (a as Double).rem(b as Short) + } + } + "times" -> when (typeA) { + "Byte" -> when (typeB) { + "Byte" -> return (a as Byte).times(b as Byte) + "Double" -> return (a as Byte).times(b as Double) + "Float" -> return (a as Byte).times(b as Float) + "Int" -> return (a as Byte).times(b as Int) + "Long" -> return (a as Byte).times(b as Long) + "Short" -> return (a as Byte).times(b as Short) + } + "Short" -> when (typeB) { + "Byte" -> return (a as Short).times(b as Byte) + "Double" -> return (a as Short).times(b as Double) + "Float" -> return (a as Short).times(b as Float) + "Int" -> return (a as Short).times(b as Int) + "Long" -> return (a as Short).times(b as Long) + "Short" -> return (a as Short).times(b as Short) + } + "Int" -> when (typeB) { + "Byte" -> return (a as Int).times(b as Byte) + "Double" -> return (a as Int).times(b as Double) + "Float" -> return (a as Int).times(b as Float) + "Int" -> return (a as Int).times(b as Int) + "Long" -> return (a as Int).times(b as Long) + "Short" -> return (a as Int).times(b as Short) + } + "Float" -> when (typeB) { + "Byte" -> return (a as Float).times(b as Byte) + "Double" -> return (a as Float).times(b as Double) + "Float" -> return (a as Float).times(b as Float) + "Int" -> return (a as Float).times(b as Int) + "Long" -> return (a as Float).times(b as Long) + "Short" -> return (a as Float).times(b as Short) + } + "Long" -> when (typeB) { + "Byte" -> return (a as Long).times(b as Byte) + "Double" -> return (a as Long).times(b as Double) + "Float" -> return (a as Long).times(b as Float) + "Int" -> return (a as Long).times(b as Int) + "Long" -> return (a as Long).times(b as Long) + "Short" -> return (a as Long).times(b as Short) + } + "Double" -> when (typeB) { + "Byte" -> return (a as Double).times(b as Byte) + "Double" -> return (a as Double).times(b as Double) + "Float" -> return (a as Double).times(b as Float) + "Int" -> return (a as Double).times(b as Int) + "Long" -> return (a as Double).times(b as Long) + "Short" -> return (a as Double).times(b as Short) + } + } + "shl" -> when (typeA) { + "Int" -> if (typeB == "Int") return (a as Int).shl(b as Int) + "Long" -> if (typeB == "Int") return (a as Long).shl(b as Int) + } + "shr" -> when (typeA) { + "Int" -> if (typeB == "Int") return (a as Int).shr(b as Int) + "Long" -> if (typeB == "Int") return (a as Long).shr(b as Int) + } + "ushr" -> when (typeA) { + "Int" -> if (typeB == "Int") return (a as Int).ushr(b as Int) + "Long" -> if (typeB == "Int") return (a as Long).ushr(b as Int) + } + "get" -> when (typeA) { + "String" -> if (typeB == "Int") return (a as String).get(b as Int) + "BooleanArray" -> if (typeB == "Int") return (a as BooleanArray).get(b as Int) + "CharArray" -> if (typeB == "Int") return (a as CharArray).get(b as Int) + "ByteArray" -> if (typeB == "Int") return (a as ByteArray).get(b as Int) + "ShortArray" -> if (typeB == "Int") return (a as ShortArray).get(b as Int) + "IntArray" -> if (typeB == "Int") return (a as IntArray).get(b as Int) + "FloatArray" -> if (typeB == "Int") return (a as FloatArray).get(b as Int) + "LongArray" -> if (typeB == "Int") return (a as LongArray).get(b as Int) + "DoubleArray" -> if (typeB == "Int") return (a as DoubleArray).get(b as Int) + "Array" -> if (typeB == "Int") return (a as Array).get(b as Int) + } + "less" -> when (typeA) { + "Char" -> if (typeB == "Char") return (a as Char) < (b as Char) + "Byte" -> if (typeB == "Byte") return (a as Byte) < (b as Byte) + "Short" -> if (typeB == "Short") return (a as Short) < (b as Short) + "Int" -> if (typeB == "Int") return (a as Int) < (b as Int) + "Float" -> if (typeB == "Float") return (a as Float) < (b as Float) + "Long" -> if (typeB == "Long") return (a as Long) < (b as Long) + "Double" -> if (typeB == "Double") return (a as Double) < (b as Double) + } + "lessOrEqual" -> when (typeA) { + "Char" -> if (typeB == "Char") return (a as Char) <= (b as Char) + "Byte" -> if (typeB == "Byte") return (a as Byte) <= (b as Byte) + "Short" -> if (typeB == "Short") return (a as Short) <= (b as Short) + "Int" -> if (typeB == "Int") return (a as Int) <= (b as Int) + "Float" -> if (typeB == "Float") return (a as Float) <= (b as Float) + "Long" -> if (typeB == "Long") return (a as Long) <= (b as Long) + "Double" -> if (typeB == "Double") return (a as Double) <= (b as Double) + } + "greater" -> when (typeA) { + "Char" -> if (typeB == "Char") return (a as Char) > (b as Char) + "Byte" -> if (typeB == "Byte") return (a as Byte) > (b as Byte) + "Short" -> if (typeB == "Short") return (a as Short) > (b as Short) + "Int" -> if (typeB == "Int") return (a as Int) > (b as Int) + "Float" -> if (typeB == "Float") return (a as Float) > (b as Float) + "Long" -> if (typeB == "Long") return (a as Long) > (b as Long) + "Double" -> if (typeB == "Double") return (a as Double) > (b as Double) + } + "greaterOrEqual" -> when (typeA) { + "Char" -> if (typeB == "Char") return (a as Char) >= (b as Char) + "Byte" -> if (typeB == "Byte") return (a as Byte) >= (b as Byte) + "Short" -> if (typeB == "Short") return (a as Short) >= (b as Short) + "Int" -> if (typeB == "Int") return (a as Int) >= (b as Int) + "Float" -> if (typeB == "Float") return (a as Float) >= (b as Float) + "Long" -> if (typeB == "Long") return (a as Long) >= (b as Long) + "Double" -> if (typeB == "Double") return (a as Double) >= (b as Double) + } + "EQEQ" -> when (typeA) { + "Any?" -> if (typeB == "Any?") return a == b + } + "EQEQEQ" -> when (typeA) { + "Any?" -> if (typeB == "Any?") return if (a is Proxy && b is Proxy) a.state === b.state else a === b + } + "ieee754equals" -> when (typeA) { + "Float?" -> if (typeB == "Float?") return (a as Float?) == (b as Float?) + "Double?" -> if (typeB == "Double?") return (a as Double?) == (b as Double?) + } + "ANDAND" -> when (typeA) { + "Boolean" -> if (typeB == "Boolean") return (a as Boolean) && (b as Boolean) + } + "OROR" -> when (typeA) { + "Boolean" -> if (typeB == "Boolean") return (a as Boolean) || (b as Boolean) + } + } + throw InterpreterMethodNotFoundError("Unknown function: $name($typeA, $typeB)") +} -val ternaryFunctions = mapOf>( - ternaryOperation("subSequence", "String", "Int", "Int") { a, b, c -> a.subSequence(b, c) }, - ternaryOperation("set", "BooleanArray", "Int", "Boolean") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "CharArray", "Int", "Char") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "ByteArray", "Int", "Byte") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "ShortArray", "Int", "Short") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "IntArray", "Int", "Int") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "FloatArray", "Int", "Float") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "LongArray", "Int", "Long") { a, b, c -> a.set(b, c) }, - ternaryOperation("set", "DoubleArray", "Int", "Double") { a, b, c -> a.set(b, c) }, - ternaryOperation, Int, Any?>("set", "Array", "Int", "T") { a, b, c -> a.set(b, c) } -) +internal fun interpretTernaryFunction(name: String, typeA: String, typeB: String, typeC: String, a: Any?, b: Any?, c: Any?): Any { + when (name) { + "subSequence" -> when (typeA) { + "String" -> if (typeB == "Int" && typeC == "Int") return (a as String).subSequence(b as Int, c as Int) + } + "set" -> when (typeA) { + "BooleanArray" -> if (typeB == "Int" && typeC == "Boolean") return (a as BooleanArray).set(b as Int, c as Boolean) + "CharArray" -> if (typeB == "Int" && typeC == "Char") return (a as CharArray).set(b as Int, c as Char) + "ByteArray" -> if (typeB == "Int" && typeC == "Byte") return (a as ByteArray).set(b as Int, c as Byte) + "ShortArray" -> if (typeB == "Int" && typeC == "Short") return (a as ShortArray).set(b as Int, c as Short) + "IntArray" -> if (typeB == "Int" && typeC == "Int") return (a as IntArray).set(b as Int, c as Int) + "FloatArray" -> if (typeB == "Int" && typeC == "Float") return (a as FloatArray).set(b as Int, c as Float) + "LongArray" -> if (typeB == "Int" && typeC == "Long") return (a as LongArray).set(b as Int, c as Long) + "DoubleArray" -> if (typeB == "Int" && typeC == "Double") return (a as DoubleArray).set(b as Int, c as Double) + "Array" -> if (typeB == "Int" && typeC == "T") return (a as Array).set(b as Int, c) + } + } + throw InterpreterMethodNotFoundError("Unknown function: $name($typeA, $typeB, $typeC)") +} diff --git a/generators/interpreter/GenerateInterpreterMap.kt b/generators/interpreter/GenerateInterpreterMap.kt index 4872b907cd7..a66d0ded3d3 100644 --- a/generators/interpreter/GenerateInterpreterMap.kt +++ b/generators/interpreter/GenerateInterpreterMap.kt @@ -14,13 +14,10 @@ import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil -import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.types.impl.originalKotlinType -import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.ir.util.IdSignatureComposer -import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl import org.jetbrains.kotlin.storage.LockBasedStorageManager @@ -37,81 +34,184 @@ fun generateMap(): String { val sb = StringBuilder() val p = Printer(sb) p.println(File("license/COPYRIGHT.txt").readText()) + p.println("@file:Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\", \"UNCHECKED_CAST\")") + p.println() p.println("package org.jetbrains.kotlin.ir.interpreter.builtins") p.println() + p.println("import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterMethodNotFoundError") p.println("import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy") p.println() - p.println("/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */") + p.println("/** This file is generated by `./gradlew generateInterpreterMap`. DO NOT MODIFY MANUALLY */") p.println() val irBuiltIns = getIrBuiltIns() - val unaryOperationsMap = getOperationMap(1) - val binaryOperationsMap = getOperationMap(2) - val ternaryOperationsMap = getOperationMap(3) - val binaryIrOperationsMap = getBinaryIrOperationMap(irBuiltIns) + generateInterpretUnaryFunction(p, getOperationMap(1).apply { + val irNullCheck = irBuiltIns.checkNotNullSymbol.owner + this += Operation(irNullCheck.name.asString(), listOf("T0?"), customExpression = "a!!") + }) - p.println("@Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\")") - p.println("val unaryFunctions = mapOf>(") - p.println(generateUnaryBody(unaryOperationsMap, irBuiltIns)) - p.println(")") - p.println() + generateInterpretBinaryFunction(p, getOperationMap(2) + getBinaryIrOperationMap(irBuiltIns)) - p.println("val binaryFunctions = mapOf>(") - p.println(generateBinaryBody(binaryOperationsMap, binaryIrOperationsMap)) - p.println(")") - p.println() - - p.println("val ternaryFunctions = mapOf>(") - p.println(generateTernaryBody(ternaryOperationsMap)) - p.println(")") - p.println() + generateInterpretTernaryFunction(p, getOperationMap(3)) return sb.toString() } -private fun getOperationMap(argumentsCount: Int): MutableMap> { +private fun generateInterpretUnaryFunction(p: Printer, unaryOperations: List) { + p.println("internal fun interpretUnaryFunction(name: String, type: String, a: Any?): Any? {") + p.pushIndent() + p.println("when (name) {") + p.pushIndent() + for ((name, operations) in unaryOperations.groupBy(Operation::name)) { + p.println("\"$name\" -> when (type) {") + p.pushIndent() + for (operation in operations) { + p.println("\"${operation.typeA}\" -> return ${operation.expressionString}") + } + p.popIndent() + p.println("}") + } + p.popIndent() + p.println("}") + p.println("throw InterpreterMethodNotFoundError(\"Unknown function: \$name(\$type)\")") + p.popIndent() + p.println("}") + p.println() +} + +private fun generateInterpretBinaryFunction(p: Printer, binaryOperations: List) { + p.println("internal fun interpretBinaryFunction(name: String, typeA: String, typeB: String, a: Any?, b: Any?): Any? {") + p.pushIndent() + p.println("when (name) {") + p.pushIndent() + for ((name, operations) in binaryOperations.groupBy(Operation::name)) { + p.println("\"$name\" -> when (typeA) {") + p.pushIndent() + for ((typeA, operationsOnTypeA) in operations.groupBy(Operation::typeA)) { + val singleOperation = operationsOnTypeA.singleOrNull() + if (singleOperation != null) { + // Slightly improve readability if there's only one operation with such name and typeA. + p.println("\"$typeA\" -> if (typeB == \"${singleOperation.typeB}\") return ${singleOperation.expressionString}") + } else { + p.println("\"$typeA\" -> when (typeB) {") + p.pushIndent() + for ((typeB, operationsOnTypeB) in operationsOnTypeA.groupBy(Operation::typeB)) { + for (operation in operationsOnTypeB) { + p.println("\"$typeB\" -> return ${operation.expressionString}") + } + } + p.popIndent() + p.println("}") + } + } + p.popIndent() + p.println("}") + } + p.popIndent() + p.println("}") + p.println("throw InterpreterMethodNotFoundError(\"Unknown function: \$name(\$typeA, \$typeB)\")") + p.popIndent() + p.println("}") + p.println() +} + +private fun generateInterpretTernaryFunction(p: Printer, ternaryOperations: List) { + p.println("internal fun interpretTernaryFunction(name: String, typeA: String, typeB: String, typeC: String, a: Any?, b: Any?, c: Any?): Any {") + p.pushIndent() + p.println("when (name) {") + p.pushIndent() + for ((name, operations) in ternaryOperations.groupBy(Operation::name)) { + p.println("\"$name\" -> when (typeA) {") + p.pushIndent() + for (operation in operations) { + val (typeA, typeB, typeC) = operation.parameterTypes + p.println("\"$typeA\" -> if (typeB == \"$typeB\" && typeC == \"$typeC\") return ${operation.expressionString}") + } + p.popIndent() + p.println("}") + } + p.popIndent() + p.println("}") + p.println("throw InterpreterMethodNotFoundError(\"Unknown function: \$name(\$typeA, \$typeB, \$typeC)\")") + p.popIndent() + p.println("}") + p.println() +} + +private fun castValue(name: String, type: String): String = when (type) { + "Any?", "T" -> name + "Array" -> "$name as Array" + else -> "$name as $type" +} + +private fun castValueParenthesized(name: String, type: String): String = + if (type == "Any?") name else "(${castValue(name, type)})" + +private data class Operation( + val name: String, + val parameterTypes: List, + val isFunction: Boolean = true, + val customExpression: String? = null, +) { + val typeA: String get() = parameterTypes[0] + val typeB: String get() = parameterTypes[1] + + val expressionString: String + get() { + val receiver = castValueParenthesized("a", typeA) + println(name) + return when { + name == IrBuiltIns.OperatorNames.EQEQEQ && parameterTypes.all { it == "Any?" } -> + "if (a is Proxy && b is Proxy) a.state === b.state else a === b" + customExpression != null -> customExpression + else -> buildString { + append(receiver) + append(".") + append(name) + if (isFunction) append("(") + parameterTypes.withIndex().drop(1).joinTo(this) { (index, type) -> + castValue(('a' + index).toString(), type) + } + if (isFunction) append(")") + } + } + } +} + +private fun getOperationMap(argumentsCount: Int): MutableList { val builtIns = DefaultBuiltIns.Instance - val operationMap = mutableMapOf>() + val operationMap = mutableListOf() val allPrimitiveTypes = PrimitiveType.values().map { builtIns.getBuiltInClassByFqName(it.typeFqName) } val arrays = PrimitiveType.values().map { builtIns.getPrimitiveArrayClassDescriptor(it) } + builtIns.array fun CallableDescriptor.isFakeOverride(classDescriptor: ClassDescriptor): Boolean { val isPrimitive = KotlinBuiltIns.isPrimitiveClass(classDescriptor) || KotlinBuiltIns.isString(classDescriptor.defaultType) val isFakeOverridden = (this as? FunctionDescriptor)?.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE - return when { - isPrimitive -> false - else -> isFakeOverridden - } + return !isPrimitive && isFakeOverridden } for (classDescriptor in allPrimitiveTypes + builtIns.string + arrays + builtIns.any) { - val classTypeParameters = classDescriptor.typeConstructor.parameters.map { it.name.asString() } - val typeParametersReplacedToAny = - if (classTypeParameters.isNotEmpty()) classTypeParameters.joinToString(prefix = "<", postfix = ">") { "Any?" } else "" - val classType = classDescriptor.defaultType.constructor.toString() - val compileTimeFunctions = classDescriptor.unsubstitutedMemberScope.getContributedDescriptors() .filterIsInstance() - .filter { !it.isFakeOverride(classDescriptor) } + .filter { !it.isFakeOverride(classDescriptor) && it.valueParameters.size + 1 == argumentsCount } for (function in compileTimeFunctions) { - val operationArguments = (listOf(classType) + function.valueParameters.map { it.type }).joinToString { "\"" + it + "\"" } - - val typeParametersOfFun = listOf(classType + typeParametersReplacedToAny) + - function.valueParameters.map { if (classTypeParameters.contains(it.type.toString())) "Any?" else it.type.toString() } - - if (function.valueParameters.size + 1 == argumentsCount) { // +1 for receiver - operationMap[function] = typeParametersOfFun.joinToString(prefix = "<", postfix = ">") to operationArguments - } + operationMap.add( + Operation( + function.name.asString(), + listOf(classDescriptor.defaultType.constructor.toString()) + function.valueParameters.map { it.type.toString() }, + function is FunctionDescriptor + ) + ) } } return operationMap } -private fun getBinaryIrOperationMap(irBuiltIns: IrBuiltIns): MutableMap> { - val operationMap = mutableMapOf>() +private fun getBinaryIrOperationMap(irBuiltIns: IrBuiltIns): List { + val operationMap = mutableListOf() val irFunSymbols = (irBuiltIns.lessFunByOperandType.values + irBuiltIns.lessOrEqualFunByOperandType.values + irBuiltIns.greaterFunByOperandType.values + irBuiltIns.greaterOrEqualFunByOperandType.values + @@ -121,49 +221,21 @@ private fun getBinaryIrOperationMap(irBuiltIns: IrBuiltIns): MutableMap>, irBuiltIns: IrBuiltIns): String { - val irNullCheck = irBuiltIns.checkNotNullSymbol.owner - return unaryOperationsMap.entries.joinToString(separator = ",\n", postfix = ",\n") { (function, parameters) -> - val methodName = "${function.name}" - val parentheses = if (function is FunctionDescriptor) "()" else "" - " unaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a -> a.$methodName$parentheses }" - } + " unaryOperation(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type.originalKotlinType}\") { a -> a!! }" -} - -private fun generateBinaryBody( - binaryOperationsMap: Map>, binaryIrOperationsMap: Map> -): String { - return binaryOperationsMap.entries.joinToString(separator = ",\n", postfix = ",\n") { (function, parameters) -> - val methodName = "${function.name}" - " binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> a.$methodName(b) }" - } + binaryIrOperationsMap.entries.joinToString(separator = ",\n") { (function, parameters) -> - val methodName = "${function.name}" - val methodSymbol = getIrMethodSymbolByName(methodName) - val body = when (methodName) { - IrBuiltIns.OperatorNames.EQEQEQ -> "if (a is Proxy && b is Proxy) a.state === b.state else a === b" - else -> "a $methodSymbol b" - } - " binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> $body }" - } -} - -private fun generateTernaryBody(ternaryOperationsMap: Map>): String { - return ternaryOperationsMap.entries.joinToString(separator = ",\n") { (function, parameters) -> - val methodName = "${function.name}" - " ternaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b, c -> a.$methodName(b, c) }" - } -} - private fun getIrMethodSymbolByName(methodName: String): String { return when (methodName) { IrBuiltIns.OperatorNames.LESS -> "<" diff --git a/generators/tests/org/jetbrains/kotlin/generators/interpreter/GenerateInterpreterMapTest.kt b/generators/tests/org/jetbrains/kotlin/generators/interpreter/GenerateInterpreterMapTest.kt index e4b64047aee..765f6e4c556 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/interpreter/GenerateInterpreterMapTest.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/interpreter/GenerateInterpreterMapTest.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.generators.interpreter.DESTINATION import org.jetbrains.kotlin.generators.interpreter.generateMap import org.jetbrains.kotlin.test.KotlinTestUtils -class GenerateBuiltInsMapTest : TestCase() { +class GenerateInterpreterMapTest : TestCase() { fun testGeneratedDataIsUpToDate() { val text = generateMap() KotlinTestUtils.assertEqualsToFile(DESTINATION, text)