summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-11-04 14:53:50 +0000
committerPaul Phillips <paulp@improving.org>2011-11-04 14:53:50 +0000
commitf4991fcffc0cddcd16e7abccbc577581fbf5bd0f (patch)
treee3672911455f72dec4eb27c9e1799fe35d3d113f /src/compiler
parent8006cc6760b30274676ae5359c27b49e5cbf5670 (diff)
downloadscala-f4991fcffc0cddcd16e7abccbc577581fbf5bd0f.tar.gz
scala-f4991fcffc0cddcd16e7abccbc577581fbf5bd0f.tar.bz2
scala-f4991fcffc0cddcd16e7abccbc577581fbf5bd0f.zip
More repl work.
Hardened the repl against a bunch of erroneous conditions. Added a :reset command which causes the repl to forget everything you have told it. Added classloader tracing when repl tracing is enabled. :reset is not that useful in its current form but it's the precursor to something more interesting. No review.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala9
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala104
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala62
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala18
-rw-r--r--src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala19
-rw-r--r--src/compiler/scala/tools/util/Javap.scala22
8 files changed, 167 insertions, 73 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
index 5b6e37e4fe..70aa8ff54e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
@@ -10,7 +10,7 @@ import ch.epfl.lamp.fjbg._
import java.io.{ DataOutputStream, OutputStream, File => JFile }
import scala.tools.nsc.io._
import scala.tools.nsc.util.ScalaClassLoader
-import scala.tools.util.Javap
+import scala.tools.util.JavapClass
import java.util.jar.{ JarEntry, JarOutputStream, Attributes }
import Attributes.Name
@@ -67,7 +67,7 @@ trait BytecodeWriters {
def emitJavap(bytes: Array[Byte], javapFile: io.File) {
val pw = javapFile.printWriter()
- val javap = new Javap(ScalaClassLoader.appLoader, pw) {
+ val javap = new JavapClass(ScalaClassLoader.appLoader, pw) {
override def findBytes(path: String): Array[Byte] = bytes
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
index c79728d0b1..3bc4e1cbe1 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
@@ -20,11 +20,6 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
with ScalaClassLoader
{
// private val defined = mutable.Map[String, Class[_]]()
- private def cllog(msg: => String) {
- if (trace)
- println("[" + classLoaderUniqId + "] " + msg)
- }
-
override protected def trace =
sys.props contains "scala.debug.classloader"
@@ -57,12 +52,12 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
case file => file.toByteArray
}
override def loadClass(name: String, resolve: Boolean) = {
- cllog("load " + name + ".")
+ classLoaderLog("load " + name + ".")
super.loadClass(name, resolve)
}
override def findClass(name: String): JClass = {
val bytes = classBytes(name)
- cllog("find %s: %s".format(name,
+ classLoaderLog("find %s: %s".format(name,
if (bytes.isEmpty) "failed."
else bytes.size + " bytes."
))
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index cc06987dc4..a355e19ff9 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -19,6 +19,8 @@ import util.{ ClassPath, Exceptional, stringFromWriter, stringFromStream }
import interpreter._
import io.{ File, Sources }
import scala.reflect.NameTransformer._
+import util.ScalaClassLoader._
+import scala.tools.util._
/** The Scala interactive shell. It provides a read-eval-print loop
* around the Interpreter class.
@@ -82,13 +84,23 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
/** Record a command for replay should the user request a :replay */
def addReplay(cmd: String) = replayCommandStack ::= cmd
+ def savingReplayStack[T](body: => T): T = {
+ val saved = replayCommandStack
+ try body
+ finally replayCommandStack = saved
+ }
+ def savingReader[T](body: => T): T = {
+ val saved = in
+ try body
+ finally in = saved
+ }
+
/** Close the interpreter and set the var to null. */
def closeInterpreter() {
if (intp ne null) {
- intp.close
+ intp.close()
intp = null
removeSigIntHandler()
- Thread.currentThread.setContextClassLoader(originalClassLoader)
}
}
@@ -228,6 +240,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
nullary("power", "enable power user mode", powerCmd),
nullary("quit", "exit the interpreter", () => Result(false, None)),
nullary("replay", "reset execution and replay all previous commands", replay),
+ nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand),
+ // nullary("reset", "reset the interpreter, forgetting session values but retaining session types", replay),
shCommand,
nullary("silent", "disable/enable automatic printing of results", verbosity),
cmd("type", "<expr>", "display the type of an expression without evaluating it", typeCommand),
@@ -359,7 +373,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
- protected def newJavap() = new Javap(intp.classLoader, new IMain.ReplStrippingWriter(intp)) {
+ protected def newJavap() = new JavapClass(intp.classLoader, new IMain.ReplStrippingWriter(intp)) {
override def tryClass(path: String): Array[Byte] = {
val hd :: rest = path split '.' toList;
// If there are dots in the name, the first segment is the
@@ -387,9 +401,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
}
}
- private lazy val javap =
- try newJavap()
- catch { case _: Exception => null }
+ private lazy val javap = substituteAndLog[Javap]("javap", NoJavap)(newJavap())
// Still todo: modules.
private def typeCommand(line: String): Result = {
@@ -505,7 +517,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
|[y/n]
""".trim.stripMargin
- private val crashRecovery: PartialFunction[Throwable, Unit] = {
+ private val crashRecovery: PartialFunction[Throwable, Boolean] = {
case ex: Throwable =>
if (settings.YrichExes.value) {
val sources = implicitly[Sources]
@@ -529,6 +541,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
if (fn()) replay()
else echo("\nAbandoning crashed session.")
}
+ true
}
/** The main read-eval-print loop for the repl. It calls
@@ -553,39 +566,56 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
case _ => true
}
}
-
- while (true) {
- try if (!processLine(readOneLine())) return
- catch crashRecovery
+ def innerLoop() {
+ if ( try processLine(readOneLine()) catch crashRecovery )
+ innerLoop()
}
+ innerLoop()
}
/** interpret all lines from a specified file */
def interpretAllFrom(file: File) {
- val oldIn = in
- val oldReplay = replayCommandStack
-
- try file applyReader { reader =>
- in = SimpleReader(reader, out, false)
- echo("Loading " + file + "...")
- loop()
- }
- finally {
- in = oldIn
- replayCommandStack = oldReplay
+ savingReader {
+ savingReplayStack {
+ file applyReader { reader =>
+ in = SimpleReader(reader, out, false)
+ echo("Loading " + file + "...")
+ loop()
+ }
+ }
}
}
- /** create a new interpreter and replay all commands so far */
+ /** create a new interpreter and replay the given commands */
def replay() {
- closeInterpreter()
- createInterpreter()
- for (cmd <- replayCommands) {
+ reset()
+ if (replayCommandStack.isEmpty)
+ echo("Nothing to replay.")
+ else for (cmd <- replayCommands) {
echo("Replaying: " + cmd) // flush because maybe cmd will have its own output
command(cmd)
echo("")
}
}
+ def resetCommand() {
+ echo("Resetting interpreter state.")
+ if (replayCommandStack.nonEmpty) {
+ echo("Forgetting this session history:\n")
+ replayCommands foreach echo
+ echo("")
+ replayCommandStack = Nil
+ }
+ if (intp.namedDefinedTerms.nonEmpty)
+ echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", "))
+ if (intp.definedTypes.nonEmpty)
+ echo("Forgetting defined types: " + intp.definedTypes.mkString(", "))
+
+ reset()
+ }
+ def reset() {
+ intp.reset()
+ unleashAndSetPhase()
+ }
/** fork a shell and run a command */
lazy val shCommand = new LoopCommand("sh", "run a shell command (result is implicitly => List[String])") {
@@ -632,10 +662,20 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
}
def enablePowerMode(isDuringInit: Boolean) = {
replProps.power setValue true
- power.unleash()
- intp.beSilentDuring(phaseCommand("typer"))
- if (isDuringInit) asyncMessage(power.banner)
- else echo(power.banner)
+ unleashAndSetPhase()
+ asyncEcho(isDuringInit, power.banner)
+ }
+ private def unleashAndSetPhase() {
+ if (isReplPower) {
+ power.unleash()
+ // Set the phase to "typer"
+ intp beSilentDuring phaseCommand("typer")
+ }
+ }
+
+ def asyncEcho(async: Boolean, msg: => String) {
+ if (async) asyncMessage(msg)
+ else echo(msg)
}
def verbosity() = {
@@ -792,7 +832,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
SimpleReader()
}
}
- def process(settings: Settings): Boolean = {
+ def process(settings: Settings): Boolean = savingContextLoader {
this.settings = settings
createInterpreter()
@@ -925,7 +965,7 @@ object ILoop {
if (assertion) break[T](args.toList)
// start a repl, binding supplied args
- def break[T: Manifest](args: List[NamedParam]): Unit = {
+ def break[T: Manifest](args: List[NamedParam]): Unit = savingContextLoader {
val msg = if (args.isEmpty) "" else " Binding " + args.size + " value%s.".format(
if (args.size == 1) "" else "s"
)
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala
index 6ebe3f7362..2f02748e8f 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala
@@ -61,7 +61,7 @@ trait ILoopInit {
}
}
protected def removeSigIntHandler() {
- SignalManager("INT") = null
+ squashAndLog("removeSigIntHandler")(SignalManager("INT") = null)
}
private val initLock = new java.util.concurrent.locks.ReentrantLock()
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index ff6100e9e8..a7fb15124a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -226,14 +226,6 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def quietRun[T](code: String) = beQuietDuring(interpret(code))
- private def logAndDiscard[T](label: String, alt: => T): PartialFunction[Throwable, T] = {
- case t =>
- repldbg(label + ": " + unwrap(t))
- repltrace(util.stackTraceString(unwrap(t)))
-
- alt
- }
-
/** whether to bind the lastException variable */
private var bindExceptions = true
/** takes AnyRef because it may be binding a Throwable or an Exceptional */
@@ -242,7 +234,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
bindExceptions = false
try beQuietDuring(body)
- catch logAndDiscard("bindLastException", alt)
+ catch logAndDiscard("withLastExceptionLock", alt)
finally bindExceptions = true
}
@@ -310,6 +302,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
else new URLClassLoader(compilerClasspath, parentClassLoader)
new AbstractFileClassLoader(virtualDirectory, parent) {
+ private[IMain] var traceClassLoading = isReplTrace
+ override protected def trace = traceClassLoading
+
/** Overridden here to try translating a simple name to the generated
* class name if the original attempt fails. This method is used by
* getResourceAsStream as well as findClass.
@@ -638,6 +633,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
interpret(line)
}
}
+ def directBind(name: String, boundType: String, value: Any): IR.Result = {
+ val result = bind(name, boundType, value)
+ if (result == IR.Success)
+ directlyBoundNames += name
+ result
+ }
+ def directBind(p: NamedParam): IR.Result = directBind(p.name, p.tpe, p.value)
+ def directBind[T: Manifest](name: String, value: T): IR.Result = directBind((name, value))
def rebind(p: NamedParam): IR.Result = {
val name = p.name
@@ -661,10 +664,13 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** Reset this interpreter, forgetting all user-specified requests. */
def reset() {
- virtualDirectory.clear()
+ clearExecutionWrapper()
resetClassLoader()
resetAllCreators()
prevRequests.clear()
+ referencedNameMap.clear()
+ definedNameMap.clear()
+ virtualDirectory.clear()
}
/** This instance is no longer needed, so release any resources
@@ -711,14 +717,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
withLastExceptionLock[String]({
if (opt.richExes) {
val ex = new LineExceptional(unwrapped)
- bind[Exceptional]("lastException", ex)
+ directBind[Exceptional]("lastException", ex)
ex.contextHead + "\n(access lastException for the full trace)"
}
else {
- bind[Throwable]("lastException", unwrapped)
+ directBind[Throwable]("lastException", unwrapped)
util.stackTraceString(unwrapped)
}
- }, "" + unwrapped)
+ }, util.stackTraceString(unwrapped))
}
// TODO: split it out into a package object and a regular
@@ -732,8 +738,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def evalPath = pathTo(evalName)
def printPath = pathTo(printName)
- def call(name: String, args: Any*): AnyRef =
- evalMethod(name).invoke(evalClass, args.map(_.asInstanceOf[AnyRef]): _*)
+ def call(name: String, args: Any*): AnyRef = {
+ val m = evalMethod(name)
+ repldbg("Invoking: " + m)
+ if (args.nonEmpty)
+ repldbg(" with args: " + args.mkString(", "))
+
+ m.invoke(evalClass, args.map(_.asInstanceOf[AnyRef]): _*)
+ }
def callEither(name: String, args: Any*): Either[Throwable, AnyRef] =
try Right(call(name, args: _*))
@@ -1093,6 +1105,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def definedTypes = onlyTypes(allDefinedNames)
def definedSymbols = prevRequests.toSet flatMap ((x: Request) => x.definedSymbols.values)
+ // Terms with user-given names (i.e. not res0 and not synthetic)
+ def namedDefinedTerms = definedTerms filterNot (x => isUserVarName("" + x) || directlyBoundNames(x))
+
private def findName(name: Name) = definedSymbols find (_.name == name)
private def missingOpt(op: => Symbol): Option[Symbol] =
@@ -1127,14 +1142,15 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
}
/** the previous requests this interpreter has processed */
- private lazy val prevRequests = mutable.ListBuffer[Request]()
- private lazy val referencedNameMap = mutable.Map[Name, Request]()
- private lazy val definedNameMap = mutable.Map[Name, Request]()
- protected def prevRequestList = prevRequests.toList
- private def allHandlers = prevRequestList flatMap (_.handlers)
- def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct
- def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames)
- def importHandlers = allHandlers collect { case x: ImportHandler => x }
+ private lazy val prevRequests = mutable.ListBuffer[Request]()
+ private lazy val referencedNameMap = mutable.Map[Name, Request]()
+ private lazy val definedNameMap = mutable.Map[Name, Request]()
+ private lazy val directlyBoundNames = mutable.Set[Name]()
+ protected def prevRequestList = prevRequests.toList
+ private def allHandlers = prevRequestList flatMap (_.handlers)
+ def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct
+ def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames)
+ def importHandlers = allHandlers collect { case x: ImportHandler => x }
def visibleTermNames: List[Name] = definedTerms ++ importedTerms distinct
diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala b/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala
index c4a77e9630..8c589eba60 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ReplConfig.scala
@@ -6,6 +6,9 @@
package scala.tools.nsc
package interpreter
+import util.Exceptional.unwrap
+import util.stackTraceString
+
trait ReplConfig {
lazy val replProps = new ReplProps
@@ -28,6 +31,21 @@ trait ReplConfig {
private[nsc] def repltrace(msg: => String) = if (isReplTrace) echo(msg)
private[nsc] def replinfo(msg: => String) = if (isReplInfo) echo(msg)
+ private[nsc] def logAndDiscard[T](label: String, alt: => T): PartialFunction[Throwable, T] = {
+ case t =>
+ repldbg(label + ": " + unwrap(t))
+ repltrace(stackTraceString(unwrap(t)))
+ alt
+ }
+ private[nsc] def substituteAndLog[T](alt: => T)(body: => T): T =
+ substituteAndLog("" + alt, alt)(body)
+ private[nsc] def substituteAndLog[T](label: String, alt: => T)(body: => T): T = {
+ try body
+ catch logAndDiscard(label, alt)
+ }
+ private[nsc] def squashAndLog(label: String)(body: => Unit): Unit =
+ substituteAndLog(label, ())(body)
+
def isReplTrace: Boolean = replProps.trace
def isReplDebug: Boolean = replProps.debug || isReplTrace
def isReplInfo: Boolean = replProps.info || isReplDebug
diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
index 74a56fbc2c..952b1e4dd2 100644
--- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
@@ -26,7 +26,11 @@ trait HasClassPath {
trait ScalaClassLoader extends JClassLoader {
/** Override to see classloader activity traced */
protected def trace: Boolean = false
- val classLoaderUniqId = "Cl#" + System.identityHashCode(this)
+ protected lazy val classLoaderUniqueId = "Cl#" + System.identityHashCode(this)
+ protected def classLoaderLog(msg: => String) {
+ if (trace)
+ Console.err.println("[" + classLoaderUniqueId + "] " + msg)
+ }
/** Executing an action with this classloader as context classloader */
def asContext[T](action: => T): T = {
@@ -51,13 +55,13 @@ trait ScalaClassLoader extends JClassLoader {
override def findClass(name: String) = {
val result = super.findClass(name)
- // if (trace) println("findClass(%s) = %s".format(name, result))
+ classLoaderLog("findClass(%s) = %s".format(name, result))
result
}
override def loadClass(name: String, resolve: Boolean) = {
val result = super.loadClass(name, resolve)
- // if (trace) println("loadClass(%s, %s) = %s".format(name, resolve, result))
+ classLoaderLog("loadClass(%s, %s) = %s".format(name, resolve, result))
result
}
@@ -94,7 +98,7 @@ trait ScalaClassLoader extends JClassLoader {
case null => Nil
case p => p.loaderChain
})
- override def toString = classLoaderUniqId
+ override def toString = classLoaderUniqueId
}
/** Methods for obtaining various classloaders.
@@ -146,6 +150,11 @@ object ScalaClassLoader {
}
def setContext(cl: JClassLoader) =
Thread.currentThread.setContextClassLoader(cl)
+ def savingContextLoader[T](body: => T): T = {
+ val saved = contextLoader
+ try body
+ finally setContext(saved)
+ }
class URLClassLoader(urls: Seq[URL], parent: JClassLoader)
extends JURLClassLoader(urls.toArray, parent)
@@ -162,7 +171,7 @@ object ScalaClassLoader {
classloaderURLs :+= url
super.addURL(url)
}
- def toLongString = urls.mkString("URLClassLoader(id=" + classLoaderUniqId + "\n ", "\n ", "\n)\n")
+ def toLongString = urls.mkString("URLClassLoader(id=" + classLoaderUniqueId + "\n ", "\n ", "\n)\n")
}
def fromURLs(urls: Seq[URL], parent: ClassLoader = null): URLClassLoader =
diff --git a/src/compiler/scala/tools/util/Javap.scala b/src/compiler/scala/tools/util/Javap.scala
index 94de5588dd..0c359a2619 100644
--- a/src/compiler/scala/tools/util/Javap.scala
+++ b/src/compiler/scala/tools/util/Javap.scala
@@ -13,10 +13,26 @@ import java.io.{ InputStream, PrintWriter, ByteArrayInputStream, FileNotFoundExc
import scala.tools.nsc.io.{ File, NullPrintStream }
import Javap._
-class Javap(
+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
@@ -87,7 +103,7 @@ object Javap {
type FakePrinter = AnyRef
def apply(path: String): Unit = apply(Seq(path))
- def apply(args: Seq[String]): Unit = new Javap() apply args foreach (_.show())
+ def apply(args: Seq[String]): Unit = new JavapClass() apply args foreach (_.show())
sealed trait JpResult {
type ResultType