scala.tools.util.Javap.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-compiler Show documentation
Show all versions of scala-compiler Show documentation
Compiler for the Scala Programming Language
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Paul Phillips
*/
package scala.tools
package util
import java.lang.reflect.{ GenericSignatureFormatError, Method, Constructor }
import java.lang.{ ClassLoader => JavaClassLoader }
import scala.tools.nsc.util.ScalaClassLoader
import java.io.{ InputStream, PrintWriter, ByteArrayInputStream, FileNotFoundException }
import scala.tools.nsc.io.File
import Javap._
import scala.language.reflectiveCalls
trait Javap {
def loader: ScalaClassLoader
def printWriter: PrintWriter
def apply(args: Seq[String]): List[JpResult]
def tryFile(path: String): Option[Array[Byte]]
def tryClass(path: String): Array[Byte]
}
object NoJavap extends Javap {
def loader: ScalaClassLoader = getClass.getClassLoader
def printWriter: PrintWriter = new PrintWriter(System.err, true)
def apply(args: Seq[String]): List[JpResult] = Nil
def tryFile(path: String): Option[Array[Byte]] = None
def tryClass(path: String): Array[Byte] = Array()
}
class JavapClass(
val loader: ScalaClassLoader = ScalaClassLoader.appLoader,
val printWriter: PrintWriter = new PrintWriter(System.out, true)
) extends Javap {
lazy val parser = new JpOptions
val EnvClass = loader.tryToInitializeClass[FakeEnvironment](Env).orNull
val PrinterClass = loader.tryToInitializeClass[FakePrinter](Printer).orNull
private def failed = (EnvClass eq null) || (PrinterClass eq null)
val PrinterCtr = (
if (failed) null
else PrinterClass.getConstructor(classOf[InputStream], classOf[PrintWriter], EnvClass)
)
def findBytes(path: String): Array[Byte] =
tryFile(path) getOrElse tryClass(path)
def apply(args: Seq[String]): List[JpResult] = {
if (failed) Nil
else args.toList filterNot (_ startsWith "-") map { path =>
val bytes = findBytes(path)
if (bytes.isEmpty) new JpError("Could not find class bytes for '%s'".format(path))
else new JpSuccess(newPrinter(new ByteArrayInputStream(bytes), newEnv(args)))
}
}
def newPrinter(in: InputStream, env: FakeEnvironment): FakePrinter =
if (failed) null
else PrinterCtr.newInstance(in, printWriter, env)
def newEnv(opts: Seq[String]): FakeEnvironment = {
lazy val env: FakeEnvironment = EnvClass.newInstance()
if (failed) null
else parser(opts) foreach { case (name, value) =>
val field = EnvClass getDeclaredField name
field setAccessible true
field.set(env, value.asInstanceOf[AnyRef])
}
env
}
/** Assume the string is a path and try to find the classfile
* it represents.
*/
def tryFile(path: String): Option[Array[Byte]] = {
val file = File(
if (path.endsWith(".class")) path
else path.replace('.', '/') + ".class"
)
if (!file.exists) None
else try Some(file.toByteArray) catch { case x: Exception => None }
}
/** Assume the string is a fully qualified class name and try to
* find the class object it represents.
*/
def tryClass(path: String): Array[Byte] = {
val extName = (
if (path endsWith ".class") (path dropRight 6).replace('/', '.')
else path
)
loader.classBytes(extName)
}
}
object Javap {
val Env = "sun.tools.javap.JavapEnvironment"
val Printer = "sun.tools.javap.JavapPrinter"
def isAvailable(cl: ScalaClassLoader = ScalaClassLoader.appLoader) =
cl.tryToInitializeClass[AnyRef](Env).isDefined
// "documentation"
type FakeEnvironment = AnyRef
type FakePrinter = AnyRef
def apply(path: String): Unit = apply(Seq(path))
def apply(args: Seq[String]): Unit = new JavapClass() apply args foreach (_.show())
sealed trait JpResult {
type ResultType
def isError: Boolean
def value: ResultType
def show(): Unit
// todo
// def header(): String
// def fields(): List[String]
// def methods(): List[String]
// def signatures(): List[String]
}
class JpError(msg: String) extends JpResult {
type ResultType = String
def isError = true
def value = msg
def show() = println(msg)
}
class JpSuccess(val value: AnyRef) extends JpResult {
type ResultType = AnyRef
def isError = false
def show() = value.asInstanceOf[{ def print(): Unit }].print()
}
class JpOptions {
private object Access {
final val PRIVATE = 0
final val PROTECTED = 1
final val PACKAGE = 2
final val PUBLIC = 3
}
private val envActionMap: Map[String, (String, Any)] = {
val map = Map(
"-l" -> (("showLineAndLocal", true)),
"-c" -> (("showDisassembled", true)),
"-s" -> (("showInternalSigs", true)),
"-verbose" -> (("showVerbose", true)),
"-private" -> (("showAccess", Access.PRIVATE)),
"-package" -> (("showAccess", Access.PACKAGE)),
"-protected" -> (("showAccess", Access.PROTECTED)),
"-public" -> (("showAccess", Access.PUBLIC)),
"-all" -> (("showallAttr", true))
)
map ++ List(
"-v" -> map("-verbose"),
"-p" -> map("-private")
)
}
def apply(opts: Seq[String]): Seq[(String, Any)] = {
opts flatMap { opt =>
envActionMap get opt match {
case Some(pair) => List(pair)
case _ =>
val charOpts = opt.tail.toSeq map ("-" + _)
if (charOpts forall (envActionMap contains _))
charOpts map envActionMap
else Nil
}
}
}
}
}