Client library for communicating with the Kotlin compilation daemon, enabling remote compilation services and incremental compilation workflows.
—
Interactive Kotlin compilation and evaluation through the daemon with state management and history tracking. Provides a complete REPL (Read-Eval-Print Loop) implementation for interactive Kotlin development.
Main REPL client class that provides interactive compilation capabilities through the daemon.
/**
* Remote REPL compiler client for interactive Kotlin compilation
* @param compileService The daemon service to use
* @param clientAliveFlagFile File indicating client is alive (optional)
* @param targetPlatform Target platform for compilation
* @param args Compiler arguments and configuration
* @param messageCollector Handles compiler messages
* @param templateClasspath Classpath for REPL template
* @param templateClassName Name of the REPL template class
* @param port Port for service communication
*/
class KotlinRemoteReplCompilerClient(
protected val compileService: CompileService,
clientAliveFlagFile: File?,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
messageCollector: MessageCollector,
templateClasspath: List<File>,
templateClassName: String,
port: Int = SOCKET_ANY_FREE_PORT
) : ReplCompiler {
val services: BasicCompilerServicesWithResultsFacadeServer
val sessionId: Int
}Usage Example:
import org.jetbrains.kotlin.daemon.client.KotlinRemoteReplCompilerClient
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import java.io.File
val compileService = KotlinCompilerClient.connectToCompileService(...)
val messageCollector = PrintingMessageCollector(System.out, null, false)
val templateClasspath = listOf(File("/path/to/kotlin-stdlib.jar"))
val replClient = KotlinRemoteReplCompilerClient(
compileService = compileService,
clientAliveFlagFile = File("/tmp/repl-client.flag"),
targetPlatform = CompileService.TargetPlatform.JVM,
args = arrayOf("-classpath", "/path/to/libs/*"),
messageCollector = messageCollector,
templateClasspath = templateClasspath,
templateClassName = "kotlin.script.templates.standard.ScriptTemplateWithArgs"
)
try {
// Create REPL state
val lock = ReentrantReadWriteLock()
val state = replClient.createState(lock)
// Evaluate REPL lines
val codeLine1 = ReplCodeLine(0, 0, "val x = 42")
val checkResult1 = replClient.check(state, codeLine1)
if (checkResult1 is ReplCheckResult.Ok) {
val compileResult1 = replClient.compile(state, codeLine1)
println("Result: $compileResult1")
}
val codeLine2 = ReplCodeLine(1, 1, "println(\"x = \$x\")")
val checkResult2 = replClient.check(state, codeLine2)
if (checkResult2 is ReplCheckResult.Ok) {
val compileResult2 = replClient.compile(state, codeLine2)
println("Result: $compileResult2")
}
} finally {
replClient.dispose()
}Creates and manages REPL execution state with thread-safe access.
/**
* Create a new REPL state for managing compilation context
* @param lock Read-write lock for thread-safe state access
* @return REPL state instance
*/
fun createState(lock: ReentrantReadWriteLock): IReplStageState<*>Checks REPL code lines for syntax and semantic errors without compilation.
/**
* Check a REPL code line for errors without compiling
* @param state The REPL state to check against
* @param codeLine The code line to check
* @return Check result indicating success or failure with diagnostics
*/
fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResultCompiles and executes REPL code lines within the managed state.
/**
* Compile and execute a REPL code line
* @param state The REPL state for compilation context
* @param codeLine The code line to compile
* @return Compilation result with execution outcome
*/
fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResultProperly disposes of REPL resources and releases daemon session.
/**
* Dispose REPL client and free resources
* Should be called at the end of REPL lifetime
*/
fun dispose()Manages REPL compilation state with history and generation tracking.
/**
* Remote REPL compiler state implementation
* @param replStateFacade Interface to the remote REPL state
* @param lock Thread synchronization lock
*/
class RemoteReplCompilerState(
internal val replStateFacade: ReplStateFacade,
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) : IReplStageState<Unit> {
override val currentGeneration: Int
override val history: IReplStageHistory<Unit>
}Manages REPL execution history with navigation and reset capabilities.
/**
* REPL state history management
* @param state The REPL state this history belongs to
*/
class RemoteReplCompilerStateHistory(
private val state: RemoteReplCompilerState
) : IReplStageHistory<Unit>, AbstractList<ReplHistoryRecord<Unit>>() {
override val size: Int
val currentGeneration: AtomicInteger
override val lock: ReentrantReadWriteLock
}/**
* Get history record at index
* @param index The history index
* @return History record at the specified index
*/
fun get(index: Int): ReplHistoryRecord<Unit>
/**
* Push new item to history (not supported for remote history)
* @param id Line identifier
* @param item History item
*/
fun push(id: ILineId, item: Unit)
/**
* Pop last item from history (not supported for remote history)
* @return Last history record or null
*/
fun pop(): ReplHistoryRecord<Unit>?
/**
* Reset history to initial state
* @return Iterable of removed line IDs
*/
fun reset(): Iterable<ILineId>
/**
* Reset history to specific line ID
* @param id Target line ID to reset to
* @return Iterable of removed line IDs
*/
fun resetTo(id: ILineId): Iterable<ILineId>val replClient = KotlinRemoteReplCompilerClient(...)
val lock = ReentrantReadWriteLock()
val state = replClient.createState(lock)
try {
var lineNumber = 0
// Read-eval-print loop
while (true) {
print("kotlin> ")
val input = readLine() ?: break
if (input.trim() == ":quit") break
val codeLine = ReplCodeLine(lineNumber++, lineNumber, input)
// Check syntax first
when (val checkResult = replClient.check(state, codeLine)) {
is ReplCheckResult.Ok -> {
// Compile and execute
when (val compileResult = replClient.compile(state, codeLine)) {
is ReplCompileResult.Ok -> {
// Print result if available
compileResult.data.let { data ->
if (data.result != null) {
println("res${lineNumber}: ${data.result}")
}
}
}
is ReplCompileResult.Error -> {
println("Compilation error: ${compileResult.message}")
}
}
}
is ReplCheckResult.Error -> {
println("Syntax error: ${checkResult.message}")
}
}
}
} finally {
replClient.dispose()
}val replClient = KotlinRemoteReplCompilerClient(...)
val state = replClient.createState(ReentrantReadWriteLock())
try {
// Execute some code
val lines = listOf(
"val x = 10",
"val y = 20",
"val sum = x + y",
"println(sum)"
)
lines.forEachIndexed { index, code ->
val codeLine = ReplCodeLine(index, index, code)
replClient.check(state, codeLine)
replClient.compile(state, codeLine)
}
// Check history
val history = state.history
println("History size: ${history.size}")
// Reset to a previous state
if (history.size >= 2) {
val secondLineId = history[1].id
val removedIds = history.resetTo(secondLineId)
println("Removed lines: $removedIds")
}
} finally {
replClient.dispose()
}class ReplErrorHandler(private val replClient: KotlinRemoteReplCompilerClient) {
fun evaluateLine(state: IReplStageState<*>, code: String, lineId: Int): String {
val codeLine = ReplCodeLine(lineId, lineId, code)
return try {
when (val checkResult = replClient.check(state, codeLine)) {
is ReplCheckResult.Ok -> {
when (val compileResult = replClient.compile(state, codeLine)) {
is ReplCompileResult.Ok -> {
compileResult.data.result?.toString() ?: "OK"
}
is ReplCompileResult.Error -> {
"Compilation Error: ${compileResult.message}"
}
else -> "Unknown compilation result: $compileResult"
}
}
is ReplCheckResult.Error -> {
"Check Error: ${checkResult.message}"
}
else -> "Unknown check result: $checkResult"
}
} catch (e: Exception) {
"Exception: ${e.message}"
}
}
}
val errorHandler = ReplErrorHandler(replClient)
val result = errorHandler.evaluateLine(state, "val invalid syntax", 0)
println(result)Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-daemon-client