
org.jetbrains.kotlinx.jupyter.repl.kt Maven / Gradle / Ivy
package org.jetbrains.kotlinx.jupyter
import jupyter.kotlin.CompilerArgs
import jupyter.kotlin.DependsOn
import jupyter.kotlin.KotlinContext
import jupyter.kotlin.Repository
import jupyter.kotlin.generateHTMLVarsReport
import jupyter.kotlin.providers.UserHandlesProvider
import jupyter.kotlin.variablesReport
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlinx.jupyter.api.Code
import org.jetbrains.kotlinx.jupyter.api.ExecutionCallback
import org.jetbrains.kotlinx.jupyter.api.JupyterClientType
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelVersion
import org.jetbrains.kotlinx.jupyter.api.NullabilityEraser
import org.jetbrains.kotlinx.jupyter.api.ProcessingPriority
import org.jetbrains.kotlinx.jupyter.api.Renderable
import org.jetbrains.kotlinx.jupyter.api.SessionOptions
import org.jetbrains.kotlinx.jupyter.codegen.ClassAnnotationsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.ClassAnnotationsProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.FieldsProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.FieldsProcessorInternal
import org.jetbrains.kotlinx.jupyter.codegen.FileAnnotationsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.FileAnnotationsProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.RenderersProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.ResultsRenderersProcessor
import org.jetbrains.kotlinx.jupyter.codegen.TextRenderersProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.TextRenderersProcessorWithPreventingRecursion
import org.jetbrains.kotlinx.jupyter.codegen.ThrowableRenderersProcessor
import org.jetbrains.kotlinx.jupyter.codegen.ThrowableRenderersProcessorImpl
import org.jetbrains.kotlinx.jupyter.common.looksLikeReplCommand
import org.jetbrains.kotlinx.jupyter.compiler.CompilerArgsConfigurator
import org.jetbrains.kotlinx.jupyter.compiler.DefaultCompilerArgsConfigurator
import org.jetbrains.kotlinx.jupyter.compiler.ScriptDeclarationsCollectorInternal
import org.jetbrains.kotlinx.jupyter.compiler.ScriptImportsCollector
import org.jetbrains.kotlinx.jupyter.compiler.util.Classpath
import org.jetbrains.kotlinx.jupyter.compiler.util.EvaluatedSnippetMetadata
import org.jetbrains.kotlinx.jupyter.compiler.util.SerializedCompiledScriptsData
import org.jetbrains.kotlinx.jupyter.config.catchAll
import org.jetbrains.kotlinx.jupyter.config.getCompilationConfiguration
import org.jetbrains.kotlinx.jupyter.dependencies.JupyterScriptDependenciesResolver
import org.jetbrains.kotlinx.jupyter.dependencies.JupyterScriptDependenciesResolverImpl
import org.jetbrains.kotlinx.jupyter.dependencies.ScriptDependencyAnnotationHandlerImpl
import org.jetbrains.kotlinx.jupyter.execution.ColorSchemeChangeCallbacksProcessor
import org.jetbrains.kotlinx.jupyter.execution.InterruptionCallbacksProcessor
import org.jetbrains.kotlinx.jupyter.libraries.KERNEL_LIBRARIES
import org.jetbrains.kotlinx.jupyter.libraries.LibrariesProcessor
import org.jetbrains.kotlinx.jupyter.libraries.LibrariesProcessorImpl
import org.jetbrains.kotlinx.jupyter.libraries.LibrariesScanner
import org.jetbrains.kotlinx.jupyter.libraries.LibraryDescriptorsProvider
import org.jetbrains.kotlinx.jupyter.libraries.LibraryResolver
import org.jetbrains.kotlinx.jupyter.libraries.LibraryResourcesProcessorImpl
import org.jetbrains.kotlinx.jupyter.libraries.ResolutionInfoProvider
import org.jetbrains.kotlinx.jupyter.libraries.getDefaultResolutionInfoSwitcher
import org.jetbrains.kotlinx.jupyter.magics.CompletionMagicsProcessor
import org.jetbrains.kotlinx.jupyter.magics.CompoundCodePreprocessor
import org.jetbrains.kotlinx.jupyter.magics.ErrorsMagicsProcessor
import org.jetbrains.kotlinx.jupyter.magics.FullMagicsHandler
import org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor
import org.jetbrains.kotlinx.jupyter.messaging.DisplayHandler
import org.jetbrains.kotlinx.jupyter.messaging.NoOpDisplayHandler
import org.jetbrains.kotlinx.jupyter.repl.CellExecutor
import org.jetbrains.kotlinx.jupyter.repl.CompletionResult
import org.jetbrains.kotlinx.jupyter.repl.ContextUpdater
import org.jetbrains.kotlinx.jupyter.repl.EvalResultEx
import org.jetbrains.kotlinx.jupyter.repl.InternalEvaluator
import org.jetbrains.kotlinx.jupyter.repl.InternalVariablesMarkersProcessor
import org.jetbrains.kotlinx.jupyter.repl.KotlinCompleter
import org.jetbrains.kotlinx.jupyter.repl.ListErrorsResult
import org.jetbrains.kotlinx.jupyter.repl.ShutdownEvalResult
import org.jetbrains.kotlinx.jupyter.repl.impl.AfterCellExecutionsProcessor
import org.jetbrains.kotlinx.jupyter.repl.impl.BaseKernelHost
import org.jetbrains.kotlinx.jupyter.repl.impl.BeforeCellExecutionsProcessor
import org.jetbrains.kotlinx.jupyter.repl.impl.CellExecutorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.ColorSchemeChangeCallbacksProcessorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.InternalEvaluatorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.InternalVariablesMarkersProcessorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.InterruptionCallbacksProcessorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.JupyterCompilerWithCompletion
import org.jetbrains.kotlinx.jupyter.repl.impl.ScriptDeclarationsCollectorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.ScriptImportsCollectorImpl
import org.jetbrains.kotlinx.jupyter.repl.impl.SharedReplContext
import org.jetbrains.kotlinx.jupyter.repl.impl.ShutdownExecutionsProcessor
import org.jetbrains.kotlinx.jupyter.repl.postRender
import org.jetbrains.kotlinx.jupyter.repl.workflow.ExecutorWorkflowListener
import java.io.File
import java.net.URLClassLoader
import java.util.concurrent.atomic.AtomicReference
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
import kotlin.script.experimental.api.asSuccess
import kotlin.script.experimental.api.constructorArgs
import kotlin.script.experimental.api.dependencies
import kotlin.script.experimental.api.fileExtension
import kotlin.script.experimental.api.implicitReceivers
import kotlin.script.experimental.api.refineConfiguration
import kotlin.script.experimental.api.with
import kotlin.script.experimental.dependencies.RepositoryCoordinates
import kotlin.script.experimental.jvm.BasicJvmReplEvaluator
import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.baseClassLoader
import kotlin.script.experimental.jvm.jvm
data class CheckResult(val isComplete: Boolean = true)
class EvalRequestData(
val code: Code,
val jupyterId: Int = -1,
val storeHistory: Boolean = true,
@Suppress("UNUSED")
val isSilent: Boolean = false,
)
enum class ExecutedCodeLogging {
OFF,
ALL,
GENERATED
}
interface ReplRuntimeProperties {
val version: KotlinKernelVersion?
@Deprecated("This parameter is meaningless, do not use")
val librariesFormatVersion: Int
val currentBranch: String
val currentSha: String
val jvmTargetForSnippets: String
}
interface ReplOptions {
val currentBranch: String
val librariesDir: File
var trackClasspath: Boolean
var executedCodeLogging: ExecutedCodeLogging
var writeCompiledClasses: Boolean
var outputConfig: OutputConfig
val debugPort: Int?
}
interface ReplForJupyter {
fun eval(execution: ExecutionCallback): T
fun evalEx(evalData: EvalRequestData): EvalResultEx
fun evalOnShutdown(): List
fun checkComplete(code: Code): CheckResult
suspend fun complete(code: Code, cursor: Int, callback: (CompletionResult) -> Unit)
suspend fun listErrors(code: Code, callback: (ListErrorsResult) -> Unit)
val homeDir: File?
val currentClasspath: Collection
val currentClassLoader: ClassLoader
val mavenRepositories: List
val libraryResolver: LibraryResolver?
val librariesScanner: LibrariesScanner
val libraryDescriptorsProvider: LibraryDescriptorsProvider
val runtimeProperties: ReplRuntimeProperties
val resolutionInfoProvider: ResolutionInfoProvider
val throwableRenderersProcessor: ThrowableRenderersProcessor
var outputConfig: OutputConfig
val notebook: MutableNotebook
val displayHandler: DisplayHandler
val fileExtension: String
val isEmbedded: Boolean
get() = false
}
class ReplForJupyterImpl(
override val resolutionInfoProvider: ResolutionInfoProvider,
override val displayHandler: DisplayHandler = NoOpDisplayHandler,
private val scriptClasspath: List = emptyList(),
override val homeDir: File? = null,
override val mavenRepositories: List = listOf(),
override val libraryResolver: LibraryResolver? = null,
override val runtimeProperties: ReplRuntimeProperties = defaultRuntimeProperties,
private val scriptReceivers: List = emptyList(),
override val isEmbedded: Boolean = false,
override val notebook: MutableNotebook,
override val librariesScanner: LibrariesScanner,
override val debugPort: Int? = null
) : ReplForJupyter, ReplOptions, BaseKernelHost, UserHandlesProvider {
override val currentBranch: String
get() = runtimeProperties.currentBranch
override val librariesDir: File = KERNEL_LIBRARIES.homeLibrariesDir(homeDir)
private val libraryInfoSwitcher = getDefaultResolutionInfoSwitcher(
resolutionInfoProvider,
librariesDir,
currentBranch
)
private val parseOutCellMagic = notebook.jupyterClientType == JupyterClientType.KOTLIN_NOTEBOOK
private var outputConfigImpl = OutputConfig()
private var currentKernelHost: KotlinKernelHost? = null
private val resourcesProcessor = LibraryResourcesProcessorImpl()
override val sessionOptions: SessionOptions = object : SessionOptions {
override var resolveSources: Boolean
get() = resolver.resolveSources
set(value) { resolver.resolveSources = value }
override var resolveMpp: Boolean
get() = resolver.resolveMpp
set(value) { resolver.resolveMpp = value }
override var serializeScriptData: Boolean
get() = internalEvaluator.serializeScriptData
set(value) { internalEvaluator.serializeScriptData = value }
}
override var outputConfig
get() = outputConfigImpl
set(value) {
// reuse output config instance, because it is already passed to CapturingOutputStream and stream parameters should be updated immediately
outputConfigImpl.update(value)
}
override var trackClasspath: Boolean = false
private var _executedCodeLogging: ExecutedCodeLogging = ExecutedCodeLogging.OFF
override var executedCodeLogging: ExecutedCodeLogging
get() = _executedCodeLogging
set(value) {
_executedCodeLogging = value
internalEvaluator.logExecution = value != ExecutedCodeLogging.OFF
}
override var writeCompiledClasses: Boolean
get() = internalEvaluator.writeCompiledClasses
set(value) {
internalEvaluator.writeCompiledClasses = value
}
private val internalVariablesMarkersProcessor: InternalVariablesMarkersProcessor = InternalVariablesMarkersProcessorImpl()
private val resolver: JupyterScriptDependenciesResolver = JupyterScriptDependenciesResolverImpl(mavenRepositories)
private val ctx = KotlinContext()
private val compilerArgsConfigurator: CompilerArgsConfigurator = DefaultCompilerArgsConfigurator(
runtimeProperties.jvmTargetForSnippets
)
private val librariesProcessor: LibrariesProcessor = LibrariesProcessorImpl(libraryResolver, runtimeProperties.version)
private val magics = MagicsProcessor(
FullMagicsHandler(
this,
librariesProcessor,
libraryInfoSwitcher,
),
parseOutCellMagic
)
override val libraryDescriptorsProvider = run {
val provider = HomeDirLibraryDescriptorsProvider(homeDir)
if (libraryResolver != null) {
LibraryDescriptorsByResolutionProvider(provider, libraryResolver)
} else {
provider
}
}
private val completionMagics = CompletionMagicsProcessor(libraryDescriptorsProvider, parseOutCellMagic)
private val errorsMagics = ErrorsMagicsProcessor(parseOutCellMagic)
private val codePreprocessor = CompoundCodePreprocessor(magics)
private val importsCollector: ScriptImportsCollector = ScriptImportsCollectorImpl()
private val declarationsCollector: ScriptDeclarationsCollectorInternal = ScriptDeclarationsCollectorImpl()
// Used for various purposes, i.e. completion and listing errors
private val compilerConfiguration: ScriptCompilationConfiguration =
getCompilationConfiguration(
scriptClasspath,
scriptReceivers,
compilerArgsConfigurator,
scriptDataCollectors = listOf(importsCollector, declarationsCollector)
).with {
refineConfiguration {
onAnnotations(DependsOn::class, Repository::class, CompilerArgs::class, handler = ::onAnnotationsHandler)
}
}
override val fileExtension: String
get() = compilerConfiguration[ScriptCompilationConfiguration.fileExtension]!!
private val ScriptCompilationConfiguration.classpath
get() = this[ScriptCompilationConfiguration.dependencies]
?.filterIsInstance()
?.flatMap { it.classpath }
.orEmpty()
override val currentClasspath = compilerConfiguration.classpath.map { it.canonicalPath }.toMutableSet()
private val currentSources = mutableSetOf()
private class FilteringClassLoader(parent: ClassLoader, val includeFilter: (String) -> Boolean) :
ClassLoader(parent) {
override fun loadClass(name: String?, resolve: Boolean): Class<*> {
val c = if (name != null && includeFilter(name)) {
parent.loadClass(name)
} else parent.parent.loadClass(name)
if (resolve) {
resolveClass(c)
}
return c
}
}
private val evaluatorConfiguration = ScriptEvaluationConfiguration {
implicitReceivers.invoke(v = scriptReceivers)
if (!isEmbedded) {
jvm {
val filteringClassLoader = FilteringClassLoader(ClassLoader.getSystemClassLoader()) { fqn ->
listOf(
"jupyter.kotlin.",
"org.jetbrains.kotlinx.jupyter.api",
"kotlin.",
"kotlinx.serialization.",
).any { fqn.startsWith(it) } ||
(fqn.startsWith("org.jetbrains.kotlin.") && !fqn.startsWith("org.jetbrains.kotlinx.jupyter."))
}
val scriptClassloader =
URLClassLoader(scriptClasspath.map { it.toURI().toURL() }.toTypedArray(), filteringClassLoader)
baseClassLoader(scriptClassloader)
}
}
constructorArgs(this@ReplForJupyterImpl)
}
private val jupyterCompiler by lazy {
JupyterCompilerWithCompletion.create(compilerConfiguration, evaluatorConfiguration)
}
private val evaluator: BasicJvmReplEvaluator by lazy {
BasicJvmReplEvaluator()
}
private val completer = KotlinCompleter()
private val contextUpdater = ContextUpdater(ctx, evaluator)
private val internalEvaluator: InternalEvaluator = InternalEvaluatorImpl(
jupyterCompiler,
evaluator,
contextUpdater,
executedCodeLogging != ExecutedCodeLogging.OFF,
internalVariablesMarkersProcessor,
)
@Suppress("unused")
private val debugUtilityProvider = DebugUtilityProvider(notebook)
private val textRenderersProcessor: TextRenderersProcessorWithPreventingRecursion = TextRenderersProcessorImpl().apply {
//registerDefaultRenderers()
}
private val renderersProcessor: ResultsRenderersProcessor = RenderersProcessorImpl(contextUpdater).apply {
registerDefaultRenderers()
}
override val currentClassLoader: ClassLoader get() = internalEvaluator.lastClassLoader
override val throwableRenderersProcessor: ThrowableRenderersProcessor = ThrowableRenderersProcessorImpl()
private val fieldsProcessor: FieldsProcessorInternal = FieldsProcessorImpl(contextUpdater).apply {
register(NullabilityEraser, ProcessingPriority.LOWEST)
}
private val classAnnotationsProcessor: ClassAnnotationsProcessor = ClassAnnotationsProcessorImpl()
private val fileAnnotationsProcessor: FileAnnotationsProcessor = FileAnnotationsProcessorImpl(ScriptDependencyAnnotationHandlerImpl(resolver), compilerArgsConfigurator, jupyterCompiler, this)
private val interruptionCallbacksProcessor: InterruptionCallbacksProcessor = InterruptionCallbacksProcessorImpl(this)
private val colorSchemeChangeCallbacksProcessor: ColorSchemeChangeCallbacksProcessor = ColorSchemeChangeCallbacksProcessorImpl()
private val beforeCellExecutionsProcessor = BeforeCellExecutionsProcessor()
private val afterCellExecutionsProcessor = AfterCellExecutionsProcessor()
private val shutdownExecutionsProcessor = ShutdownExecutionsProcessor()
override fun checkComplete(code: String) = jupyterCompiler.checkComplete(code)
internal val sharedContext = SharedReplContext(
classAnnotationsProcessor,
fileAnnotationsProcessor,
fieldsProcessor,
renderersProcessor,
textRenderersProcessor,
throwableRenderersProcessor,
codePreprocessor,
resourcesProcessor,
librariesProcessor,
librariesScanner,
notebook,
beforeCellExecutionsProcessor,
shutdownExecutionsProcessor,
afterCellExecutionsProcessor,
internalEvaluator,
this,
internalVariablesMarkersProcessor,
interruptionCallbacksProcessor,
colorSchemeChangeCallbacksProcessor,
displayHandler,
).also {
notebook.sharedReplContext = it
}
private var evalContextEnabled = false
private fun withEvalContext(action: () -> T): T {
return synchronized(this) {
evalContextEnabled = true
try {
action()
} finally {
evalContextEnabled = false
ctx.cellExecutionFinished()
}
}
}
private val executor: CellExecutor = CellExecutorImpl(sharedContext)
private fun onAnnotationsHandler(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics {
return if (evalContextEnabled) fileAnnotationsProcessor.process(context, currentKernelHost!!)
else context.compilationConfiguration.asSuccess()
}
@TestOnly
@Suppress("unused")
private fun printVariables(isHtmlFormat: Boolean = false) = log.debug(
if (isHtmlFormat) generateHTMLVarsReport(notebook.variablesState) else notebook.variablesReport
)
@TestOnly
@Suppress("unused")
private fun printUsagesInfo(cellId: Int, usedVariables: Set?) {
log.debug(buildString {
if (usedVariables.isNullOrEmpty()) {
append("No usages for cell $cellId")
return@buildString
}
append("Usages for cell $cellId:\n")
usedVariables.forEach {
append(it + "\n")
}
})
}
override fun evalEx(evalData: EvalRequestData): EvalResultEx {
return withEvalContext {
beforeCellExecutionsProcessor.process(executor)
val cell: MutableCodeCell = notebook.addCell(EvalData(evalData))
val compiledData: SerializedCompiledScriptsData
val newImports: List
val result = try {
log.debug("Current cell id: ${evalData.jupyterId}")
val executorWorkflowListener = object : ExecutorWorkflowListener {
override fun internalIdGenerated(id: Int) {
cell.internalId = id
}
override fun codePreprocessed(preprocessedCode: Code) {
cell.preprocessedCode = preprocessedCode
}
override fun compilationFinished() {
cell.declarations = declarationsCollector.getLastSnippetDeclarations()
}
}
executor.execute(
evalData.code,
isUserCode = true,
currentCellId = evalData.jupyterId - 1,
executorWorkflowListener = executorWorkflowListener
)
} finally {
compiledData = internalEvaluator.popAddedCompiledScripts()
newImports = importsCollector.popAddedImports()
}
cell.resultVal = result.result.value
val rendered = result.result.let {
log.catchAll {
renderersProcessor.renderResult(executor, it)
}
}?.let {
log.catchAll {
if (it is Renderable) it.render(notebook) else it
}
}
val displayValue = log.catchAll {
notebook.postRender(rendered)
}
val newClasspath = log.catchAll {
updateClasspath()
} ?: emptyList()
val newSources = log.catchAll {
updateSources()
} ?: emptyList()
if (!evalData.storeHistory) {
log.catchAll { notebook.popCell() }
}
val variablesStateUpdate = notebook.variablesState.mapValues { "" }
EvalResultEx(
result.result.value,
rendered,
displayValue,
result.scriptInstance,
result.result.name,
EvaluatedSnippetMetadata(newClasspath, newSources, compiledData, newImports, variablesStateUpdate),
)
}
}
override fun eval(execution: ExecutionCallback): T {
return synchronized(this) {
executor.execute(execution)
}
}
override fun evalOnShutdown(): List {
return shutdownExecutionsProcessor.process(executor)
}
/**
* Updates current classpath with newly resolved libraries paths
* Also, prints information about resolved libraries to stdout if [trackClasspath] is true
*
* @return Newly resolved classpath
*/
private fun updateClasspath(): Classpath {
val resolvedClasspath = resolver.popAddedClasspath().map { it.canonicalPath }
if (resolvedClasspath.isEmpty()) return emptyList()
val (oldClasspath, newClasspath) = resolvedClasspath.partition { it in currentClasspath }
currentClasspath.addAll(newClasspath)
if (trackClasspath) {
val sb = StringBuilder()
if (newClasspath.isNotEmpty()) {
sb.appendLine("${newClasspath.count()} new paths were added to classpath:")
newClasspath.sortedBy { it }.forEach { sb.appendLine(it) }
}
if (oldClasspath.isNotEmpty()) {
sb.appendLine("${oldClasspath.count()} resolved paths were already in classpath:")
oldClasspath.sortedBy { it }.forEach { sb.appendLine(it) }
}
sb.appendLine("Current classpath size: ${currentClasspath.count()}")
println(sb.toString())
}
return newClasspath
}
private fun updateSources(): Classpath {
val resolvedClasspath = resolver.popAddedSources().map { it.canonicalPath }
val newClasspath = resolvedClasspath.filter { it !in currentSources }
currentSources.addAll(newClasspath)
return newClasspath
}
private val completionQueue = LockQueue()
override suspend fun complete(code: String, cursor: Int, callback: (CompletionResult) -> Unit) =
doWithLock(
CompletionArgs(code, cursor, callback),
completionQueue,
CompletionResult.Empty(code, cursor),
::doComplete
)
private fun doComplete(args: CompletionArgs): CompletionResult {
if (looksLikeReplCommand(args.code)) return doCommandCompletion(args.code, args.cursor)
val preprocessed = completionMagics.process(args.code, args.cursor)
if (preprocessed.cursorInsideMagic) {
return KotlinCompleter.getResult(args.code, args.cursor, preprocessed.completions)
}
return completer.complete(
jupyterCompiler.completer,
compilerConfiguration,
args.code,
preprocessed.code,
jupyterCompiler.nextCounter(),
args.cursor
)
}
private val listErrorsQueue = LockQueue()
override suspend fun listErrors(code: String, callback: (ListErrorsResult) -> Unit) =
doWithLock(ListErrorsArgs(code, callback), listErrorsQueue, ListErrorsResult(code), ::doListErrors)
private fun doListErrors(args: ListErrorsArgs): ListErrorsResult {
if (looksLikeReplCommand(args.code)) return reportCommandErrors(args.code)
val preprocessingResult = errorsMagics.process(args.code)
val errorsList = preprocessingResult.diagnostics + jupyterCompiler.listErrors(preprocessingResult.code)
return ListErrorsResult(args.code, errorsList)
}
private fun > doWithLock(
args: Args,
queue: LockQueue,
default: T,
action: (Args) -> T
) {
queue.add(args)
val result = synchronized(this) {
val lastArgs = queue.get()
if (lastArgs !== args) {
default
} else {
action(args)
}
}
args.callback(result)
}
private interface LockQueueArgs {
val callback: (T) -> Unit
}
private data class CompletionArgs(
val code: String,
val cursor: Int,
override val callback: (CompletionResult) -> Unit
) : LockQueueArgs
private data class ListErrorsArgs(val code: String, override val callback: (ListErrorsResult) -> Unit) :
LockQueueArgs
@JvmInline
private value class LockQueue>(
private val args: AtomicReference = AtomicReference()
) {
fun add(args: Args) {
this.args.set(args)
}
fun get(): Args {
return args.get()!!
}
}
init {
log.info("Starting kotlin REPL engine. Compiler version: ${KotlinCompilerVersion.VERSION}")
log.info("Kernel version: ${runtimeProperties.version}")
log.info("Classpath used in script: $scriptClasspath")
}
override fun withHost(currentHost: KotlinKernelHost, callback: () -> T): T {
try {
currentKernelHost = currentHost
return callback()
} finally {
currentKernelHost = null
}
}
override val host: KotlinKernelHost?
get() = currentKernelHost
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy