Self-contained embeddable Kotlin compiler with shaded dependencies for integration into applications without classpath conflicts
—
Comprehensive diagnostic collection system for compilation errors, warnings, and informational messages with customizable output formatting. The message collection system provides structured reporting of compilation diagnostics with precise source location information.
Core interface for collecting compilation diagnostics with severity levels and source location information.
/**
* Core interface for collecting compilation diagnostic messages
* Implementations handle display, storage, or processing of compiler messages
*/
interface MessageCollector {
/** Report a diagnostic message with severity and optional location */
fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation? = null
): Unit
/** Check if any error messages have been reported */
fun hasErrors(): Boolean
/** Clear all collected messages */
fun clear(): Unit
}Usage Examples:
// Custom message collector implementation
class CustomMessageCollector : MessageCollector {
private val messages = mutableListOf<CompilerMessage>()
private var hasErrorsFlag = false
override fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
) {
messages.add(CompilerMessage(severity, message, location))
if (severity == CompilerMessageSeverity.ERROR) {
hasErrorsFlag = true
}
// Custom handling
when (severity) {
CompilerMessageSeverity.ERROR -> logger.error(message)
CompilerMessageSeverity.WARNING -> logger.warn(message)
else -> logger.info(message)
}
}
override fun hasErrors(): Boolean = hasErrorsFlag
override fun clear() {
messages.clear()
hasErrorsFlag = false
}
}
// Using with compiler
val messageCollector = CustomMessageCollector()
val compiler = K2JVMCompiler()
val exitCode = compiler.exec(messageCollector, Services.EMPTY, arguments)
if (messageCollector.hasErrors()) {
println("Compilation failed with errors")
}Enumeration of message severity levels for categorizing diagnostic messages.
/**
* Message severity levels for compilation diagnostics
* Ordered from most severe (ERROR) to least severe (OUTPUT)
*/
enum class CompilerMessageSeverity {
/** Fatal compilation error - prevents successful compilation */
ERROR,
/** Strong warning - significant issue but compilation can continue */
STRONG_WARNING,
/** Standard warning - potential issue worth noting */
WARNING,
/** Informational message */
INFO,
/** Verbose logging information */
LOGGING,
/** Compiler output information */
OUTPUT;
companion object {
/** Verbose logging level for detailed output */
val VERBOSE: CompilerMessageSeverity = LOGGING
}
}Source location information for precise error reporting and IDE integration.
/**
* Source location information for diagnostic messages
* Provides precise file, line, and column information
*/
data class CompilerMessageSourceLocation(
/** File path where the diagnostic occurred */
val path: String,
/** Line number (1-based) */
val line: Int,
/** Column number (1-based) */
val column: Int,
/** Source line content for context (optional) */
val lineContent: String? = null
) {
/** Create location with line content for better error reporting */
constructor(
path: String,
line: Int,
column: Int,
lineContent: String
) : this(path, line, column, lineContent)
override fun toString(): String = "$path:$line:$column"
}Pre-built message collector implementations for common use cases.
/**
* Message collector that prints messages to a PrintStream
* Supports different output formats and verbosity levels
*/
class PrintingMessageCollector(
/** Stream to write messages to */
val stream: PrintStream,
/** Message renderer for formatting output */
val messageRenderer: MessageRenderer,
/** Whether to print verbose messages */
val verbose: Boolean
) : MessageCollector {
override fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
): Unit
override fun hasErrors(): Boolean
override fun clear(): Unit
}
/**
* Message collector that groups messages by severity
* Useful for batch processing of diagnostics
*/
class GroupingMessageCollector(
/** Delegate message collector */
private val delegate: MessageCollector,
/** Treat warnings as errors */
private val treatWarningsAsErrors: Boolean,
/** Report all warnings */
private val reportAllWarnings: Boolean
) : MessageCollector {
/** Get all messages grouped by severity */
fun getGroupedMessages(): Map<CompilerMessageSeverity, List<String>>
override fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
): Unit
override fun hasErrors(): Boolean
override fun clear(): Unit
}
/**
* Message collector that filters messages based on severity
* Useful for controlling output verbosity
*/
class FilteringMessageCollector(
/** Delegate message collector */
private val delegate: MessageCollector,
/** Minimum severity to report */
private val minSeverity: CompilerMessageSeverity
) : MessageCollector {
override fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
): Unit
override fun hasErrors(): Boolean
override fun clear(): Unit
}Different output formats for diagnostic messages.
/**
* Message rendering formats for different output contexts
*/
enum class MessageRenderer {
/** Plain text format suitable for console output */
PLAIN,
/** Plain text with full file paths */
PLAIN_FULL_PATHS,
/** XML format suitable for IDE integration */
XML,
/** JSON format for structured processing */
JSON;
/** Render a diagnostic message with the specified format */
fun render(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
): String
}Advanced Usage Examples:
// Hierarchical message collection with filtering
val baseCollector = PrintingMessageCollector(
System.err,
MessageRenderer.PLAIN_FULL_PATHS,
verbose = false
)
val groupingCollector = GroupingMessageCollector(
baseCollector,
treatWarningsAsErrors = false,
reportAllWarnings = true
)
val filteringCollector = FilteringMessageCollector(
groupingCollector,
minSeverity = CompilerMessageSeverity.WARNING
)
// Use with compilation
val compiler = K2JVMCompiler()
val exitCode = compiler.exec(filteringCollector, Services.EMPTY, arguments)
// Analyze results
val groupedMessages = groupingCollector.getGroupedMessages()
val errors = groupedMessages[CompilerMessageSeverity.ERROR] ?: emptyList()
val warnings = groupedMessages[CompilerMessageSeverity.WARNING] ?: emptyList()
println("Compilation completed with ${errors.size} errors, ${warnings.size} warnings")
// XML output for IDE integration
val xmlCollector = PrintingMessageCollector(
System.out,
MessageRenderer.XML,
verbose = true
)
// JSON output for tooling
val jsonCollector = PrintingMessageCollector(
FileOutputStream("compilation-results.json"),
MessageRenderer.JSON,
verbose = true
)Utility functions for working with compiler messages.
/**
* Utilities for message processing and formatting
*/
object MessageUtil {
/** Format a location for display */
fun formatLocation(location: CompilerMessageSourceLocation): String
/** Extract file path from location */
fun getPath(location: CompilerMessageSourceLocation): String
/** Create location from PSI element */
fun psiElementToMessageLocation(element: PsiElement): CompilerMessageSourceLocation?
/** Render exception as compiler message */
fun renderException(exception: Throwable): String
}
/**
* Output message utilities for structured output
*/
object OutputMessageUtil {
/** Format output message for display */
fun formatOutputMessage(message: String): String
/** Format compilation statistics */
fun formatCompilationStats(
duration: Long,
filesCompiled: Int,
errorsCount: Int,
warningsCount: Int
): String
}// Complete message collection setup for build tools
class BuildToolMessageCollector(
private val buildLogger: Logger,
private val failOnWarnings: Boolean = false
) : MessageCollector {
private var errorCount = 0
private var warningCount = 0
override fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
) {
val locationStr = location?.let { " at $it" } ?: ""
val fullMessage = "$message$locationStr"
when (severity) {
CompilerMessageSeverity.ERROR -> {
errorCount++
buildLogger.error(fullMessage)
}
CompilerMessageSeverity.STRONG_WARNING,
CompilerMessageSeverity.WARNING -> {
warningCount++
if (failOnWarnings) {
buildLogger.error("Warning treated as error: $fullMessage")
errorCount++
} else {
buildLogger.warn(fullMessage)
}
}
CompilerMessageSeverity.INFO -> buildLogger.info(fullMessage)
CompilerMessageSeverity.LOGGING,
CompilerMessageSeverity.OUTPUT -> buildLogger.debug(fullMessage)
}
}
override fun hasErrors(): Boolean = errorCount > 0
fun getErrorCount(): Int = errorCount
fun getWarningCount(): Int = warningCount
override fun clear() {
errorCount = 0
warningCount = 0
}
}
// IDE integration with source navigation
class IDEMessageCollector(
private val project: Project,
private val problemsHolder: ProblemsHolder
) : MessageCollector {
override fun report(
severity: CompilerMessageSeverity,
message: String,
location: CompilerMessageSourceLocation?
) {
location?.let { loc ->
val virtualFile = VirtualFileManager.getInstance()
.findFileByUrl("file://${loc.path}")
if (virtualFile != null) {
val psiFile = PsiManager.getInstance(project).findFile(virtualFile)
psiFile?.let { file ->
val element = file.findElementAt(loc.line, loc.column)
element?.let {
when (severity) {
CompilerMessageSeverity.ERROR ->
problemsHolder.registerProblem(it, message, ProblemHighlightType.ERROR)
CompilerMessageSeverity.WARNING,
CompilerMessageSeverity.STRONG_WARNING ->
problemsHolder.registerProblem(it, message, ProblemHighlightType.WARNING)
else -> Unit
}
}
}
}
}
}
override fun hasErrors(): Boolean = problemsHolder.hasErrors()
override fun clear(): Unit = problemsHolder.clear()
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-compiler-embeddable