Implement trim function interpretation in compile time
This commit is contained in:
+88
-51
@@ -5,32 +5,36 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.interpreter
|
package org.jetbrains.kotlin.backend.common.interpreter
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.*
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.binaryFunctions
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
||||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
|
||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
|
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
import org.jetbrains.kotlin.ir.util.statements
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import java.lang.invoke.MethodHandles
|
||||||
|
import java.lang.invoke.MethodType
|
||||||
|
|
||||||
enum class Code(var info: String = "") {
|
enum class Code(var info: String = "") {
|
||||||
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
class IrInterpreter(private val irBuiltIns: IrBuiltIns) {
|
||||||
|
|
||||||
fun interpret(expression: IrExpression): IrExpression {
|
fun interpret(expression: IrExpression): IrExpression {
|
||||||
return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression)
|
return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(irBuiltIns, expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrElement.interpret(data: Frame): Code {
|
private fun IrElement.interpret(data: Frame): Code {
|
||||||
@@ -83,18 +87,30 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code {
|
private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code {
|
||||||
return irFunction.body?.interpret(data)
|
if (irFunction.body == null) {
|
||||||
?: throw NoSuchMethodException("Method \"${irFunction.name}\" wasn't implemented")
|
val receiver = data.getVariableState(irFunction.symbol.getReceiver()!!) as Complex
|
||||||
|
val instance = receiver.instance!!
|
||||||
|
|
||||||
|
val functionImplementation = instance.getIrFunction(irFunction.descriptor)
|
||||||
|
if (functionImplementation?.body == null) throw NoSuchMethodException("Method \"${irFunction.name}\" wasn't implemented")
|
||||||
|
val arguments = functionImplementation.valueParameters.map { Variable(it.descriptor, data.getVariableState(it.descriptor)) }
|
||||||
|
val newFrame = InterpreterFrame()
|
||||||
|
newFrame.addVar(Variable(functionImplementation.symbol.getReceiver()!!, instance))
|
||||||
|
newFrame.addAll(arguments)
|
||||||
|
return functionImplementation.body!!.interpret(newFrame).apply { data.pushReturnValue(newFrame) }
|
||||||
|
}
|
||||||
|
return irFunction.body!!.interpret(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateOverridden(owner: IrFunctionImpl, data: Frame): Code {
|
private fun calculateOverridden(owner: IrFunctionImpl, data: Frame): Code {
|
||||||
val variableDescriptor = owner.symbol.getThisAsReceiver()!!
|
val variableDescriptor = owner.symbol.getReceiver()!!
|
||||||
val superQualifier = (data.getVariableState(variableDescriptor) as Complex).getSuperQualifier()!!
|
val superQualifier = (data.getVariableState(variableDescriptor) as Complex).superType!!
|
||||||
val overridden = owner.overriddenSymbols.first { it.getThisAsReceiver()?.equalTo(superQualifier.getThisReceiver()) == true }
|
val overridden = owner.overriddenSymbols.first { it.getReceiver()?.equalTo(superQualifier.getReceiver()) == true }
|
||||||
|
|
||||||
val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters)
|
val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters)
|
||||||
.map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) }
|
.map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) }
|
||||||
val newStates = InterpreterFrame((valueParameters + Variable(superQualifier.getThisReceiver(), superQualifier)).toMutableList())
|
val newStates = InterpreterFrame(valueParameters.toMutableList())
|
||||||
|
newStates.addVar(Variable(overridden.getReceiver()!!, superQualifier))
|
||||||
|
|
||||||
val overriddenOwner = overridden.owner as IrFunctionImpl
|
val overriddenOwner = overridden.owner as IrFunctionImpl
|
||||||
val body = overriddenOwner.body
|
val body = overriddenOwner.body
|
||||||
@@ -104,26 +120,15 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
}.apply { data.pushReturnValue(newStates) }
|
}.apply { data.pushReturnValue(newStates) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isBuiltIn(irFunction: IrFunction): Boolean {
|
private fun calculateBuiltIns(irFunction: IrFunction, data: Frame): Code {
|
||||||
val descriptor = irFunction.descriptor
|
val descriptor = irFunction.descriptor
|
||||||
val methodName = descriptor.name.asString()
|
val methodName = descriptor.name.asString()
|
||||||
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
||||||
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
||||||
val signature = CompileTimeFunction(
|
|
||||||
methodName,
|
|
||||||
argsType.map { it.toString() })
|
|
||||||
return (unaryFunctions[signature] ?: binaryFunctions[signature]) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateBuiltIns(expression: IrCall, data: Frame): Code {
|
|
||||||
val descriptor = expression.symbol.descriptor
|
|
||||||
val methodName = descriptor.name.asString()
|
|
||||||
val receiverType = descriptor.dispatchReceiverParameter?.type ?: descriptor.extensionReceiverParameter?.type
|
|
||||||
val argsType = listOfNotNull(receiverType) + descriptor.valueParameters.map { TypeUtils.makeNotNullable(it.original.type) }
|
|
||||||
val argsValues = data.getAll()
|
val argsValues = data.getAll()
|
||||||
.map { it.state }
|
.map { it.state }
|
||||||
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||||
.map { it.getIrConst().value }
|
.map { it.getValue() }
|
||||||
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
val signature = CompileTimeFunction(methodName, argsType.map { it.toString() })
|
||||||
//todo try catch
|
//todo try catch
|
||||||
val result = when (argsType.size) {
|
val result = when (argsType.size) {
|
||||||
@@ -136,22 +141,27 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
val function = binaryFunctions[signature]
|
val function = binaryFunctions[signature]
|
||||||
?: throw NoSuchMethodException("For given function $signature there is no entry in binary map")
|
?: throw NoSuchMethodException("For given function $signature there is no entry in binary map")
|
||||||
when (methodName) {
|
when (methodName) {
|
||||||
"rangeTo" -> return calculateRangeTo(expression, data)
|
"rangeTo" -> return calculateRangeTo(irFunction.returnType, data)
|
||||||
else -> function.invoke(argsValues[0], argsValues[1])
|
else -> function.invoke(argsValues[0], argsValues[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3 -> {
|
||||||
|
val function = ternaryFunctions[signature]
|
||||||
|
?: throw NoSuchMethodException("For given function $signature there is no entry in ternary map")
|
||||||
|
function.invoke(argsValues[0], argsValues[1], argsValues[2])
|
||||||
|
}
|
||||||
else -> throw UnsupportedOperationException("Unsupported number of arguments")
|
else -> throw UnsupportedOperationException("Unsupported number of arguments")
|
||||||
}
|
}
|
||||||
data.pushReturnValue(result.toState(expression))
|
data.pushReturnValue(result.toState(irBuiltIns))
|
||||||
return Code.NEXT
|
return Code.NEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateRangeTo(expression: IrExpression, data: Frame): Code {
|
private fun calculateRangeTo(type: IrType, data: Frame): Code {
|
||||||
val constructor = expression.type.classOrNull!!.owner.constructors.first()
|
val constructor = type.classOrNull!!.owner.constructors.first()
|
||||||
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
|
||||||
|
|
||||||
val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> }
|
val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> }
|
||||||
primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) }
|
primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getValue().toIrConst(irBuiltIns)) }
|
||||||
|
|
||||||
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters)
|
||||||
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList())
|
||||||
@@ -161,6 +171,27 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun calculateIntrinsic(irFunction: IrFunction, data: Frame): Code {
|
||||||
|
val annotation = irFunction.getAnnotation(evaluateIntrinsicAnnotation)
|
||||||
|
val argsValues = data.getAll()
|
||||||
|
.map { it.state }
|
||||||
|
.map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") }
|
||||||
|
.map { it.getValue() }
|
||||||
|
|
||||||
|
val textClass = Class.forName((annotation.getValueArgument(0) as IrConst<*>).value.toString())
|
||||||
|
val returnClass = irFunction.returnType.getFqName()!!.let { getPrimitiveClass(it) ?: Class.forName(it) }
|
||||||
|
val extensionClass = irFunction.extensionReceiverParameter?.type?.getFqName()?.let { getPrimitiveClass(it) ?: Class.forName(it) }
|
||||||
|
val argsClasses = irFunction.valueParameters.map {
|
||||||
|
it.descriptor.fqNameSafe.asString().let { getPrimitiveClass(it) ?: Class.forName(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val methodSignature = MethodType.methodType(returnClass, listOfNotNull(extensionClass) + argsClasses)
|
||||||
|
val method = MethodHandles.lookup().findStatic(textClass, irFunction.name.asString(), methodSignature)
|
||||||
|
val result = method.invokeWithArguments(argsValues)
|
||||||
|
data.pushReturnValue(result.toState(irBuiltIns))
|
||||||
|
return Code.NEXT
|
||||||
|
}
|
||||||
|
|
||||||
private fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code {
|
private fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code {
|
||||||
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
|
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
|
||||||
val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT
|
val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT
|
||||||
@@ -175,25 +206,28 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
interpretValueParameters(expression, data).also { if (it != Code.NEXT) return it }
|
interpretValueParameters(expression, data).also { if (it != Code.NEXT) return it }
|
||||||
val valueParameters = expression.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }
|
val valueParameters = expression.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }
|
||||||
|
|
||||||
val rawReceiver = expression.dispatchReceiver ?: expression.extensionReceiver
|
// dispatch receiver processing
|
||||||
rawReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
val rawDispatchReceiver = expression.dispatchReceiver
|
||||||
|
rawDispatchReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
||||||
|
val irCallReceiver = rawDispatchReceiver?.let { data.popReturnValue() }
|
||||||
|
val irFunctionReceiver = if (expression.superQualifierSymbol == null) irCallReceiver else (irCallReceiver as Complex).superType
|
||||||
|
// it is important firstly to add receiver, then arguments; this order is used in builtin method call
|
||||||
|
val irFunction = irFunctionReceiver?.getIrFunction(expression.symbol.descriptor) ?: expression.symbol.owner
|
||||||
|
irFunctionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getDispatchReceiver()!!, it)) }
|
||||||
|
|
||||||
|
// extension receiver processing
|
||||||
|
val rawExtensionReceiver = expression.extensionReceiver
|
||||||
|
rawExtensionReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it }
|
||||||
|
rawExtensionReceiver?.let { newFrame.addVar(Variable(irFunction.symbol.getExtensionReceiver()!!, data.popReturnValue())) }
|
||||||
|
|
||||||
val receiver = rawReceiver?.let { data.popReturnValue() }
|
|
||||||
val irFunction = receiver.getIrFunction(expression)
|
|
||||||
val receiverParameter = irFunction.symbol.getThisAsReceiver()
|
|
||||||
// it is important firstly to add receiver, then arguments
|
|
||||||
receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) }
|
|
||||||
newFrame.addAll(valueParameters)
|
newFrame.addAll(valueParameters)
|
||||||
|
|
||||||
val code = when {
|
val code = when {
|
||||||
//irFunction.annotations.any { it.descriptor.containingDeclaration.fqNameSafe == evaluateIntrinsicAnnotation } -> empty
|
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> calculateIntrinsic(irFunction, newFrame)
|
||||||
isBuiltIn(irFunction) -> calculateBuiltIns(expression, newFrame)
|
irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
|
||||||
expression.isAbstract() -> calculateAbstract(
|
irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
|
||||||
irFunction,
|
irFunction.body == null -> calculateBuiltIns(irFunction, newFrame)
|
||||||
newFrame
|
else -> irFunction.body!!.interpret(newFrame)
|
||||||
) //abstract check must be before fake overridden check
|
|
||||||
expression.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
|
|
||||||
else -> (irFunction.body ?: expression.getBody())!!.interpret(newFrame)
|
|
||||||
}
|
}
|
||||||
data.pushReturnValue(newFrame)
|
data.pushReturnValue(newFrame)
|
||||||
return code
|
return code
|
||||||
@@ -208,14 +242,17 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
||||||
val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT
|
val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT
|
||||||
if (newFrame.hasReturnValue()) {
|
if (newFrame.hasReturnValue()) {
|
||||||
state.setSuperQualifier(newFrame.popReturnValue() as Complex)
|
state.superType = newFrame.popReturnValue() as Complex
|
||||||
}
|
}
|
||||||
data.pushReturnValue(state)
|
data.pushReturnValue(state)
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code {
|
private fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code {
|
||||||
return interpretConstructor(constructorCall, data)
|
return interpretConstructor(constructorCall, data).apply {
|
||||||
|
val instance = data.peekReturnValue() as Complex
|
||||||
|
instance.setInstanceRecursive(instance)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code {
|
private fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code {
|
||||||
@@ -261,7 +298,7 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
var code = Code.NEXT
|
var code = Code.NEXT
|
||||||
while (code == Code.NEXT) {
|
while (code == Code.NEXT) {
|
||||||
code = expression.condition.interpret(data)
|
code = expression.condition.interpret(data)
|
||||||
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) {
|
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getValue() as? Boolean == true) {
|
||||||
code = expression.body?.interpret(data) ?: Code.NEXT
|
code = expression.body?.interpret(data) ?: Code.NEXT
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@@ -281,7 +318,7 @@ class IrInterpreter(private val irSymbols: Symbols<CommonBackendContext>) {
|
|||||||
|
|
||||||
private fun interpretBranch(expression: IrBranch, data: Frame): Code {
|
private fun interpretBranch(expression: IrBranch, data: Frame): Code {
|
||||||
var code = expression.condition.interpret(data)
|
var code = expression.condition.interpret(data)
|
||||||
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) {
|
if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getValue() as? Boolean == true) {
|
||||||
code = expression.result.interpret(data)
|
code = expression.result.interpret(data)
|
||||||
if (code == Code.NEXT) return Code.BREAK_WHEN
|
if (code == Code.NEXT) return Code.BREAK_WHEN
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-29
@@ -9,15 +9,22 @@ import org.jetbrains.kotlin.backend.common.interpreter.stack.Complex
|
|||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Primitive
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.State
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.State
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
// main purpose is to get receiver from constructor call
|
// main purpose is to get receiver from constructor call
|
||||||
@@ -25,14 +32,17 @@ fun IrMemberAccessExpression.getThisAsReceiver(): DeclarationDescriptor {
|
|||||||
return (this.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter
|
return (this.symbol.descriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrFunctionSymbol.getThisAsReceiver(): DeclarationDescriptor? {
|
fun IrFunctionSymbol.getDispatchReceiver(): DeclarationDescriptor? {
|
||||||
return (this.descriptor.containingDeclaration as? ClassDescriptor)?.thisAsReceiverParameter
|
return (this.descriptor.containingDeclaration as? ClassDescriptor)?.thisAsReceiverParameter
|
||||||
?: this.owner.extensionReceiverParameter?.descriptor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fun IrFunctionSymbol.getReceiverDescriptor(): DeclarationDescriptor? {
|
fun IrFunctionSymbol.getExtensionReceiver(): DeclarationDescriptor? {
|
||||||
return this.owner.dispatchReceiverParameter?.descriptor ?: this.owner.extensionReceiverParameter?.descriptor
|
return this.owner.extensionReceiverParameter?.descriptor
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
fun IrFunctionSymbol.getReceiver(): DeclarationDescriptor? {
|
||||||
|
return this.getDispatchReceiver() ?: this.getExtensionReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
fun IrFunctionAccessExpression.getBody(): IrBody? {
|
fun IrFunctionAccessExpression.getBody(): IrBody? {
|
||||||
return this.symbol.owner.body
|
return this.symbol.owner.body
|
||||||
@@ -52,7 +62,7 @@ private fun DeclarationDescriptor.isSubtypeOf(other: DeclarationDescriptor): Boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): Boolean {
|
private fun DeclarationDescriptor.hasSameNameAs(other: DeclarationDescriptor): Boolean {
|
||||||
return this is ValueParameterDescriptor && other is ValueParameterDescriptor && this.name == other.name
|
return this is VariableDescriptor && other is VariableDescriptor && this.name == other.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrCall.isAbstract(): Boolean {
|
fun IrCall.isAbstract(): Boolean {
|
||||||
@@ -63,45 +73,76 @@ fun IrCall.isFakeOverridden(): Boolean {
|
|||||||
return this.symbol.owner.isFakeOverride
|
return this.symbol.owner.isFakeOverride
|
||||||
}
|
}
|
||||||
|
|
||||||
fun State?.getIrFunction(expression: IrCall): IrFunction {
|
fun IrFunction.isAbstract(): Boolean {
|
||||||
return this.let { it?.getIrFunctionByName(expression.symbol.descriptor.name) } ?: expression.symbol.owner
|
return (this.symbol.owner as? IrSimpleFunction)?.modality == Modality.ABSTRACT
|
||||||
}
|
}
|
||||||
|
|
||||||
fun State.toIrExpression(expression: IrExpression): IrExpression {
|
fun IrFunction.isFakeOverridden(): Boolean {
|
||||||
|
return this.symbol.owner.isFakeOverride
|
||||||
|
}
|
||||||
|
|
||||||
|
fun State.toIrExpression(irBuiltIns: IrBuiltIns, expression: IrExpression): IrExpression {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Primitive<*> -> this.getIrConst().value.toIrConst(expression) // it is necessary to replace ir offsets
|
is Primitive<*> -> this.getValue().toIrConst( // this is necessary to replace ir offsets
|
||||||
|
irBuiltIns, expression.startOffset, expression.endOffset
|
||||||
|
)
|
||||||
else -> TODO("not supported")
|
else -> TODO("not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any?.toState(expression: IrExpression): State {
|
fun Any?.toState(irBuiltIns: IrBuiltIns): State {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Complex -> this
|
is Complex -> this
|
||||||
else -> this.toIrConst(expression).toPrimitive()
|
else -> this.toIrConst(irBuiltIns).toPrimitive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Any?.toIrConst(expression: IrExpression): IrConst<*> {
|
fun Any?.toIrConst(irBuiltIns: IrBuiltIns, startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET): IrConst<*> {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Boolean -> expression.copyParametersTo(IrConstKind.Boolean, this)
|
is Boolean -> IrConstImpl(startOffset, endOffset, irBuiltIns.booleanType, IrConstKind.Boolean, this)
|
||||||
is Char -> expression.copyParametersTo(IrConstKind.Char, this)
|
is Char -> IrConstImpl(startOffset, endOffset, irBuiltIns.charType, IrConstKind.Char, this)
|
||||||
is Byte -> expression.copyParametersTo(IrConstKind.Byte, this)
|
is Byte -> IrConstImpl(startOffset, endOffset, irBuiltIns.byteType, IrConstKind.Byte, this)
|
||||||
is Short -> expression.copyParametersTo(IrConstKind.Short, this)
|
is Short -> IrConstImpl(startOffset, endOffset, irBuiltIns.shortType, IrConstKind.Short, this)
|
||||||
is Int -> expression.copyParametersTo(IrConstKind.Int, this)
|
is Int -> IrConstImpl(startOffset, endOffset, irBuiltIns.intType, IrConstKind.Int, this)
|
||||||
is Long -> expression.copyParametersTo(IrConstKind.Long, this)
|
is Long -> IrConstImpl(startOffset, endOffset, irBuiltIns.longType, IrConstKind.Long, this)
|
||||||
is String -> expression.copyParametersTo(IrConstKind.String, this)
|
is String -> IrConstImpl(startOffset, endOffset, irBuiltIns.stringType, IrConstKind.String, this)
|
||||||
is Float -> expression.copyParametersTo(IrConstKind.Float, this)
|
is Float -> IrConstImpl(startOffset, endOffset, irBuiltIns.floatType, IrConstKind.Float, this)
|
||||||
is Double -> expression.copyParametersTo(IrConstKind.Double, this)
|
is Double -> IrConstImpl(startOffset, endOffset, irBuiltIns.doubleType, IrConstKind.Double, this)
|
||||||
null -> expression.copyParametersTo(IrConstKind.Null, this)
|
null -> IrConstImpl(startOffset, endOffset, irBuiltIns.nothingType, IrConstKind.Null, this)
|
||||||
else -> throw UnsupportedOperationException("Unsupported const element type $this")
|
else -> throw UnsupportedOperationException("Unsupported const element type $this")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
fun <T> IrConst<T>.toPrimitive(): Primitive<T> {
|
||||||
private fun <T> IrExpression.copyParametersTo(kind: IrConstKind<T>, value: Any?): IrConst<T> {
|
return Primitive(this.value, this.type)
|
||||||
return IrConstImpl(startOffset, endOffset, type, kind, value as T)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> IrConst<T>.toPrimitive(): Primitive<T> {
|
fun IrAnnotationContainer.hasAnnotation(annotation: FqName): Boolean {
|
||||||
return Primitive(this)
|
if (this.annotations.isNotEmpty()) {
|
||||||
|
return this.annotations.any { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation }
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrAnnotationContainer.getAnnotation(annotation: FqName): IrConstructorCall {
|
||||||
|
return this.annotations.first { it.symbol.descriptor.containingDeclaration.fqNameSafe == annotation }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPrimitiveClass(fqName: String): Class<*>? {
|
||||||
|
return when (fqName) {
|
||||||
|
"kotlin.Boolean" -> Boolean::class.java
|
||||||
|
"kotlin.Char" -> Char::class.java
|
||||||
|
"kotlin.Byte" -> Byte::class.java
|
||||||
|
"kotlin.Short" -> Short::class.java
|
||||||
|
"kotlin.Int" -> Int::class.java
|
||||||
|
"kotlin.Long" -> Long::class.java
|
||||||
|
"kotlin.String" -> String::class.java
|
||||||
|
"kotlin.Float" -> Float::class.java
|
||||||
|
"kotlin.Double" -> Double::class.java
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrType.getFqName(): String? {
|
||||||
|
return this.classOrNull?.owner?.fqNameForIrSerialization?.asString()
|
||||||
}
|
}
|
||||||
+10
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common.interpreter.builtins
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation")
|
val compileTimeAnnotation = FqName("kotlin.CompileTimeCalculation")
|
||||||
|
val evaluateIntrinsicAnnotation = FqName("kotlin.EvaluateIntrinsic")
|
||||||
|
|
||||||
data class CompileTimeFunction(val methodName: String, val args: List<String>)
|
data class CompileTimeFunction(val methodName: String, val args: List<String>)
|
||||||
|
|
||||||
@@ -24,3 +25,12 @@ fun <T, E> binaryOperation(
|
|||||||
): Pair<CompileTimeFunction, Function2<Any?, Any?, Any>> {
|
): Pair<CompileTimeFunction, Function2<Any?, Any?, Any>> {
|
||||||
return CompileTimeFunction(methodName, listOfNotNull(receiverType, parameterType)) to function as Function2<Any?, Any?, Any>
|
return CompileTimeFunction(methodName, listOfNotNull(receiverType, parameterType)) to function as Function2<Any?, Any?, Any>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T, E, R> ternaryOperation(
|
||||||
|
methodName: String, receiverType: String, firstParameterType: String, secondParameterType: String, function: (T, E, R) -> Any
|
||||||
|
): Pair<CompileTimeFunction, Function3<Any?, Any?, Any?, Any>> {
|
||||||
|
return CompileTimeFunction(
|
||||||
|
methodName, listOfNotNull(receiverType, firstParameterType, secondParameterType)
|
||||||
|
) to function as Function3<Any?, Any?, Any?, Any>
|
||||||
|
}
|
||||||
|
|||||||
+4
@@ -397,3 +397,7 @@ val binaryFunctions = mapOf<CompileTimeFunction, Function2<Any?, Any?, Any>>(
|
|||||||
binaryOperation<Boolean, Boolean>("ANDAND", "Boolean", "Boolean") { a, b -> a && b },
|
binaryOperation<Boolean, Boolean>("ANDAND", "Boolean", "Boolean") { a, b -> a && b },
|
||||||
binaryOperation<Boolean, Boolean>("OROR", "Boolean", "Boolean") { a, b -> a || b }
|
binaryOperation<Boolean, Boolean>("OROR", "Boolean", "Boolean") { a, b -> a || b }
|
||||||
)
|
)
|
||||||
|
val ternaryFunctions = mapOf<CompileTimeFunction, Function3<Any?, Any?, Any?, Any>>(
|
||||||
|
ternaryOperation<String, Int, Int>("subSequence", "String", "Int", "Int") { a, b, c -> a.subSequence(b, c) }
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
-2
@@ -29,9 +29,7 @@ interface Frame {
|
|||||||
fun pushReturnValue(state: State)
|
fun pushReturnValue(state: State)
|
||||||
fun pushReturnValue(frame: Frame)
|
fun pushReturnValue(frame: Frame)
|
||||||
fun peekReturnValue(): State
|
fun peekReturnValue(): State
|
||||||
//fun peekReturnValueOrNull(): State?
|
|
||||||
fun popReturnValue(): State
|
fun popReturnValue(): State
|
||||||
//fun popReturnValueOrNull(): State?
|
|
||||||
fun hasReturnValue(): Boolean
|
fun hasReturnValue(): Boolean
|
||||||
fun copy(): Frame
|
fun copy(): Frame
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-45
@@ -5,30 +5,49 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
package org.jetbrains.kotlin.backend.common.interpreter.stack
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.CompileTimeFunction
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.builtins.unaryFunctions
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
import org.jetbrains.kotlin.backend.common.interpreter.equalTo
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
fun getState(descriptor: DeclarationDescriptor): State?
|
val fields: MutableList<Variable>
|
||||||
fun setState(newVar: Variable)
|
|
||||||
fun copy(): State
|
|
||||||
fun getIrFunctionByName(name: Name): IrFunction?
|
|
||||||
}
|
|
||||||
|
|
||||||
class Primitive<T>(private var value: IrConst<T>) : State {
|
fun getState(descriptor: DeclarationDescriptor): State? {
|
||||||
fun getIrConst(): IrConst<T> {
|
return fields.firstOrNull { it.descriptor.equalTo(descriptor) }?.state
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getState(descriptor: DeclarationDescriptor): State {
|
fun setState(newVar: Variable)
|
||||||
throw UnsupportedOperationException("Only complex are allowed")
|
fun copy(): State
|
||||||
|
fun getIrFunction(descriptor: FunctionDescriptor): IrFunction?
|
||||||
|
}
|
||||||
|
|
||||||
|
class Primitive<T>(private var value: T, private val type: IrType?) : State {
|
||||||
|
override val fields: MutableList<Variable> = mutableListOf()
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (type != null) {
|
||||||
|
val properties = type.classOrNull!!.owner.declarations.filterIsInstance<IrProperty>()
|
||||||
|
for (property in properties) {
|
||||||
|
val propertySignature = CompileTimeFunction(property.name.asString(), listOf(type.getName()))
|
||||||
|
val propertyValue = unaryFunctions[propertySignature]?.invoke(value)
|
||||||
|
?: throw NoSuchMethodException("For given property $propertySignature there is no entry in unary map")
|
||||||
|
fields.add(Variable(property.descriptor, Primitive(propertyValue, null)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrType?.getName() = this?.classOrNull!!.owner.name.asString()
|
||||||
|
|
||||||
|
fun getValue(): T {
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setState(newVar: Variable) {
|
override fun setState(newVar: Variable) {
|
||||||
@@ -37,60 +56,57 @@ class Primitive<T>(private var value: IrConst<T>) : State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(): State {
|
override fun copy(): State {
|
||||||
return Primitive(value)
|
return Primitive(value, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getIrFunctionByName(name: Name): IrFunction? {
|
override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? {
|
||||||
//if (this.value.kind != IrConstKind.String) return null
|
if (type == null) return null
|
||||||
val declarations = value.type.classOrNull!!.owner.declarations.flatMap {
|
// must add property's getter to declaration's list because they are not present in ir class for primitives
|
||||||
when {
|
val declarations = type.classOrNull!!.owner.declarations.map { if (it is IrProperty) it.getter else it }
|
||||||
it is IrProperty -> listOf(it, it.getter)
|
return declarations.filterIsInstance<IrFunction>()
|
||||||
else -> listOf(it)
|
.filter { it.descriptor.name == descriptor.name }
|
||||||
}
|
.firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } }
|
||||||
}
|
|
||||||
return declarations.firstOrNull { it?.descriptor?.name == name } as? IrFunction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Primitive(value=${value.value})"
|
return "Primitive(value=$value, type=${type?.getName()})"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Complex(private var classOfObject: IrClass, private val values: MutableList<Variable>) : State {
|
class Complex(private var type: IrClass, override val fields: MutableList<Variable>) : State {
|
||||||
var superType: Complex? = null
|
var superType: Complex? = null
|
||||||
|
var instance: Complex? = null
|
||||||
|
|
||||||
fun setSuperQualifier(superType: Complex) {
|
fun setInstanceRecursive(instance: Complex) {
|
||||||
this.superType = superType
|
this.instance = instance
|
||||||
|
superType?.setInstanceRecursive(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSuperQualifier(): Complex? {
|
fun getReceiver(): DeclarationDescriptor {
|
||||||
return superType
|
return type.thisReceiver!!.descriptor
|
||||||
}
|
|
||||||
|
|
||||||
fun getThisReceiver(): DeclarationDescriptor {
|
|
||||||
return classOfObject.thisReceiver!!.descriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getIrFunctionByName(name: Name): IrFunction? {
|
|
||||||
return classOfObject.declarations.filterIsInstance<IrFunction>().firstOrNull { it.descriptor.name == name }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getState(descriptor: DeclarationDescriptor): State? {
|
|
||||||
return values.firstOrNull { it.descriptor.equalTo(descriptor) }?.state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setState(newVar: Variable) {
|
override fun setState(newVar: Variable) {
|
||||||
when (val oldState = values.firstOrNull { it.descriptor == newVar.descriptor }) {
|
when (val oldState = fields.firstOrNull { it.descriptor == newVar.descriptor }) {
|
||||||
null -> values.add(newVar) // newVar isn't present in value list
|
null -> fields.add(newVar) // newVar isn't present in value list
|
||||||
else -> values[values.indexOf(oldState)] = newVar // newVar already present
|
else -> fields[fields.indexOf(oldState)] = newVar // newVar already present
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getIrFunction(descriptor: FunctionDescriptor): IrFunction? {
|
||||||
|
return type.declarations.filterIsInstance<IrFunction>()
|
||||||
|
.filter { it.descriptor.name == descriptor.name }
|
||||||
|
.firstOrNull { it.descriptor.valueParameters.map { it.type } == descriptor.valueParameters.map { it.type } }
|
||||||
|
}
|
||||||
|
|
||||||
override fun copy(): State {
|
override fun copy(): State {
|
||||||
return Complex(classOfObject, values).apply { this@apply.superType = this@Complex.superType }
|
return Complex(type, fields).apply {
|
||||||
|
this@apply.superType = this@Complex.superType
|
||||||
|
this@apply.instance = this@Complex.instance
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Complex(obj='${classOfObject.fqNameForIrSerialization}', super=$superType, values=$values)"
|
return "Complex(obj='${type.fqNameForIrSerialization}', super=$superType, values=$fields)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ fun generateMap(): String {
|
|||||||
|
|
||||||
val unaryOperationsMap = mutableMapOf<CallableDescriptor, List<KotlinType>>()
|
val unaryOperationsMap = mutableMapOf<CallableDescriptor, List<KotlinType>>()
|
||||||
val binaryOperationsMap = mutableMapOf<CallableDescriptor, List<KotlinType>>()
|
val binaryOperationsMap = mutableMapOf<CallableDescriptor, List<KotlinType>>()
|
||||||
|
val ternaryOperationsMap = mutableMapOf<CallableDescriptor, List<KotlinType>>()
|
||||||
val builtIns = DefaultBuiltIns.Instance
|
val builtIns = DefaultBuiltIns.Instance
|
||||||
|
|
||||||
//save common built ins
|
//save common built ins
|
||||||
@@ -67,6 +68,7 @@ fun generateMap(): String {
|
|||||||
when (parametersTypes.size) {
|
when (parametersTypes.size) {
|
||||||
1 -> unaryOperationsMap[function] = parametersTypes
|
1 -> unaryOperationsMap[function] = parametersTypes
|
||||||
2 -> binaryOperationsMap[function] = parametersTypes
|
2 -> binaryOperationsMap[function] = parametersTypes
|
||||||
|
3 -> ternaryOperationsMap[function] = 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}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,6 +136,19 @@ fun generateMap(): String {
|
|||||||
p.println(binaryBody)
|
p.println(binaryBody)
|
||||||
p.println(")")
|
p.println(")")
|
||||||
|
|
||||||
|
p.println("val ternaryFunctions = mapOf<CompileTimeFunction, Function3<Any?, Any?, Any?, Any>>(")
|
||||||
|
val ternaryBody = ternaryOperationsMap.entries.joinToString(",\n") { (function, parameters) ->
|
||||||
|
val receiverType = parameters.last().toString()
|
||||||
|
val firstParameter = parameters[0].toString()
|
||||||
|
val secondParameter = parameters[1].toString()
|
||||||
|
val methodName = "${function.name}"
|
||||||
|
" ternaryOperation<$receiverType, $firstParameter, $secondParameter>" +
|
||||||
|
"(\"$methodName\", \"$receiverType\", \"$firstParameter\", \"$secondParameter\") { a, b, c -> a.$methodName(b, c) }"
|
||||||
|
}
|
||||||
|
p.println(ternaryBody)
|
||||||
|
p.println(")")
|
||||||
|
p.println()
|
||||||
|
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user