scala.tools.nsc.interpreter.shell.JavacTool.scala Maven / Gradle / Ivy
The newest version!
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools.nsc.interpreter
package shell
import java.io.CharArrayWriter
import java.net.URI
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.Path
import java.util.Locale
import java.util.concurrent.ConcurrentLinkedQueue
import javax.tools._, JavaFileManager.Location, StandardLocation._, JavaFileObject.Kind, Kind._
import scala.collection.mutable.Clearable
import scala.jdk.CollectionConverters._
import scala.reflect.io.AbstractFile
import scala.util.chaining._
import System.lineSeparator
class JavacTool private (tool: JavaCompiler, dir: AbstractFile, loader: ClassLoader) {
private val out = new CharArrayWriter
def written = {
out.flush()
val w = out.toString
out.reset()
w
}
val listener = new JavaReporter
val locale = Locale.getDefault
val fileManager = new JavaToolFileManager(dir, loader)(tool.getStandardFileManager(listener, locale, UTF_8))
def compile(label: String, code: String): Option[String] = {
val options = (
"-encoding" ::
UTF_8.name() ::
Nil
).asJava
val classes: java.lang.Iterable[String] = null
val units = List(StringFileObject(label, code)).asJava
val task = tool.getTask(out, fileManager, listener, options, classes, units)
val success = task.call()
if (success) None else Some(listener.reported(locale))
}
}
object JavacTool {
def apply(dir: AbstractFile, loader: ClassLoader): JavacTool = new JavacTool(ToolProvider.getSystemJavaCompiler, dir, loader)
def apply(dir: Path, loader: ClassLoader) : JavacTool = apply(AbstractFile.getURL(dir.toUri().toURL()), loader)
}
// use `dir` for output, `loader` for inputs
class JavaToolFileManager(dir: AbstractFile, loader: ClassLoader)(delegate: JavaFileManager) extends ForwardingJavaFileManager[JavaFileManager](delegate) {
override def getJavaFileForOutput(location: Location, className: String, kind: Kind, sibling: FileObject): JavaFileObject = {
require(location == CLASS_OUTPUT, s"$location is not CLASS_OUTPUT")
require(kind == CLASS, s"$kind is not CLASS")
AbstractFileObject(dir, className, kind)
}
}
class AbstractFileObject(file: AbstractFile, uri0: URI, kind0: Kind) extends SimpleJavaFileObject(uri0, kind0) {
override def delete() = { file.delete() ; true }
override def openInputStream() = file.input
override def openOutputStream() = file.output
}
object AbstractFileObject {
def apply(dir: AbstractFile, path: String, kind: Kind) = {
val segments = path.replace(".", "/").split("/")
val parts = segments.init
val name = segments.last
val subdir = parts.foldLeft(dir)((vd, n) => vd.subdirectoryNamed(n))
val file = subdir.fileNamed(s"${name}${kind.extension}")
val uri = file.file.toURI
new AbstractFileObject(file, uri, kind)
}
}
// name is the URI path
//
class StringFileObject(uri0: URI, code: String) extends SimpleJavaFileObject(uri0, SOURCE) {
override def getCharContent(ignoreEncodingErrors: Boolean) = code
}
object StringFileObject {
def apply(label: String, code: String): StringFileObject =
new StringFileObject(URI.create(s"string:///${label.replace('.','/')}${SOURCE.extension}"), code)
}
// A clearable diagnostic collector.
//
class JavaReporter extends DiagnosticListener[JavaFileObject] with Clearable {
type D = Diagnostic[_ <: JavaFileObject]
val diagnostics = new ConcurrentLinkedQueue[D]
private def messagesIterator(implicit locale: Locale) = diagnostics.iterator.asScala.map(_.getMessage(locale))
override def report(d: Diagnostic[_ <: JavaFileObject]) = diagnostics.add(d)
override def clear() = diagnostics.clear()
/** All diagnostic messages.
* @param locale Locale for diagnostic messages, null by default.
*/
def messages(implicit locale: Locale = null) = messagesIterator.toList
def reported(implicit locale: Locale = null): String =
if (diagnostics.isEmpty) ""
else
messages
.mkString("", lineSeparator, lineSeparator)
.tap(_ => clear())
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy