|  | /* | 
|  | * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. | 
|  | * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. | 
|  | */ | 
|  |  | 
|  | package org.jetbrains.kotlin.generators.evaluate | 
|  |  | 
|  | import org.jetbrains.kotlin.builtins.DefaultBuiltIns | 
|  | import org.jetbrains.kotlin.builtins.KotlinBuiltIns | 
|  | import org.jetbrains.kotlin.descriptors.CallableDescriptor | 
|  | 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.typeUtil.makeNotNullable | 
|  | import org.jetbrains.kotlin.utils.Printer | 
|  | import java.io.File | 
|  |  | 
|  | val DEST_FILE: File = File("compiler/frontend.common/src/org/jetbrains/kotlin/resolve/constants/evaluate/OperationsMapGenerated.kt") | 
|  | private val EXCLUDED_FUNCTIONS: List<String> = listOf("rangeTo", "rangeUntil", "hashCode", "inc", "dec", "subSequence") | 
|  |  | 
|  | fun main() { | 
|  | GeneratorsFileUtil.writeFileIfContentChanged(DEST_FILE, generate()) | 
|  | } | 
|  |  | 
|  | fun generate(): String { | 
|  | val sb = StringBuilder() | 
|  | val p = Printer(sb) | 
|  | p.println(File("license/COPYRIGHT_HEADER.txt").readText()) | 
|  | p.println("@file:Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\")") | 
|  |  | 
|  | 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() | 
|  | 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> | 
|  |  | 
|  | val integerTypes = allPrimitiveTypes.map { it.defaultType }.filter { it.isIntegerType() } | 
|  | val fpTypes = allPrimitiveTypes.map { it.defaultType }.filter { it.isFpType() } | 
|  |  | 
|  | 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> | 
|  |  | 
|  | for (function in functions) { | 
|  | val parametersTypes = function.getParametersTypes() | 
|  |  | 
|  | 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}" | 
|  | ) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | unaryOperationsMap.add(Triple("code", listOf(builtIns.charType), false)) | 
|  |  | 
|  | for (type in integerTypes) { | 
|  | for (otherType in integerTypes) { | 
|  | val parameters = listOf(type, otherType) | 
|  | binaryOperationsMap.add("mod" to parameters) | 
|  | binaryOperationsMap.add("floorDiv" to parameters) | 
|  | } | 
|  | } | 
|  |  | 
|  | for (type in fpTypes) { | 
|  | for (otherType in fpTypes) { | 
|  | val parameters = listOf(type, otherType) | 
|  | binaryOperationsMap.add("mod" to parameters) | 
|  | } | 
|  | } | 
|  |  | 
|  | p.println("fun evalUnaryOp(name: String, type: CompileTimeType, value: Any): Any? {") | 
|  | p.pushIndent() | 
|  | 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.println("else -> {}") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | p.println("return null") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | p.println() | 
|  |  | 
|  | p.println("fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, rightType: CompileTimeType, right: Any): Any? {") | 
|  | p.pushIndent() | 
|  | 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.println("else -> {}") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | } | 
|  | p.println("else -> {}") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | p.println("return null") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | p.println() | 
|  |  | 
|  | p.println("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.println("else -> {}") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | } | 
|  | p.println("else -> {}") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  | p.println("return null") | 
|  | p.popIndent() | 
|  | p.println("}") | 
|  |  | 
|  | return sb.toString() | 
|  | } | 
|  |  | 
|  | private fun getBinaryCheckerName(name: String, leftType: KotlinType, rightType: KotlinType): String? { | 
|  | if (!leftType.isIntegerType() || !rightType.isIntegerType()) return null | 
|  |  | 
|  | return when (name) { | 
|  | "plus" -> "add" | 
|  | "minus" -> "subtract" | 
|  | "div" -> "divide" | 
|  | "times" -> "multiply" | 
|  | "rem", "xor", "or", "and" -> name | 
|  | else -> null | 
|  | } | 
|  | } | 
|  |  | 
|  | private fun KotlinType.isIntegerType(): Boolean = | 
|  | KotlinBuiltIns.isInt(this) || KotlinBuiltIns.isShort(this) || KotlinBuiltIns.isByte(this) || KotlinBuiltIns.isLong(this) | 
|  |  | 
|  | private fun KotlinType.isFpType(): Boolean = | 
|  | KotlinBuiltIns.isDouble(this) || KotlinBuiltIns.isFloat(this) | 
|  |  | 
|  | private fun CallableDescriptor.getParametersTypes(): List<KotlinType> = | 
|  | listOf((containingDeclaration as ClassDescriptor).defaultType) + | 
|  | valueParameters.map { it.type.makeNotNullable() } | 
|  |  | 
|  | private fun KotlinType.asString(): String = typeName.uppercase() | 
|  |  | 
|  | private val KotlinType.typeName: String | 
|  | get(): String = constructor.declarationDescriptor!!.name.asString() |