External Java-compatible interfaces for tool integration, reporting, and diagnostics, enabling seamless integration with Java-based build tools, IDEs, and external systems.
Java interface for handling compiler diagnostics with simple callback-based reporting.
/**
* Handle compiler diagnostics
* Java-compatible interface for receiving compilation messages
*/
trait SimpleReporter {
/**
* Report a diagnostic message
* Called by the compiler for each diagnostic (error, warning, info)
* @param diag Diagnostic information containing message, level, and position
*/
def report(diag: Diagnostic): Unit
}Usage Examples:
import dotty.tools.dotc.interfaces.SimpleReporter;
import dotty.tools.dotc.interfaces.Diagnostic;
// Java implementation
public class MyReporter implements SimpleReporter {
@Override
public void report(Diagnostic diag) {
System.err.println(
diag.level() + ": " + diag.message() +
" at " + diag.position().map(p -> p.toString()).orElse("unknown")
);
}
}
// Usage with compiler
Driver driver = new Driver();
SimpleReporter reporter = new MyReporter();
driver.process(new String[]{"MyFile.scala"}, reporter, null);// Scala implementation
import dotty.tools.dotc.interfaces.{SimpleReporter, Diagnostic}
class ScalaReporter extends SimpleReporter {
override def report(diag: Diagnostic): Unit = {
val level = diag.level() match {
case 0 => "INFO"
case 1 => "WARNING"
case 2 => "ERROR"
case _ => "UNKNOWN"
}
println(s"[$level] ${diag.message()}")
}
}Java interface for receiving compilation events and notifications during the compilation process.
/**
* React to compilation events
* Java-compatible interface for receiving compilation lifecycle callbacks
*/
trait CompilerCallback {
/**
* Called when a class file is generated
* Provides access to generated bytecode and metadata
* @param source Original source file that generated the class
* @param generatedClass Generated class file as AbstractFile
* @param className Fully qualified name of the generated class
*/
def onClassGenerated(source: SourceFile, generatedClass: AbstractFile, className: String): Unit = {}
/**
* Called when a source file compilation is completed
* Indicates that all phases have been applied to the source file
* @param source Source file that was compiled
*/
def onSourceCompiled(source: SourceFile): Unit = {}
/**
* Called at the start of compilation
* Provides opportunity to initialize resources or logging
*/
def onCompilationStart(): Unit = {}
/**
* Called at the end of compilation
* Provides opportunity to clean up resources or perform final reporting
* @param success Whether compilation completed successfully
*/
def onCompilationEnd(success: Boolean): Unit = {}
}Usage Examples:
import dotty.tools.dotc.interfaces.CompilerCallback;
import dotty.tools.dotc.util.SourceFile;
import dotty.tools.io.AbstractFile;
// Java implementation
public class BuildToolCallback implements CompilerCallback {
@Override
public void onClassGenerated(SourceFile source, AbstractFile generatedClass, String className) {
System.out.println("Generated class: " + className + " from " + source.path());
// Copy to build output directory, update dependency tracking, etc.
}
@Override
public void onSourceCompiled(SourceFile source) {
System.out.println("Compiled: " + source.path());
// Update incremental compilation state
}
@Override
public void onCompilationEnd(boolean success) {
if (success) {
System.out.println("Compilation completed successfully");
} else {
System.err.println("Compilation failed");
}
}
}// Scala implementation
import dotty.tools.dotc.interfaces.CompilerCallback
import dotty.tools.dotc.util.SourceFile
import dotty.tools.io.AbstractFile
class IDECallback extends CompilerCallback {
override def onClassGenerated(source: SourceFile, generatedClass: AbstractFile, className: String): Unit = {
// Notify IDE of new class for indexing
println(s"New class available: $className")
}
override def onSourceCompiled(source: SourceFile): Unit = {
// Update syntax highlighting, error markers, etc.
println(s"Source compiled: ${source.path}")
}
}Java interface representing compilation diagnostics with position information and severity levels.
/**
* Represent compilation diagnostics
* Java-compatible interface for diagnostic messages with position and severity information
*/
trait Diagnostic {
/**
* Get diagnostic severity level
* @return Integer representing severity: 0=INFO, 1=WARNING, 2=ERROR
*/
def level(): Int
/**
* Get diagnostic message text
* @return Human-readable diagnostic message
*/
def message(): String
/**
* Get source position where diagnostic was reported
* @return Optional source position, None if position is not available
*/
def position(): Option[SourcePosition]
/**
* Get diagnostic category/code
* @return Optional diagnostic code for programmatic handling
*/
def code(): Option[String] = None
/**
* Get additional diagnostic information
* @return Optional map of additional diagnostic metadata
*/
def metadata(): java.util.Map[String, String] = java.util.Collections.emptyMap()
}Java interface for compilation result information with error counts and status.
/**
* Result type for reporting operations
* Java-compatible interface providing compilation outcome information
*/
trait ReporterResult {
/**
* Check if compilation had errors
* @return True if any errors were reported during compilation
*/
def hasErrors(): Boolean
/**
* Check if compilation had warnings
* @return True if any warnings were reported during compilation
*/
def hasWarnings(): Boolean
/**
* Get total number of errors
* @return Count of error-level diagnostics
*/
def errorCount(): Int
/**
* Get total number of warnings
* @return Count of warning-level diagnostics
*/
def warningCount(): Int
/**
* Get all reported diagnostics
* @return List of all diagnostics from compilation
*/
def allDiagnostics(): java.util.List[Diagnostic]
}Java interface for representing positions in source code with line and column information.
/**
* Position in source code
* Java-compatible interface for source location information
*/
trait SourcePosition {
/**
* Get source file containing this position
* @return Source file reference
*/
def source(): SourceFile
/**
* Get line number (1-based)
* @return Line number where position occurs
*/
def line(): Int
/**
* Get column number (1-based)
* @return Column number where position occurs
*/
def column(): Int
/**
* Get character offset from start of file
* @return Zero-based character offset
*/
def offset(): Int
/**
* Get end position for range diagnostics
* @return Optional end position if this represents a range
*/
def endOffset(): Option[Int] = None
}// Example Maven/Gradle plugin integration
public class ScalaCompilerPlugin {
public void compile(List<String> sourceFiles, String outputDir, List<String> classpath) {
Driver driver = new Driver();
SimpleReporter reporter = diagnostic -> {
if (diagnostic.level() >= 2) { // ERROR level
throw new CompilationException(diagnostic.message());
}
getLog().warn(diagnostic.message());
};
CompilerCallback callback = new CompilerCallback() {
@Override
public void onClassGenerated(SourceFile source, AbstractFile generatedClass, String className) {
// Copy generated class to Maven/Gradle output directory
copyToOutput(generatedClass, outputDir, className);
}
};
String[] args = buildCompilerArgs(sourceFiles, outputDir, classpath);
ReporterResult result = driver.process(args, reporter, callback);
if (result.hasErrors()) {
throw new CompilationException("Compilation failed with " + result.errorCount() + " errors");
}
}
}// Example IDE language server integration
public class ScalaLanguageServer {
private Driver driver = new Driver();
public void handleDidChange(String filePath, String content) {
SimpleReporter reporter = diagnostic -> {
// Send diagnostic to IDE client
sendDiagnostic(filePath, diagnostic);
};
// Compile updated file
String[] args = {filePath, "-classpath", getProjectClasspath()};
driver.process(args, reporter, null);
}
private void sendDiagnostic(String filePath, Diagnostic diagnostic) {
JsonObject lspDiagnostic = new JsonObject();
lspDiagnostic.addProperty("message", diagnostic.message());
lspDiagnostic.addProperty("severity", mapSeverity(diagnostic.level()));
diagnostic.position().ifPresent(pos -> {
JsonObject range = new JsonObject();
range.addProperty("line", pos.line() - 1); // LSP uses 0-based
range.addProperty("character", pos.column() - 1);
lspDiagnostic.add("range", range);
});
// Send to IDE client via LSP protocol
sendToClient(filePath, lspDiagnostic);
}
}/**
* Abstract file representation used throughout the compiler
*/
abstract class AbstractFile {
def name: String
def path: String
def isDirectory: Boolean
def exists: Boolean
def lastModified: Long
}/**
* Source file with content and metadata
*/
class SourceFile {
def file: AbstractFile
def content: Array[Char]
def path: String
def lineIndices: Array[Int]
}