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

org.jetbrains.kotlinx.jupyter.codegen.FieldsProcessorImpl.kt Maven / Gradle / Ivy

There is a newer version: 0.12.0-356
Show newest version
package org.jetbrains.kotlinx.jupyter.codegen

import org.jetbrains.kotlinx.jupyter.api.Code
import org.jetbrains.kotlinx.jupyter.api.FieldHandler
import org.jetbrains.kotlinx.jupyter.api.FieldHandlerExecution
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
import org.jetbrains.kotlinx.jupyter.exceptions.LibraryProblemPart
import org.jetbrains.kotlinx.jupyter.exceptions.rethrowAsLibraryException
import org.jetbrains.kotlinx.jupyter.joinToLines
import org.jetbrains.kotlinx.jupyter.repl.ContextUpdater
import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty
import kotlin.reflect.full.withNullability
import kotlin.reflect.jvm.isAccessible

class FieldsProcessorImpl(
    private val contextUpdater: ContextUpdater,
) : FieldsProcessor {

    private val handlers = mutableListOf()

    override fun register(handler: FieldHandler) {
        handlers.add(handler)
    }

    override fun process(host: KotlinKernelHost): List {
        val conversionCodes = mutableMapOf, Code>()
        val initCodes = mutableListOf()
        val variablePlaceholder = "\$it"
        val tempFieldPrefix = "___"

        for (it in contextUpdater.context.vars.values.filter { !it.name.startsWith(tempFieldPrefix) }) {
            val property = it.descriptor
            property.isAccessible = true
            val value = it.value ?: continue
            val propertyType = property.returnType
            val notNullType = propertyType.withNullability(false)
            val handler = handlers.asIterable().firstOrNull { it.acceptsType(notNullType) }
            if (handler != null) {
                @Suppress("UNCHECKED_CAST")
                val execution = handler.execution as FieldHandlerExecution
                rethrowAsLibraryException(LibraryProblemPart.CONVERTERS) {
                    execution.execute(host, value, property)
                }
                continue
            }
            if (propertyType.isMarkedNullable) {
                conversionCodes[property] = "$variablePlaceholder!!"
            }
        }

        if (conversionCodes.isNotEmpty()) {
            val initCode = initCodes.joinToLines()
            val tempFieldsCode = conversionCodes
                .map { "val $tempFieldPrefix${it.key.name} = ${it.key.name}" }
                .joinToLines()

            val newFieldsCode = conversionCodes
                .mapValues { it.value.replace(variablePlaceholder, "$tempFieldPrefix${it.key.name}") }
                .map {
                    val valOrVar = if (it.key is KMutableProperty) "var" else "val"
                    "$valOrVar ${it.key.name} = ${it.value}"
                }
                .joinToLines()

            return listOf("$initCode\n$tempFieldsCode", newFieldsCode)
        }
        return emptyList()
    }
}