diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index 800f2eccde0..0aec814cc37 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -5,10 +5,12 @@ package org.jetbrains.kotlin.backend.common.interpreter +import org.jetbrains.kotlin.backend.common.CommonBackendContext 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.ir.Symbols import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement @@ -25,323 +27,330 @@ enum class Code(var info: String = "") { NEXT, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION } -fun interpret(expression: IrExpression): IrExpression { - return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression) -} +class IrInterpreter(private val irSymbols: Symbols) { -fun IrElement.interpret(data: Frame): Code { - try { - val code = when (this) { - is IrCall -> this.interpretCall(data) - is IrConstructorCall -> this.interpretConstructorCall(data) - is IrDelegatingConstructorCall -> this.interpretDelegatedConstructorCall(data) - is IrBody -> this.interpretBody(data) - is IrBlock -> this.interpretBlock(data) - is IrReturn -> this.interpretReturn(data) - is IrSetField -> this.interpretSetField(data) - is IrGetField -> this.interpretGetField(data) - is IrGetValue -> this.interpretGetValue(data) - is IrGetObjectValue -> this.interpretGetObjectValue(data) - is IrConst<*> -> this.interpretConst(data) - is IrVariable -> this.interpretVariable(data) - is IrSetVariable -> this.interpretSetVariable(data) - is IrTypeOperatorCall -> this.interpretTypeOperatorCall(data) - is IrBranch -> this.interpretBranch(data) - is IrWhileLoop -> this.interpretWhile(data) - is IrWhen -> this.interpretWhen(data) - is IrBreak -> this.interpretBreak(data) + fun interpret(expression: IrExpression): IrExpression { + return InterpreterFrame().apply { expression.interpret(this) }.popReturnValue().toIrExpression(expression) + } - else -> TODO("${this.javaClass} not supported") - } + private fun IrElement.interpret(data: Frame): Code { + try { + val code = when (this) { + is IrCall -> interpretCall(this, data) + is IrConstructorCall -> interpretConstructorCall(this, data) + is IrDelegatingConstructorCall -> interpretDelegatedConstructorCall(this, data) + is IrBody -> interpretBody(this, data) + is IrBlock -> interpretBlock(this, data) + is IrReturn -> interpretReturn(this, data) + is IrSetField -> interpretSetField(this, data) + is IrGetField -> interpretGetField(this, data) + is IrGetValue -> interpretGetValue(this, data) + is IrGetObjectValue -> interpretGetObjectValue(this, data) + is IrConst<*> -> interpretConst(this, data) + is IrVariable -> interpretVariable(this, data) + is IrSetVariable -> interpretSetVariable(this, data) + is IrTypeOperatorCall -> interpretTypeOperatorCall(this, data) + is IrBranch -> interpretBranch(this, data) + is IrWhileLoop -> interpretWhile(this, data) + is IrWhen -> interpretWhen(this, data) + is IrBreak -> interpretBreak(this, data) - return when (code) { - Code.RETURN -> when (this) { - is IrCall -> Code.NEXT - else -> Code.RETURN + else -> TODO("${this.javaClass} not supported") } - Code.BREAK_WHEN -> when (this) { - is IrWhen -> Code.NEXT - else -> code + + return when (code) { + Code.RETURN -> when (this) { + is IrCall -> Code.NEXT + else -> Code.RETURN + } + Code.BREAK_WHEN -> when (this) { + is IrWhen -> Code.NEXT + else -> code + } + Code.BREAK_LOOP -> when (this) { + is IrWhileLoop -> if ((this.label ?: "") == code.info) Code.NEXT else code + else -> code + } + Code.CONTINUE -> TODO("Code.CONTINUE not implemented") + Code.EXCEPTION -> TODO("Code.EXCEPTION not implemented") + Code.NEXT -> Code.NEXT } - Code.BREAK_LOOP -> when (this) { - is IrWhileLoop -> if ((this.label ?: "") == code.info) Code.NEXT else code - else -> code + } catch (e: Exception) { + e.printStackTrace() + assert(false) + return Code.EXCEPTION + } + } + + private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code { + return irFunction.body?.interpret(data) + ?: throw NoSuchMethodException("Method \"${irFunction.name}\" wasn't implemented") + } + + private fun calculateOverridden(owner: IrFunctionImpl, data: Frame): Code { + val variableDescriptor = owner.symbol.getThisAsReceiver()!! + val superQualifier = (data.getVariableState(variableDescriptor) as Complex).getSuperQualifier()!! + val overridden = owner.overriddenSymbols.first { it.getThisAsReceiver()?.equalTo(superQualifier.getThisReceiver()) == true } + + val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters) + .map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) } + val newStates = InterpreterFrame((valueParameters + Variable(superQualifier.getThisReceiver(), superQualifier)).toMutableList()) + + val overriddenOwner = overridden.owner as IrFunctionImpl + val body = overriddenOwner.body + return when { + body != null -> body.interpret(newStates) + else -> calculateOverridden(overriddenOwner, newStates) + }.apply { data.pushReturnValue(newStates) } + } + + private fun isBuiltIn(irFunction: IrFunction): Boolean { + val descriptor = irFunction.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 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() + .map { it.state } + .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } + .map { it.getIrConst().value } + val signature = CompileTimeFunction(methodName, argsType.map { it.toString() }) + //todo try catch + val result = when (argsType.size) { + 1 -> { + val function = unaryFunctions[signature] + ?: throw NoSuchMethodException("For given function $signature there is no entry in unary map") + function.invoke(argsValues.first()) } - Code.CONTINUE -> TODO("Code.CONTINUE not implemented") - Code.EXCEPTION -> TODO("Code.EXCEPTION not implemented") - Code.NEXT -> Code.NEXT - } - } catch (e: Exception) { - e.printStackTrace() - assert(false) - return Code.EXCEPTION - } -} - -private fun calculateAbstract(irFunction: IrFunction, data: Frame): Code { - return irFunction.body?.interpret(data) - ?: throw NoSuchMethodException("Method \"${irFunction.name}\" wasn't implemented") -} - -private fun calculateOverridden(owner: IrFunctionImpl, data: Frame): Code { - val variableDescriptor = owner.symbol.getThisAsReceiver()!! - val superQualifier = (data.getVariableState(variableDescriptor) as Complex).getSuperQualifier()!! - val overridden = owner.overriddenSymbols.first { it.getThisAsReceiver()?.equalTo(superQualifier.getThisReceiver()) == true } - - val valueParameters = owner.valueParameters.zip(overridden.owner.valueParameters) - .map { Variable(it.second.descriptor, data.getVariableState(it.first.descriptor)) } - val newStates = InterpreterFrame((valueParameters + Variable(superQualifier.getThisReceiver(), superQualifier)).toMutableList()) - - val overriddenOwner = overridden.owner as IrFunctionImpl - val body = overriddenOwner.body - return when { - body != null -> body.interpret(newStates) - else -> calculateOverridden(overriddenOwner, newStates) - }.apply { data.pushReturnValue(newStates) } -} - -private fun isBuiltIn(irFunction: IrFunction): Boolean { - val descriptor = irFunction.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 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() - .map { it.state } - .map { it as? Primitive<*> ?: throw IllegalArgumentException("Builtin functions accept only const args") } - .map { it.getIrConst().value } - val signature = CompileTimeFunction(methodName, argsType.map { it.toString() }) - //todo try catch - val result = when (argsType.size) { - 1 -> { - val function = unaryFunctions[signature] - ?: throw NoSuchMethodException("For given function $signature there is no entry in unary map") - function.invoke(argsValues.first()) - } - 2 -> { - val function = binaryFunctions[signature] - ?: throw NoSuchMethodException("For given function $signature there is no entry in binary map") - when (methodName) { - "rangeTo" -> return calculateRangeTo(expression, data) - else -> function.invoke(argsValues[0], argsValues[1]) + 2 -> { + val function = binaryFunctions[signature] + ?: throw NoSuchMethodException("For given function $signature there is no entry in binary map") + when (methodName) { + "rangeTo" -> return calculateRangeTo(expression, data) + else -> function.invoke(argsValues[0], argsValues[1]) + } } + else -> throw UnsupportedOperationException("Unsupported number of arguments") } - else -> throw UnsupportedOperationException("Unsupported number of arguments") - } - data.pushReturnValue(result.toState(expression)) - return Code.NEXT -} - -private fun calculateRangeTo(expression: IrExpression, data: Frame): Code { - val constructor = expression.type.classOrNull!!.owner.constructors.first() - val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) - - val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> } - primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) } - - val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters) - val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList()) - - val code = constructorCall.interpret(newFrame) - data.pushReturnValue(newFrame) - return code -} - -fun IrMemberAccessExpression.interpretValueParameters(data: Frame): Code { - for (i in (this.valueArgumentsCount - 1) downTo 0) { - val code = this.getValueArgument(i)?.interpret(data) ?: Code.NEXT - if (code != Code.NEXT) return code - } - return Code.NEXT -} - -fun IrCall.interpretCall(data: Frame): Code { - val newFrame = InterpreterFrame() - - this.interpretValueParameters(data).also { if (it != Code.NEXT) return it } - val valueParameters = this.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) } - - val rawReceiver = this.dispatchReceiver ?: this.extensionReceiver - rawReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it } - - val receiver = rawReceiver?.let { data.popReturnValue() } - val irFunction = receiver.getIrFunction(this) - val receiverParameter = irFunction.symbol.getThisAsReceiver() - // it is important firstly to add receiver, then arguments - receiver?.let { newFrame.addVar(Variable(receiverParameter!!, it)) } - newFrame.addAll(valueParameters) - - val code = when { - //irFunction.annotations.any { it.descriptor.containingDeclaration.fqNameSafe == evaluateIntrinsicAnnotation } -> empty - isBuiltIn(irFunction) -> calculateBuiltIns(this, newFrame) - this.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check - this.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) - else -> (irFunction.body ?: this.getBody())!!.interpret(newFrame) - } - data.pushReturnValue(newFrame) - return code -} - -fun IrFunctionAccessExpression.interpretConstructor(data: Frame): Code { - this.interpretValueParameters(data).also { if (it != Code.NEXT) return it } - val valueParameters = this.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList() - - val newFrame = InterpreterFrame(valueParameters) - val state = Complex(this.symbol.owner.parent as IrClass, mutableListOf()) - newFrame.addVar(Variable(this.getThisAsReceiver(), state)) //used to set up fields in body - val code = this.getBody()?.interpret(newFrame) ?: Code.NEXT - if (newFrame.hasReturnValue()) { - state.setSuperQualifier(newFrame.popReturnValue() as Complex) - } - data.pushReturnValue(state) - return code -} - -fun IrConstructorCall.interpretConstructorCall(data: Frame): Code { - return this.interpretConstructor(data) -} - -fun IrDelegatingConstructorCall.interpretDelegatedConstructorCall(data: Frame): Code { - if (this.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) { + data.pushReturnValue(result.toState(expression)) return Code.NEXT } - return this.interpretConstructor(data) -} + private fun calculateRangeTo(expression: IrExpression, data: Frame): Code { + val constructor = expression.type.classOrNull!!.owner.constructors.first() + val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) -fun IrConst<*>.interpretConst(data: Frame): Code { - data.pushReturnValue(this.toPrimitive()) - return Code.NEXT -} + val primitiveValueParameters = data.getAll().map { it.state as Primitive<*> } + primitiveValueParameters.forEachIndexed { index, primitive -> constructorCall.putValueArgument(index, primitive.getIrConst()) } -fun List.interpretStatements(data: Frame): Code { - //create newFrame - val newFrame = data.copy() + val constructorValueParameters = constructor.valueParameters.map { it.descriptor }.zip(primitiveValueParameters) + val newFrame = InterpreterFrame(constructorValueParameters.map { Variable(it.first, it.second) }.toMutableList()) - var code = Code.NEXT - val iterator = this.asSequence().iterator() - while (code == Code.NEXT && iterator.hasNext()) { - code = iterator.next().interpret(newFrame) + val code = constructorCall.interpret(newFrame) + data.pushReturnValue(newFrame) + return code } - data.pushReturnValue(newFrame) - return code -} -fun IrBlock.interpretBlock(data: Frame): Code { - return this.statements.interpretStatements(data) -} + private fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code { + for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) { + val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT + if (code != Code.NEXT) return code + } + return Code.NEXT + } -fun IrBody.interpretBody(data: Frame): Code { - return this.statements.interpretStatements(data) -} + private fun interpretCall(expression: IrCall, data: Frame): Code { + val newFrame = InterpreterFrame() -fun IrReturn.interpretReturn(data: Frame): Code { - val code = this.value.interpret(data) - return if (code == Code.NEXT) Code.RETURN else code -} + interpretValueParameters(expression, data).also { if (it != Code.NEXT) return it } + val valueParameters = expression.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) } -fun IrWhileLoop.interpretWhile(data: Frame): Code { - var code = Code.NEXT - while (code == Code.NEXT) { - code = this.condition.interpret(data) + val rawReceiver = expression.dispatchReceiver ?: expression.extensionReceiver + rawReceiver?.interpret(data)?.also { if (it != Code.NEXT) return it } + + 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) + + val code = when { + //irFunction.annotations.any { it.descriptor.containingDeclaration.fqNameSafe == evaluateIntrinsicAnnotation } -> empty + isBuiltIn(irFunction) -> calculateBuiltIns(expression, newFrame) + expression.isAbstract() -> calculateAbstract( + irFunction, + 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) + return code + } + + private fun interpretConstructor(constructorCall: IrFunctionAccessExpression, data: Frame): Code { + interpretValueParameters(constructorCall, data).also { if (it != Code.NEXT) return it } + val valueParameters = constructorCall.symbol.descriptor.valueParameters.map { Variable(it, data.popReturnValue()) }.toMutableList() + + val newFrame = InterpreterFrame(valueParameters) + val state = Complex(constructorCall.symbol.owner.parent as IrClass, mutableListOf()) + newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body + val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT + if (newFrame.hasReturnValue()) { + state.setSuperQualifier(newFrame.popReturnValue() as Complex) + } + data.pushReturnValue(state) + return code + } + + private fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code { + return interpretConstructor(constructorCall, data) + } + + private fun interpretDelegatedConstructorCall(delegatingConstructorCall: IrDelegatingConstructorCall, data: Frame): Code { + if (delegatingConstructorCall.symbol.descriptor.containingDeclaration.defaultType == DefaultBuiltIns.Instance.anyType) { + return Code.NEXT + } + + return interpretConstructor(delegatingConstructorCall, data) + } + + private fun interpretConst(expression: IrConst<*>, data: Frame): Code { + data.pushReturnValue(expression.toPrimitive()) + return Code.NEXT + } + + private fun interpretStatements(statements: List, data: Frame): Code { + //create newFrame + val newFrame = data.copy() + + var code = Code.NEXT + val iterator = statements.asSequence().iterator() + while (code == Code.NEXT && iterator.hasNext()) { + code = iterator.next().interpret(newFrame) + } + data.pushReturnValue(newFrame) + return code + } + + private fun interpretBlock(block: IrBlock, data: Frame): Code { + return interpretStatements(block.statements, data) + } + + private fun interpretBody(body: IrBody, data: Frame): Code { + return interpretStatements(body.statements, data) + } + + private fun interpretReturn(expression: IrReturn, data: Frame): Code { + val code = expression.value.interpret(data) + return if (code == Code.NEXT) Code.RETURN else code + } + + private fun interpretWhile(expression: IrWhileLoop, data: Frame): Code { + var code = Code.NEXT + while (code == Code.NEXT) { + code = expression.condition.interpret(data) + if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) { + code = expression.body?.interpret(data) ?: Code.NEXT + } else { + break + } + } + return code + } + + private fun interpretWhen(expression: IrWhen, data: Frame): Code { + var code = Code.NEXT + val iterator = expression.branches.asSequence().iterator() + while (code == Code.NEXT && iterator.hasNext()) { + code = iterator.next().interpret(data) + } + return code + } + + private fun interpretBranch(expression: IrBranch, data: Frame): Code { + var code = expression.condition.interpret(data) if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) { - code = this.body?.interpret(data) ?: Code.NEXT + code = expression.result.interpret(data) + if (code == Code.NEXT) return Code.BREAK_WHEN + } + return code + } + + private fun interpretBreak(breakStatement: IrBreak, data: Frame): Code { + return Code.BREAK_LOOP.apply { info = breakStatement.label ?: "" } + } + + private fun interpretSetField(expression: IrSetField, data: Frame): Code { + val code = expression.value.interpret(data) + if (code != Code.NEXT) return code + + val receiver = (expression.receiver as IrDeclarationReference).symbol.descriptor + data.getVariableState(receiver).setState(Variable(expression.symbol.owner.descriptor, data.popReturnValue())) + return Code.NEXT + } + + private fun interpretGetField(expression: IrGetField, data: Frame): Code { + val receiver = (expression.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields + val result = receiver?.let { data.getVariableState(receiver).getState(expression.symbol.descriptor)?.copy() } + if (result == null) { + return expression.symbol.owner.initializer?.expression?.interpret(data) ?: Code.NEXT + } + data.pushReturnValue(result) + return Code.NEXT + } + + private fun interpretGetValue(expression: IrGetValue, data: Frame): Code { + data.pushReturnValue(data.getVariableState(expression.symbol.descriptor).copy()) + return Code.NEXT + } + + private fun interpretVariable(expression: IrVariable, data: Frame): Code { + val code = expression.initializer?.interpret(data) + if (code != Code.NEXT) return code ?: Code.NEXT + data.addVar(Variable(expression.descriptor, data.popReturnValue())) + return Code.NEXT + } + + private fun interpretSetVariable(expression: IrSetVariable, data: Frame): Code { + val code = expression.value.interpret(data) + if (code != Code.NEXT) return code + + if (data.contains(expression.symbol.descriptor)) { + val variable = data.getVariableState(expression.symbol.descriptor) + variable.setState(Variable(expression.symbol.descriptor, data.popReturnValue())) } else { - break + data.addVar(Variable(expression.symbol.descriptor, data.popReturnValue())) + } + return Code.NEXT + } + + private fun interpretGetObjectValue(expression: IrGetObjectValue, data: Frame): Code { + data.pushReturnValue(Complex(expression.symbol.owner, mutableListOf())) + return Code.NEXT + } + + private fun interpretTypeOperatorCall(expression: IrTypeOperatorCall, data: Frame): Code { + return when (expression.operator) { + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { + expression.argument.interpret(data) + } + IrTypeOperator.CAST -> { + expression.argument.interpret(data) //todo check cast correctness + } + else -> TODO("${expression.operator} not implemented") } } - return code -} -fun IrWhen.interpretWhen(data: Frame): Code { - var code = Code.NEXT - val iterator = this.branches.asSequence().iterator() - while (code == Code.NEXT && iterator.hasNext()) { - code = iterator.next().interpret(data) - } - return code -} - -fun IrBranch.interpretBranch(data: Frame): Code { - var code = this.condition.interpret(data) - if (code == Code.NEXT && (data.popReturnValue() as? Primitive<*>)?.getIrConst()?.value as? Boolean == true) { - code = this.result.interpret(data) - if (code == Code.NEXT) return Code.BREAK_WHEN - } - return code -} - -fun IrBreak.interpretBreak(data: Frame): Code { - return Code.BREAK_LOOP.apply { info = this@interpretBreak.label ?: "" } -} - -fun IrSetField.interpretSetField(data: Frame): Code { - val code = this.value.interpret(data) - if (code != Code.NEXT) return code - - val receiver = (this.receiver as IrDeclarationReference).symbol.descriptor - data.getVariableState(receiver).setState(Variable(this.symbol.owner.descriptor, data.popReturnValue())) - return Code.NEXT -} - -fun IrGetField.interpretGetField(data: Frame): Code { - val receiver = (this.receiver as? IrDeclarationReference)?.symbol?.descriptor // receiver is null, for example, for top level fields - val result = receiver?.let { data.getVariableState(receiver).getState(this.symbol.descriptor)?.copy() } - if (result == null) { - return this.symbol.owner.initializer?.expression?.interpret(data) ?: Code.NEXT - } - data.pushReturnValue(result) - return Code.NEXT -} - -fun IrGetValue.interpretGetValue(data: Frame): Code { - data.pushReturnValue(data.getVariableState(this.symbol.descriptor).copy()) - return Code.NEXT -} - -fun IrVariable.interpretVariable(data: Frame): Code { - val code = this.initializer?.interpret(data) - if (code != Code.NEXT) return code ?: Code.NEXT - data.addVar(Variable(this.descriptor, data.popReturnValue())) - return Code.NEXT -} - -fun IrSetVariable.interpretSetVariable(data: Frame): Code { - val code = this.value.interpret(data) - if (code != Code.NEXT) return code - - if (data.contains(this.symbol.descriptor)) { - val variable = data.getVariableState(this.symbol.descriptor) - variable.setState(Variable(this.symbol.descriptor, data.popReturnValue())) - } else { - data.addVar(Variable(this.symbol.descriptor, data.popReturnValue())) - } - return Code.NEXT -} - -fun IrGetObjectValue.interpretGetObjectValue(data: Frame): Code { - data.pushReturnValue(Complex(this.symbol.owner, mutableListOf())) - return Code.NEXT -} - -fun IrTypeOperatorCall.interpretTypeOperatorCall(data: Frame): Code { - return when (this.operator) { - IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { - this.argument.interpret(data) - } - IrTypeOperator.CAST -> { - this.argument.interpret(data) //todo check cast correctness - } - else -> TODO("${this.operator} not implemented") - } } \ No newline at end of file