Rewrite generator for OperationsMapGenerated

Do not generate operations as lambdas; instead use `when` over
strings/enums, which is generated to tableswitch in the bytecode.

This reduces the proguarded compiler jar size by ~0.57%.

 #KT-23565 Fixed
This commit is contained in:
Alexander Udalov
2021-01-08 18:00:04 +01:00
parent df75cddcb8
commit 742fef9042
3 changed files with 740 additions and 509 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.constants.evaluate.CompileTimeType.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -903,7 +904,7 @@ private class ConstantExpressionEvaluatorVisitor(
return null
}
private class OperationArgument(val value: Any, val ctcType: CompileTimeType<*>, val expression: KtExpression)
private class OperationArgument(val value: Any, val ctcType: CompileTimeType, val expression: KtExpression)
private fun createOperationArgumentForReceiver(resolvedCall: ResolvedCall<*>, expression: KtExpression): OperationArgument? {
val receiverExpressionType = getReceiverExpressionType(resolvedCall) ?: return null
@@ -927,7 +928,7 @@ private class ConstantExpressionEvaluatorVisitor(
return createOperationArgument(argumentExpression, parameter.type, argumentCompileTimeType)
}
private fun getCompileTimeType(c: KotlinType): CompileTimeType<out Any>? =
private fun getCompileTimeType(c: KotlinType): CompileTimeType? =
when (TypeUtils.makeNotNullable(c)) {
builtIns.intType -> INT
builtIns.byteType -> BYTE
@@ -945,7 +946,7 @@ private class ConstantExpressionEvaluatorVisitor(
private fun createOperationArgument(
expression: KtExpression,
parameterType: KotlinType,
compileTimeType: CompileTimeType<*>
compileTimeType: CompileTimeType,
): OperationArgument? {
val compileTimeConstant = constantExpressionEvaluator.evaluateExpression(expression, trace, parameterType) ?: return null
if (compileTimeConstant is TypedCompileTimeConstant && !compileTimeConstant.type.isSubtypeOf(parameterType)) return null
@@ -1098,44 +1099,11 @@ private fun getReceiverExpressionType(resolvedCall: ResolvedCall<*>): KotlinType
}
}
internal class CompileTimeType<T>(val name: String) {
override fun toString() = name
internal enum class CompileTimeType {
BYTE, SHORT, INT, LONG, DOUBLE, FLOAT, CHAR, BOOLEAN,
STRING, ANY
}
internal val BYTE = CompileTimeType<Byte>("Byte")
internal val SHORT = CompileTimeType<Short>("Short")
internal val INT = CompileTimeType<Int>("Int")
internal val LONG = CompileTimeType<Long>("Long")
internal val DOUBLE = CompileTimeType<Double>("Double")
internal val FLOAT = CompileTimeType<Float>("Float")
internal val CHAR = CompileTimeType<Char>("Char")
internal val BOOLEAN = CompileTimeType<Boolean>("Boolean")
internal val STRING = CompileTimeType<String>("String")
internal val ANY = CompileTimeType<Any>("Any")
@Suppress("UNCHECKED_CAST")
internal fun <A, B> binaryOperation(
a: CompileTimeType<A>,
b: CompileTimeType<B>,
functionName: String,
operation: Function2<A, B, Any>,
checker: Function2<BigInteger, BigInteger, BigInteger>
) = BinaryOperationKey(a, b, functionName) to Pair(
operation,
checker
) as Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>
@Suppress("UNCHECKED_CAST")
internal fun <A> unaryOperation(
a: CompileTimeType<A>,
functionName: String,
operation: Function1<A, Any>,
checker: Function1<Long, Long>
) = UnaryOperationKey(a, functionName) to Pair(operation, checker) as Pair<Function1<Any?, Any>, Function1<Long, Long>>
internal data class BinaryOperationKey<out A, out B>(val f: CompileTimeType<out A>, val s: CompileTimeType<out B>, val functionName: String)
internal data class UnaryOperationKey<out A>(val f: CompileTimeType<out A>, val functionName: String)
fun ConstantValue<*>.isStandaloneOnlyConstant(): Boolean {
return this is KClassValue || this is EnumValue || this is AnnotationValue || this is ArrayValue
}
@@ -1156,39 +1124,28 @@ private fun isZero(value: Any?): Boolean {
}
private fun typeStrToCompileTimeType(str: String) = when (str) {
BYTE.name -> BYTE
SHORT.name -> SHORT
INT.name -> INT
LONG.name -> LONG
DOUBLE.name -> DOUBLE
FLOAT.name -> FLOAT
CHAR.name -> CHAR
BOOLEAN.name -> BOOLEAN
STRING.name -> STRING
ANY.name -> ANY
"Byte" -> BYTE
"Short" -> SHORT
"Int" -> INT
"Long" -> LONG
"Double" -> DOUBLE
"Float" -> FLOAT
"Char" -> CHAR
"Boolean" -> BOOLEAN
"String" -> STRING
"Any" -> ANY
else -> throw IllegalArgumentException("Unsupported type: $str")
}
fun evaluateUnary(name: String, typeStr: String, value: Any): Any? {
return evaluateUnaryAndCheck(name, typeStrToCompileTimeType(typeStr), value)
}
fun evaluateUnary(name: String, typeStr: String, value: Any): Any? =
evalUnaryOp(name, typeStrToCompileTimeType(typeStr), value)
private fun evaluateUnaryAndCheck(name: String, type: CompileTimeType<*>, value: Any, tracer: () -> Unit = {}): Any? {
val functions = unaryOperations[UnaryOperationKey(type, name)] ?: return null
val (function, check) = functions
val result = function(value)
if (check == emptyUnaryFun) {
return result
private fun evaluateUnaryAndCheck(name: String, type: CompileTimeType, value: Any, reportIntegerOverflow: () -> Unit): Any? =
evalUnaryOp(name, type, value).also { result ->
if (isIntegerType(value) && (name == "minus" || name == "unaryMinus") && value == result && !isZero(value)) {
reportIntegerOverflow()
}
}
assert(isIntegerType(value)) { "Only integer constants should be checked for overflow" }
assert(name == "minus" || name == "unaryMinus") { "Only negation should be checked for overflow" }
if (value == result && !isZero(value)) {
tracer()
}
return result
}
fun evaluateBinary(
name: String,
@@ -1200,42 +1157,35 @@ fun evaluateBinary(
val receiverType = typeStrToCompileTimeType(receiverTypeStr)
val parameterType = typeStrToCompileTimeType(parameterTypeStr)
return evaluateBinaryAndCheck(name, receiverType, receiverValue, parameterType, parameterValue)
return try {
evalBinaryOp(name, receiverType, receiverValue, parameterType, parameterValue)
} catch (e: Exception) {
null
}
}
private fun evaluateBinaryAndCheck(
name: String,
receiverType: CompileTimeType<*>,
receiverType: CompileTimeType,
receiverValue: Any,
parameterType: CompileTimeType<*>,
parameterType: CompileTimeType,
parameterValue: Any,
tracer: () -> Unit = {}
reportIntegerOverflow: () -> Unit,
): Any? {
val functions = binaryOperations[BinaryOperationKey(receiverType, parameterType, name)] ?: return null
val (function, checker) = functions
val actualResult = try {
function(receiverValue, parameterValue)
evalBinaryOp(name, receiverType, receiverValue, parameterType, parameterValue)
} catch (e: Exception) {
null
}
if (checker == emptyBinaryFun) {
return actualResult
}
assert(isIntegerType(receiverValue) && isIntegerType(parameterValue)) { "Only integer constants should be checked for overflow" }
fun toBigInteger(value: Any?) = BigInteger.valueOf((value as Number).toLong())
val refinedChecker = if (name == OperatorNameConventions.MOD.asString()) {
binaryOperations[BinaryOperationKey(receiverType, parameterType, OperatorNameConventions.REM.asString())]?.second ?: return null
} else {
checker
if (actualResult != null && isIntegerType(receiverValue) && isIntegerType(parameterValue)) {
val checkedResult = checkBinaryOp(name, receiverType, toBigInteger(receiverValue), parameterType, toBigInteger(parameterValue))
if (checkedResult != null && toBigInteger(actualResult) != checkedResult) {
reportIntegerOverflow()
}
}
val resultInBigIntegers = refinedChecker(toBigInteger(receiverValue), toBigInteger(parameterValue))
if (toBigInteger(actualResult) != resultInBigIntegers) {
tracer()
}
return actualResult
}
@@ -14,344 +14,616 @@
* limitations under the License.
*/
@file:Suppress("DEPRECATION", "DEPRECATION_ERROR")
@file:Suppress("DEPRECATION", "DEPRECATION_ERROR", "NON_EXHAUSTIVE_WHEN")
package org.jetbrains.kotlin.resolve.constants.evaluate
import org.jetbrains.kotlin.resolve.constants.evaluate.CompileTimeType.*
import java.math.BigInteger
import java.util.HashMap
/** This file is generated by org.jetbrains.kotlin.generators.evaluate:generate(). DO NOT MODIFY MANUALLY */
/** This file is generated by `./gradlew generateOperationsMap`. DO NOT MODIFY MANUALLY */
internal val emptyBinaryFun: Function2<BigInteger, BigInteger, BigInteger> = { _, _ -> BigInteger("0") }
internal val emptyUnaryFun: Function1<Long, Long> = { _ -> 1.toLong() }
internal fun evalUnaryOp(name: String, type: CompileTimeType, value: Any): Any? {
when (type) {
BOOLEAN -> when (name) {
"not" -> return (value as Boolean).not()
"toString" -> return (value as Boolean).toString()
}
BYTE -> when (name) {
"toByte" -> return (value as Byte).toByte()
"toChar" -> return (value as Byte).toChar()
"toDouble" -> return (value as Byte).toDouble()
"toFloat" -> return (value as Byte).toFloat()
"toInt" -> return (value as Byte).toInt()
"toLong" -> return (value as Byte).toLong()
"toShort" -> return (value as Byte).toShort()
"toString" -> return (value as Byte).toString()
"unaryMinus" -> return (value as Byte).unaryMinus()
"unaryPlus" -> return (value as Byte).unaryPlus()
}
CHAR -> when (name) {
"toByte" -> return (value as Char).toByte()
"toChar" -> return (value as Char).toChar()
"toDouble" -> return (value as Char).toDouble()
"toFloat" -> return (value as Char).toFloat()
"toInt" -> return (value as Char).toInt()
"toLong" -> return (value as Char).toLong()
"toShort" -> return (value as Char).toShort()
"toString" -> return (value as Char).toString()
}
DOUBLE -> when (name) {
"toByte" -> return (value as Double).toByte()
"toChar" -> return (value as Double).toChar()
"toDouble" -> return (value as Double).toDouble()
"toFloat" -> return (value as Double).toFloat()
"toInt" -> return (value as Double).toInt()
"toLong" -> return (value as Double).toLong()
"toShort" -> return (value as Double).toShort()
"toString" -> return (value as Double).toString()
"unaryMinus" -> return (value as Double).unaryMinus()
"unaryPlus" -> return (value as Double).unaryPlus()
}
FLOAT -> when (name) {
"toByte" -> return (value as Float).toByte()
"toChar" -> return (value as Float).toChar()
"toDouble" -> return (value as Float).toDouble()
"toFloat" -> return (value as Float).toFloat()
"toInt" -> return (value as Float).toInt()
"toLong" -> return (value as Float).toLong()
"toShort" -> return (value as Float).toShort()
"toString" -> return (value as Float).toString()
"unaryMinus" -> return (value as Float).unaryMinus()
"unaryPlus" -> return (value as Float).unaryPlus()
}
INT -> when (name) {
"inv" -> return (value as Int).inv()
"toByte" -> return (value as Int).toByte()
"toChar" -> return (value as Int).toChar()
"toDouble" -> return (value as Int).toDouble()
"toFloat" -> return (value as Int).toFloat()
"toInt" -> return (value as Int).toInt()
"toLong" -> return (value as Int).toLong()
"toShort" -> return (value as Int).toShort()
"toString" -> return (value as Int).toString()
"unaryMinus" -> return (value as Int).unaryMinus()
"unaryPlus" -> return (value as Int).unaryPlus()
}
LONG -> when (name) {
"inv" -> return (value as Long).inv()
"toByte" -> return (value as Long).toByte()
"toChar" -> return (value as Long).toChar()
"toDouble" -> return (value as Long).toDouble()
"toFloat" -> return (value as Long).toFloat()
"toInt" -> return (value as Long).toInt()
"toLong" -> return (value as Long).toLong()
"toShort" -> return (value as Long).toShort()
"toString" -> return (value as Long).toString()
"unaryMinus" -> return (value as Long).unaryMinus()
"unaryPlus" -> return (value as Long).unaryPlus()
}
SHORT -> when (name) {
"toByte" -> return (value as Short).toByte()
"toChar" -> return (value as Short).toChar()
"toDouble" -> return (value as Short).toDouble()
"toFloat" -> return (value as Short).toFloat()
"toInt" -> return (value as Short).toInt()
"toLong" -> return (value as Short).toLong()
"toShort" -> return (value as Short).toShort()
"toString" -> return (value as Short).toString()
"unaryMinus" -> return (value as Short).unaryMinus()
"unaryPlus" -> return (value as Short).unaryPlus()
}
STRING -> when (name) {
"length" -> return (value as String).length
"toString" -> return (value as String).toString()
}
}
return null
}
internal val unaryOperations: HashMap<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>>
= hashMapOf<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>>(
unaryOperation(BOOLEAN, "not", { a -> a.not() }, emptyUnaryFun),
unaryOperation(BOOLEAN, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(BYTE, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(BYTE, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(BYTE, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(BYTE, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(BYTE, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(BYTE, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(BYTE, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(BYTE, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(BYTE, "unaryMinus", { a -> a.unaryMinus() }, { a -> a.unaryMinus() }),
unaryOperation(BYTE, "unaryPlus", { a -> a.unaryPlus() }, emptyUnaryFun),
unaryOperation(CHAR, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(CHAR, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(CHAR, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(CHAR, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(CHAR, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(CHAR, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(CHAR, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(CHAR, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(DOUBLE, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(DOUBLE, "unaryMinus", { a -> a.unaryMinus() }, emptyUnaryFun),
unaryOperation(DOUBLE, "unaryPlus", { a -> a.unaryPlus() }, emptyUnaryFun),
unaryOperation(FLOAT, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(FLOAT, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(FLOAT, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(FLOAT, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(FLOAT, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(FLOAT, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(FLOAT, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(FLOAT, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(FLOAT, "unaryMinus", { a -> a.unaryMinus() }, emptyUnaryFun),
unaryOperation(FLOAT, "unaryPlus", { a -> a.unaryPlus() }, emptyUnaryFun),
unaryOperation(INT, "inv", { a -> a.inv() }, emptyUnaryFun),
unaryOperation(INT, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(INT, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(INT, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(INT, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(INT, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(INT, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(INT, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(INT, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(INT, "unaryMinus", { a -> a.unaryMinus() }, { a -> a.unaryMinus() }),
unaryOperation(INT, "unaryPlus", { a -> a.unaryPlus() }, emptyUnaryFun),
unaryOperation(LONG, "inv", { a -> a.inv() }, emptyUnaryFun),
unaryOperation(LONG, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(LONG, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(LONG, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(LONG, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(LONG, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(LONG, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(LONG, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(LONG, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(LONG, "unaryMinus", { a -> a.unaryMinus() }, { a -> a.unaryMinus() }),
unaryOperation(LONG, "unaryPlus", { a -> a.unaryPlus() }, emptyUnaryFun),
unaryOperation(SHORT, "toByte", { a -> a.toByte() }, emptyUnaryFun),
unaryOperation(SHORT, "toChar", { a -> a.toChar() }, emptyUnaryFun),
unaryOperation(SHORT, "toDouble", { a -> a.toDouble() }, emptyUnaryFun),
unaryOperation(SHORT, "toFloat", { a -> a.toFloat() }, emptyUnaryFun),
unaryOperation(SHORT, "toInt", { a -> a.toInt() }, emptyUnaryFun),
unaryOperation(SHORT, "toLong", { a -> a.toLong() }, emptyUnaryFun),
unaryOperation(SHORT, "toShort", { a -> a.toShort() }, emptyUnaryFun),
unaryOperation(SHORT, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(SHORT, "unaryMinus", { a -> a.unaryMinus() }, { a -> a.unaryMinus() }),
unaryOperation(SHORT, "unaryPlus", { a -> a.unaryPlus() }, emptyUnaryFun),
unaryOperation(STRING, "length", { a -> a.length }, emptyUnaryFun),
unaryOperation(STRING, "toString", { a -> a.toString() }, emptyUnaryFun)
)
internal val binaryOperations: HashMap<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>>
= hashMapOf<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>>(
binaryOperation(BOOLEAN, BOOLEAN, "and", { a, b -> a.and(b) }, emptyBinaryFun),
binaryOperation(BOOLEAN, BOOLEAN, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BOOLEAN, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(BOOLEAN, BOOLEAN, "or", { a, b -> a.or(b) }, emptyBinaryFun),
binaryOperation(BOOLEAN, BOOLEAN, "xor", { a, b -> a.xor(b) }, emptyBinaryFun),
binaryOperation(BYTE, BYTE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BYTE, DOUBLE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BYTE, FLOAT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BYTE, INT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BYTE, LONG, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BYTE, SHORT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BYTE, BYTE, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(BYTE, DOUBLE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(BYTE, FLOAT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(BYTE, INT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(BYTE, LONG, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(BYTE, SHORT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(BYTE, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(BYTE, BYTE, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(BYTE, DOUBLE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(BYTE, FLOAT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(BYTE, INT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(BYTE, LONG, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(BYTE, SHORT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(BYTE, BYTE, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(BYTE, DOUBLE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(BYTE, FLOAT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(BYTE, INT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(BYTE, LONG, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(BYTE, SHORT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(BYTE, BYTE, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(BYTE, DOUBLE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(BYTE, FLOAT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(BYTE, INT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(BYTE, LONG, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(BYTE, SHORT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(BYTE, BYTE, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(BYTE, DOUBLE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(BYTE, FLOAT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(BYTE, INT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(BYTE, LONG, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(BYTE, SHORT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(CHAR, CHAR, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(CHAR, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(CHAR, CHAR, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(CHAR, INT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(CHAR, INT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, BYTE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, DOUBLE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, FLOAT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, INT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, LONG, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, SHORT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, BYTE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, DOUBLE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, FLOAT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, INT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, LONG, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, SHORT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, BYTE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, DOUBLE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, FLOAT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, INT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, LONG, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, SHORT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, BYTE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, DOUBLE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, FLOAT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, INT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, LONG, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, SHORT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, BYTE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, DOUBLE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, FLOAT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, INT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, LONG, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, SHORT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, BYTE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, DOUBLE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, FLOAT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, INT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, LONG, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(DOUBLE, SHORT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(FLOAT, BYTE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(FLOAT, DOUBLE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(FLOAT, FLOAT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(FLOAT, INT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(FLOAT, LONG, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(FLOAT, SHORT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(FLOAT, BYTE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(FLOAT, DOUBLE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(FLOAT, FLOAT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(FLOAT, INT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(FLOAT, LONG, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(FLOAT, SHORT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(FLOAT, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(FLOAT, BYTE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, DOUBLE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, FLOAT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, INT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, LONG, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, SHORT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, BYTE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, DOUBLE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, FLOAT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, INT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, LONG, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, SHORT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(FLOAT, BYTE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(FLOAT, DOUBLE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(FLOAT, FLOAT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(FLOAT, INT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(FLOAT, LONG, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(FLOAT, SHORT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(FLOAT, BYTE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(FLOAT, DOUBLE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(FLOAT, FLOAT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(FLOAT, INT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(FLOAT, LONG, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(FLOAT, SHORT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "and", { a, b -> a.and(b) }, { a, b -> a.and(b) }),
binaryOperation(INT, BYTE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(INT, DOUBLE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(INT, FLOAT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(INT, LONG, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(INT, SHORT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(INT, BYTE, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(INT, DOUBLE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(INT, FLOAT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(INT, LONG, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(INT, SHORT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(INT, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(INT, BYTE, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(INT, DOUBLE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(INT, FLOAT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(INT, LONG, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(INT, SHORT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(INT, INT, "or", { a, b -> a.or(b) }, { a, b -> a.or(b) }),
binaryOperation(INT, BYTE, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(INT, DOUBLE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(INT, FLOAT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(INT, LONG, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(INT, SHORT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(INT, BYTE, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(INT, DOUBLE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(INT, FLOAT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(INT, LONG, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(INT, SHORT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(INT, INT, "shl", { a, b -> a.shl(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "shr", { a, b -> a.shr(b) }, emptyBinaryFun),
binaryOperation(INT, BYTE, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(INT, DOUBLE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(INT, FLOAT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(INT, LONG, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(INT, SHORT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(INT, INT, "ushr", { a, b -> a.ushr(b) }, emptyBinaryFun),
binaryOperation(INT, INT, "xor", { a, b -> a.xor(b) }, { a, b -> a.xor(b) }),
binaryOperation(LONG, LONG, "and", { a, b -> a.and(b) }, { a, b -> a.and(b) }),
binaryOperation(LONG, BYTE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(LONG, DOUBLE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(LONG, FLOAT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(LONG, LONG, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(LONG, SHORT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(LONG, BYTE, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(LONG, DOUBLE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(LONG, FLOAT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(LONG, LONG, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(LONG, SHORT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(LONG, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(LONG, BYTE, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(LONG, DOUBLE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(LONG, FLOAT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(LONG, LONG, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(LONG, SHORT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(LONG, LONG, "or", { a, b -> a.or(b) }, { a, b -> a.or(b) }),
binaryOperation(LONG, BYTE, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(LONG, DOUBLE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(LONG, FLOAT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(LONG, LONG, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(LONG, SHORT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(LONG, BYTE, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(LONG, DOUBLE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(LONG, FLOAT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(LONG, LONG, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(LONG, SHORT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(LONG, INT, "shl", { a, b -> a.shl(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "shr", { a, b -> a.shr(b) }, emptyBinaryFun),
binaryOperation(LONG, BYTE, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(LONG, DOUBLE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(LONG, FLOAT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(LONG, INT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(LONG, LONG, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(LONG, SHORT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(LONG, INT, "ushr", { a, b -> a.ushr(b) }, emptyBinaryFun),
binaryOperation(LONG, LONG, "xor", { a, b -> a.xor(b) }, { a, b -> a.xor(b) }),
binaryOperation(SHORT, BYTE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(SHORT, DOUBLE, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(SHORT, FLOAT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(SHORT, INT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(SHORT, LONG, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(SHORT, SHORT, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(SHORT, BYTE, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(SHORT, DOUBLE, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(SHORT, FLOAT, "div", { a, b -> a.div(b) }, emptyBinaryFun),
binaryOperation(SHORT, INT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(SHORT, LONG, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(SHORT, SHORT, "div", { a, b -> a.div(b) }, { a, b -> a.divide(b) }),
binaryOperation(SHORT, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(SHORT, BYTE, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(SHORT, DOUBLE, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(SHORT, FLOAT, "minus", { a, b -> a.minus(b) }, emptyBinaryFun),
binaryOperation(SHORT, INT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(SHORT, LONG, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(SHORT, SHORT, "minus", { a, b -> a.minus(b) }, { a, b -> a.subtract(b) }),
binaryOperation(SHORT, BYTE, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(SHORT, DOUBLE, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(SHORT, FLOAT, "plus", { a, b -> a.plus(b) }, emptyBinaryFun),
binaryOperation(SHORT, INT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(SHORT, LONG, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(SHORT, SHORT, "plus", { a, b -> a.plus(b) }, { a, b -> a.add(b) }),
binaryOperation(SHORT, BYTE, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(SHORT, DOUBLE, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(SHORT, FLOAT, "rem", { a, b -> a.rem(b) }, emptyBinaryFun),
binaryOperation(SHORT, INT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(SHORT, LONG, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(SHORT, SHORT, "rem", { a, b -> a.rem(b) }, { a, b -> a.rem(b) }),
binaryOperation(SHORT, BYTE, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(SHORT, DOUBLE, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(SHORT, FLOAT, "times", { a, b -> a.times(b) }, emptyBinaryFun),
binaryOperation(SHORT, INT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(SHORT, LONG, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(SHORT, SHORT, "times", { a, b -> a.times(b) }, { a, b -> a.multiply(b) }),
binaryOperation(STRING, STRING, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(STRING, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
binaryOperation(STRING, INT, "get", { a, b -> a.get(b) }, emptyBinaryFun),
binaryOperation(STRING, ANY, "plus", { a, b -> a.plus(b) }, emptyBinaryFun)
)
internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, rightType: CompileTimeType, right: Any): Any? {
when (leftType) {
BOOLEAN -> when (rightType) {
BOOLEAN -> when (name) {
"and" -> return (left as Boolean).and(right as Boolean)
"compareTo" -> return (left as Boolean).compareTo(right as Boolean)
"or" -> return (left as Boolean).or(right as Boolean)
"xor" -> return (left as Boolean).xor(right as Boolean)
}
ANY -> when (name) {
"equals" -> return (left as Boolean).equals(right)
}
}
BYTE -> when (rightType) {
BYTE -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Byte)
"div" -> return (left as Byte).div(right as Byte)
"minus" -> return (left as Byte).minus(right as Byte)
"plus" -> return (left as Byte).plus(right as Byte)
"rem" -> return (left as Byte).rem(right as Byte)
"times" -> return (left as Byte).times(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Double)
"div" -> return (left as Byte).div(right as Double)
"minus" -> return (left as Byte).minus(right as Double)
"plus" -> return (left as Byte).plus(right as Double)
"rem" -> return (left as Byte).rem(right as Double)
"times" -> return (left as Byte).times(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Float)
"div" -> return (left as Byte).div(right as Float)
"minus" -> return (left as Byte).minus(right as Float)
"plus" -> return (left as Byte).plus(right as Float)
"rem" -> return (left as Byte).rem(right as Float)
"times" -> return (left as Byte).times(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Int)
"div" -> return (left as Byte).div(right as Int)
"minus" -> return (left as Byte).minus(right as Int)
"plus" -> return (left as Byte).plus(right as Int)
"rem" -> return (left as Byte).rem(right as Int)
"times" -> return (left as Byte).times(right as Int)
}
LONG -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Long)
"div" -> return (left as Byte).div(right as Long)
"minus" -> return (left as Byte).minus(right as Long)
"plus" -> return (left as Byte).plus(right as Long)
"rem" -> return (left as Byte).rem(right as Long)
"times" -> return (left as Byte).times(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Short)
"div" -> return (left as Byte).div(right as Short)
"minus" -> return (left as Byte).minus(right as Short)
"plus" -> return (left as Byte).plus(right as Short)
"rem" -> return (left as Byte).rem(right as Short)
"times" -> return (left as Byte).times(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Byte).equals(right)
}
}
CHAR -> when (rightType) {
CHAR -> when (name) {
"compareTo" -> return (left as Char).compareTo(right as Char)
"minus" -> return (left as Char).minus(right as Char)
}
ANY -> when (name) {
"equals" -> return (left as Char).equals(right)
}
INT -> when (name) {
"minus" -> return (left as Char).minus(right as Int)
"plus" -> return (left as Char).plus(right as Int)
}
}
DOUBLE -> when (rightType) {
BYTE -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Byte)
"div" -> return (left as Double).div(right as Byte)
"minus" -> return (left as Double).minus(right as Byte)
"plus" -> return (left as Double).plus(right as Byte)
"rem" -> return (left as Double).rem(right as Byte)
"times" -> return (left as Double).times(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Double)
"div" -> return (left as Double).div(right as Double)
"minus" -> return (left as Double).minus(right as Double)
"plus" -> return (left as Double).plus(right as Double)
"rem" -> return (left as Double).rem(right as Double)
"times" -> return (left as Double).times(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Float)
"div" -> return (left as Double).div(right as Float)
"minus" -> return (left as Double).minus(right as Float)
"plus" -> return (left as Double).plus(right as Float)
"rem" -> return (left as Double).rem(right as Float)
"times" -> return (left as Double).times(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Int)
"div" -> return (left as Double).div(right as Int)
"minus" -> return (left as Double).minus(right as Int)
"plus" -> return (left as Double).plus(right as Int)
"rem" -> return (left as Double).rem(right as Int)
"times" -> return (left as Double).times(right as Int)
}
LONG -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Long)
"div" -> return (left as Double).div(right as Long)
"minus" -> return (left as Double).minus(right as Long)
"plus" -> return (left as Double).plus(right as Long)
"rem" -> return (left as Double).rem(right as Long)
"times" -> return (left as Double).times(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Short)
"div" -> return (left as Double).div(right as Short)
"minus" -> return (left as Double).minus(right as Short)
"plus" -> return (left as Double).plus(right as Short)
"rem" -> return (left as Double).rem(right as Short)
"times" -> return (left as Double).times(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Double).equals(right)
}
}
FLOAT -> when (rightType) {
BYTE -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Byte)
"div" -> return (left as Float).div(right as Byte)
"minus" -> return (left as Float).minus(right as Byte)
"plus" -> return (left as Float).plus(right as Byte)
"rem" -> return (left as Float).rem(right as Byte)
"times" -> return (left as Float).times(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Double)
"div" -> return (left as Float).div(right as Double)
"minus" -> return (left as Float).minus(right as Double)
"plus" -> return (left as Float).plus(right as Double)
"rem" -> return (left as Float).rem(right as Double)
"times" -> return (left as Float).times(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Float)
"div" -> return (left as Float).div(right as Float)
"minus" -> return (left as Float).minus(right as Float)
"plus" -> return (left as Float).plus(right as Float)
"rem" -> return (left as Float).rem(right as Float)
"times" -> return (left as Float).times(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Int)
"div" -> return (left as Float).div(right as Int)
"minus" -> return (left as Float).minus(right as Int)
"plus" -> return (left as Float).plus(right as Int)
"rem" -> return (left as Float).rem(right as Int)
"times" -> return (left as Float).times(right as Int)
}
LONG -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Long)
"div" -> return (left as Float).div(right as Long)
"minus" -> return (left as Float).minus(right as Long)
"plus" -> return (left as Float).plus(right as Long)
"rem" -> return (left as Float).rem(right as Long)
"times" -> return (left as Float).times(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Short)
"div" -> return (left as Float).div(right as Short)
"minus" -> return (left as Float).minus(right as Short)
"plus" -> return (left as Float).plus(right as Short)
"rem" -> return (left as Float).rem(right as Short)
"times" -> return (left as Float).times(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Float).equals(right)
}
}
INT -> when (rightType) {
INT -> when (name) {
"and" -> return (left as Int).and(right as Int)
"compareTo" -> return (left as Int).compareTo(right as Int)
"div" -> return (left as Int).div(right as Int)
"minus" -> return (left as Int).minus(right as Int)
"or" -> return (left as Int).or(right as Int)
"plus" -> return (left as Int).plus(right as Int)
"rem" -> return (left as Int).rem(right as Int)
"shl" -> return (left as Int).shl(right as Int)
"shr" -> return (left as Int).shr(right as Int)
"times" -> return (left as Int).times(right as Int)
"ushr" -> return (left as Int).ushr(right as Int)
"xor" -> return (left as Int).xor(right as Int)
}
BYTE -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Byte)
"div" -> return (left as Int).div(right as Byte)
"minus" -> return (left as Int).minus(right as Byte)
"plus" -> return (left as Int).plus(right as Byte)
"rem" -> return (left as Int).rem(right as Byte)
"times" -> return (left as Int).times(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Double)
"div" -> return (left as Int).div(right as Double)
"minus" -> return (left as Int).minus(right as Double)
"plus" -> return (left as Int).plus(right as Double)
"rem" -> return (left as Int).rem(right as Double)
"times" -> return (left as Int).times(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Float)
"div" -> return (left as Int).div(right as Float)
"minus" -> return (left as Int).minus(right as Float)
"plus" -> return (left as Int).plus(right as Float)
"rem" -> return (left as Int).rem(right as Float)
"times" -> return (left as Int).times(right as Float)
}
LONG -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Long)
"div" -> return (left as Int).div(right as Long)
"minus" -> return (left as Int).minus(right as Long)
"plus" -> return (left as Int).plus(right as Long)
"rem" -> return (left as Int).rem(right as Long)
"times" -> return (left as Int).times(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Short)
"div" -> return (left as Int).div(right as Short)
"minus" -> return (left as Int).minus(right as Short)
"plus" -> return (left as Int).plus(right as Short)
"rem" -> return (left as Int).rem(right as Short)
"times" -> return (left as Int).times(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Int).equals(right)
}
}
LONG -> when (rightType) {
LONG -> when (name) {
"and" -> return (left as Long).and(right as Long)
"compareTo" -> return (left as Long).compareTo(right as Long)
"div" -> return (left as Long).div(right as Long)
"minus" -> return (left as Long).minus(right as Long)
"or" -> return (left as Long).or(right as Long)
"plus" -> return (left as Long).plus(right as Long)
"rem" -> return (left as Long).rem(right as Long)
"times" -> return (left as Long).times(right as Long)
"xor" -> return (left as Long).xor(right as Long)
}
BYTE -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Byte)
"div" -> return (left as Long).div(right as Byte)
"minus" -> return (left as Long).minus(right as Byte)
"plus" -> return (left as Long).plus(right as Byte)
"rem" -> return (left as Long).rem(right as Byte)
"times" -> return (left as Long).times(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Double)
"div" -> return (left as Long).div(right as Double)
"minus" -> return (left as Long).minus(right as Double)
"plus" -> return (left as Long).plus(right as Double)
"rem" -> return (left as Long).rem(right as Double)
"times" -> return (left as Long).times(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Float)
"div" -> return (left as Long).div(right as Float)
"minus" -> return (left as Long).minus(right as Float)
"plus" -> return (left as Long).plus(right as Float)
"rem" -> return (left as Long).rem(right as Float)
"times" -> return (left as Long).times(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Int)
"div" -> return (left as Long).div(right as Int)
"minus" -> return (left as Long).minus(right as Int)
"plus" -> return (left as Long).plus(right as Int)
"rem" -> return (left as Long).rem(right as Int)
"shl" -> return (left as Long).shl(right as Int)
"shr" -> return (left as Long).shr(right as Int)
"times" -> return (left as Long).times(right as Int)
"ushr" -> return (left as Long).ushr(right as Int)
}
SHORT -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Short)
"div" -> return (left as Long).div(right as Short)
"minus" -> return (left as Long).minus(right as Short)
"plus" -> return (left as Long).plus(right as Short)
"rem" -> return (left as Long).rem(right as Short)
"times" -> return (left as Long).times(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Long).equals(right)
}
}
SHORT -> when (rightType) {
BYTE -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Byte)
"div" -> return (left as Short).div(right as Byte)
"minus" -> return (left as Short).minus(right as Byte)
"plus" -> return (left as Short).plus(right as Byte)
"rem" -> return (left as Short).rem(right as Byte)
"times" -> return (left as Short).times(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Double)
"div" -> return (left as Short).div(right as Double)
"minus" -> return (left as Short).minus(right as Double)
"plus" -> return (left as Short).plus(right as Double)
"rem" -> return (left as Short).rem(right as Double)
"times" -> return (left as Short).times(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Float)
"div" -> return (left as Short).div(right as Float)
"minus" -> return (left as Short).minus(right as Float)
"plus" -> return (left as Short).plus(right as Float)
"rem" -> return (left as Short).rem(right as Float)
"times" -> return (left as Short).times(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Int)
"div" -> return (left as Short).div(right as Int)
"minus" -> return (left as Short).minus(right as Int)
"plus" -> return (left as Short).plus(right as Int)
"rem" -> return (left as Short).rem(right as Int)
"times" -> return (left as Short).times(right as Int)
}
LONG -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Long)
"div" -> return (left as Short).div(right as Long)
"minus" -> return (left as Short).minus(right as Long)
"plus" -> return (left as Short).plus(right as Long)
"rem" -> return (left as Short).rem(right as Long)
"times" -> return (left as Short).times(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Short)
"div" -> return (left as Short).div(right as Short)
"minus" -> return (left as Short).minus(right as Short)
"plus" -> return (left as Short).plus(right as Short)
"rem" -> return (left as Short).rem(right as Short)
"times" -> return (left as Short).times(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Short).equals(right)
}
}
STRING -> when (rightType) {
STRING -> when (name) {
"compareTo" -> return (left as String).compareTo(right as String)
}
ANY -> when (name) {
"equals" -> return (left as String).equals(right)
"plus" -> return (left as String).plus(right)
}
INT -> when (name) {
"get" -> return (left as String).get(right as Int)
}
}
}
return null
}
internal fun checkBinaryOp(
name: String, leftType: CompileTimeType, left: BigInteger, rightType: CompileTimeType, right: BigInteger
): BigInteger? {
when (leftType) {
BYTE -> when (rightType) {
BYTE -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
INT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
LONG -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
SHORT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
}
INT -> when (rightType) {
INT -> when (name) {
"and" -> return left.and(right)
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"or" -> return left.or(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
"xor" -> return left.xor(right)
}
BYTE -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
LONG -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
SHORT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
}
LONG -> when (rightType) {
LONG -> when (name) {
"and" -> return left.and(right)
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"or" -> return left.or(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
"xor" -> return left.xor(right)
}
BYTE -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
INT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
SHORT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
}
SHORT -> when (rightType) {
BYTE -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
INT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
LONG -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
SHORT -> when (name) {
"div" -> return left.divide(right)
"minus" -> return left.subtract(right)
"plus" -> return left.add(right)
"rem" -> return left.rem(right)
"times" -> return left.multiply(right)
}
}
}
return null
}
+97 -88
View File
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.utils.Printer
import java.io.File
@@ -27,29 +27,30 @@ fun generate(): String {
val sb = StringBuilder()
val p = Printer(sb)
p.println(File("license/COPYRIGHT.txt").readText())
p.println("@file:Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\")")
p.println("@file:Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\", \"NON_EXHAUSTIVE_WHEN\")")
p.println()
p.println("package org.jetbrains.kotlin.resolve.constants.evaluate")
p.println()
p.println("import org.jetbrains.kotlin.resolve.constants.evaluate.CompileTimeType.*")
p.println("import java.math.BigInteger")
p.println("import java.util.HashMap")
p.println()
p.println("/** This file is generated by org.jetbrains.kotlin.generators.evaluate:generate(). DO NOT MODIFY MANUALLY */")
p.println("/** This file is generated by `./gradlew generateOperationsMap`. DO NOT MODIFY MANUALLY */")
p.println()
val unaryOperationsMap = arrayListOf<Triple<String, List<KotlinType>, Boolean>>()
val binaryOperationsMap = arrayListOf<Pair<String, List<KotlinType>>>()
val builtIns = DefaultBuiltIns.Instance
@Suppress("UNCHECKED_CAST")
val allPrimitiveTypes = builtIns.builtInsPackageScope.getContributedDescriptors()
.filter { it is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(it.defaultType) } as List<ClassDescriptor>
.filter { it is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(it.defaultType) } as List<ClassDescriptor>
for (descriptor in allPrimitiveTypes + builtIns.string) {
@Suppress("UNCHECKED_CAST")
val functions = descriptor.getMemberScope(listOf()).getContributedDescriptors()
.filter { it is CallableDescriptor && !EXCLUDED_FUNCTIONS.contains(it.getName().asString()) } as List<CallableDescriptor>
.filter { it is CallableDescriptor && !EXCLUDED_FUNCTIONS.contains(it.getName().asString()) } as List<CallableDescriptor>
for (function in functions) {
val parametersTypes = function.getParametersTypes()
@@ -57,108 +58,116 @@ fun generate(): String {
when (parametersTypes.size) {
1 -> unaryOperationsMap.add(Triple(function.name.asString(), parametersTypes, function is FunctionDescriptor))
2 -> binaryOperationsMap.add(function.name.asString() to parametersTypes)
else -> throw IllegalStateException("Couldn't add following method from builtins to operations map: ${function.name} in class ${descriptor.name}")
else -> throw IllegalStateException(
"Couldn't add following method from builtins to operations map: ${function.name} in class ${descriptor.name}"
)
}
}
}
p.println("internal val emptyBinaryFun: Function2<BigInteger, BigInteger, BigInteger> = { _, _ -> BigInteger(\"0\") }")
p.println("internal val emptyUnaryFun: Function1<Long, Long> = { _ -> 1.toLong() }")
p.println()
p.println("internal val unaryOperations: HashMap<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>>")
p.println(" = hashMapOf<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>>(")
p.println("internal fun evalUnaryOp(name: String, type: CompileTimeType, value: Any): Any? {")
p.pushIndent()
val unaryOperationsMapIterator = unaryOperationsMap.iterator()
while (unaryOperationsMapIterator.hasNext()) {
val (funcName, parameters, isFunction) = unaryOperationsMapIterator.next()
val parenthesesOrBlank = if (isFunction) "()" else ""
p.println(
"unaryOperation(",
parameters.map { it.asString() }.joinToString(", "),
", ",
"\"$funcName\"",
", { a -> a.$funcName$parenthesesOrBlank }, ",
renderCheckUnaryOperation(funcName, parameters),
")",
if (unaryOperationsMapIterator.hasNext()) "," else ""
)
p.println("when (type) {")
p.pushIndent()
for ((type, operations) in unaryOperationsMap.groupBy { (_, parameters, _) -> parameters.single() }) {
p.println("${type.asString()} -> when (name) {")
p.pushIndent()
for ((name, _, isFunction) in operations) {
val parenthesesOrBlank = if (isFunction) "()" else ""
p.println("\"$name\" -> return (value as ${type.typeName}).$name$parenthesesOrBlank")
}
p.popIndent()
p.println("}")
}
p.popIndent()
p.println(")")
p.println("}")
p.println("return null")
p.popIndent()
p.println("}")
p.println()
p.println()
p.println("internal val binaryOperations: HashMap<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>>")
p.println(" = hashMapOf<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>>(")
p.println("internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, rightType: CompileTimeType, right: Any): Any? {")
p.pushIndent()
val binaryOperationsMapIterator = binaryOperationsMap.iterator()
while (binaryOperationsMapIterator.hasNext()) {
val (funcName, parameters) = binaryOperationsMapIterator.next()
p.println(
"binaryOperation(",
parameters.map { it.asString() }.joinToString(", "),
", ",
"\"$funcName\"",
", { a, b -> a.$funcName(b) }, ",
renderCheckBinaryOperation(funcName, parameters),
")",
if (binaryOperationsMapIterator.hasNext()) "," else ""
)
p.println("when (leftType) {")
p.pushIndent()
for ((leftType, operationsOnThisLeftType) in binaryOperationsMap.groupBy { (_, parameters) -> parameters.first() }) {
p.println("${leftType.asString()} -> when (rightType) {")
p.pushIndent()
for ((rightType, operations) in operationsOnThisLeftType.groupBy { (_, parameters) -> parameters[1] }) {
p.println("${rightType.asString()} -> when (name) {")
p.pushIndent()
for ((name, _) in operations) {
val castToRightType = if (rightType.typeName == "Any") "" else " as ${rightType.typeName}"
p.println("\"$name\" -> return (left as ${leftType.typeName}).$name(right$castToRightType)")
}
p.popIndent()
p.println("}")
}
p.popIndent()
p.println("}")
}
p.popIndent()
p.println(")")
p.println("}")
p.println("return null")
p.popIndent()
p.println("}")
p.println()
p.println("internal fun checkBinaryOp(")
p.println(" name: String, leftType: CompileTimeType, left: BigInteger, rightType: CompileTimeType, right: BigInteger")
p.println("): BigInteger? {")
p.pushIndent()
p.println("when (leftType) {")
p.pushIndent()
val checkedBinaryOperations =
binaryOperationsMap.filter { (name, parameters) -> getBinaryCheckerName(name, parameters[0], parameters[1]) != null }
for ((leftType, operationsOnThisLeftType) in checkedBinaryOperations.groupBy { (_, parameters) -> parameters.first() }) {
p.println("${leftType.asString()} -> when (rightType) {")
p.pushIndent()
for ((rightType, operations) in operationsOnThisLeftType.groupBy { (_, parameters) -> parameters[1] }) {
p.println("${rightType.asString()} -> when (name) {")
p.pushIndent()
for ((name, _) in operations) {
val checkerName = getBinaryCheckerName(name, leftType, rightType)!!
p.println("\"$name\" -> return left.$checkerName(right)")
}
p.popIndent()
p.println("}")
}
p.popIndent()
p.println("}")
}
p.popIndent()
p.println("}")
p.println("return null")
p.popIndent()
p.println("}")
return sb.toString()
}
fun renderCheckUnaryOperation(name: String, params: List<KotlinType>): String {
val isAllParamsIntegers = params.fold(true) { a, b -> a && b.isIntegerType() }
if (!isAllParamsIntegers) {
return "emptyUnaryFun"
}
private fun getBinaryCheckerName(name: String, leftType: KotlinType, rightType: KotlinType): String? {
if (!leftType.isIntegerType() || !rightType.isIntegerType()) return null
return when(name) {
"unaryMinus", "minus" -> "{ a -> a.$name() }"
else -> "emptyUnaryFun"
return when (name) {
"plus" -> "add"
"minus" -> "subtract"
"div" -> "divide"
"times" -> "multiply"
"mod", "rem", "xor", "or", "and" -> name
else -> null
}
}
fun renderCheckBinaryOperation(name: String, params: List<KotlinType>): String {
val isAllParamsIntegers = params.fold(true) { a, b -> a && b.isIntegerType() }
if (!isAllParamsIntegers) {
return "emptyBinaryFun"
}
private fun KotlinType.isIntegerType(): Boolean =
KotlinBuiltIns.isInt(this) || KotlinBuiltIns.isShort(this) || KotlinBuiltIns.isByte(this) || KotlinBuiltIns.isLong(this)
return when(name) {
"plus" -> "{ a, b -> a.add(b) }"
"minus" -> "{ a, b -> a.subtract(b) }"
"div" -> "{ a, b -> a.divide(b) }"
"times" -> "{ a, b -> a.multiply(b) }"
"mod",
"rem",
"xor",
"or",
"and" -> "{ a, b -> a.$name(b) }"
else -> "emptyBinaryFun"
}
}
private fun CallableDescriptor.getParametersTypes(): List<KotlinType> =
listOf((containingDeclaration as ClassDescriptor).defaultType) +
valueParameters.map { it.type.makeNotNullable() }
private fun KotlinType.isIntegerType(): Boolean {
return KotlinBuiltIns.isInt(this) ||
KotlinBuiltIns.isShort(this) ||
KotlinBuiltIns.isByte(this) ||
KotlinBuiltIns.isLong(this)
}
private fun KotlinType.asString(): String = typeName.toUpperCase()
private fun CallableDescriptor.getParametersTypes(): List<KotlinType> {
val list = arrayListOf<KotlinType>((containingDeclaration as ClassDescriptor).defaultType)
valueParameters.map { it.type }.forEach {
list.add(TypeUtils.makeNotNullable(it))
}
return list
}
private fun KotlinType.asString(): String = constructor.declarationDescriptor!!.name.asString().toUpperCase()
private val KotlinType.typeName: String
get(): String = constructor.declarationDescriptor!!.name.asString()