All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.ir.interpreter.Label.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 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.ir.interpreter

import org.jetbrains.kotlin.ir.interpreter.stack.Stack
import org.jetbrains.kotlin.ir.interpreter.state.Primitive
import org.jetbrains.kotlin.ir.interpreter.state.isSubtypeOf
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
import org.jetbrains.kotlin.ir.expressions.IrWhen
import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.render

enum class ReturnLabel {
    REGULAR, RETURN, BREAK_LOOP, BREAK_WHEN, CONTINUE, EXCEPTION
}

open class ExecutionResult(val returnLabel: ReturnLabel, private val owner: IrElement? = null) {
    fun getNextLabel(irElement: IrElement, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
        return when (returnLabel) {
            ReturnLabel.RETURN -> when (irElement) {
                is IrCall, is IrReturnableBlock, is IrSimpleFunction -> if (owner == irElement) Next else this
                else -> this
            }
            ReturnLabel.BREAK_WHEN -> when (irElement) {
                is IrWhen -> Next
                else -> this
            }
            ReturnLabel.BREAK_LOOP -> when (irElement) {
                is IrWhileLoop -> if (owner == irElement) Next else this
                else -> this
            }
            ReturnLabel.CONTINUE -> when (irElement) {
                is IrWhileLoop -> if (owner == irElement) irElement.interpret() else this
                else -> this
            }
            ReturnLabel.EXCEPTION -> Exception
            ReturnLabel.REGULAR -> Next
        }
    }

    fun addOwnerInfo(owner: IrElement): ExecutionResult {
        return ExecutionResult(returnLabel, owner)
    }
}

inline fun ExecutionResult.check(toCheckLabel: ReturnLabel = ReturnLabel.REGULAR, returnBlock: (ExecutionResult) -> Unit): ExecutionResult {
    if (this.returnLabel != toCheckLabel) returnBlock(this)
    return this
}

/**
 * This method is analog of `checkcast` jvm bytecode operation. Throw exception whenever actual type is not a subtype of expected.
 */
internal fun ExecutionResult.implicitCastIfNeeded(expectedType: IrType, actualType: IrType, stack: Stack): ExecutionResult {
    if (actualType.classifierOrNull !is IrTypeParameterSymbol) return this

    if (expectedType.classifierOrFail is IrTypeParameterSymbol) return this

    val actualState = stack.peekReturnValue()
    if (actualState is Primitive<*> && actualState.value == null) return this // this is handled as NullPointerException

    if (!actualState.isSubtypeOf(expectedType)) {
        val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
        throw ClassCastException("$convertibleClassName cannot be cast to ${expectedType.render()}")
    }
    return this
}

object Next : ExecutionResult(ReturnLabel.REGULAR)
object Return : ExecutionResult(ReturnLabel.RETURN)
object BreakLoop : ExecutionResult(ReturnLabel.BREAK_LOOP)
object BreakWhen : ExecutionResult(ReturnLabel.BREAK_WHEN)
object Continue : ExecutionResult(ReturnLabel.CONTINUE)
object Exception : ExecutionResult(ReturnLabel.EXCEPTION)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy