summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-04-21 17:06:38 +0000
committerPaul Phillips <paulp@improving.org>2010-04-21 17:06:38 +0000
commita17a4dc15730ce004ca8c9495c850dfca1062c24 (patch)
tree5dbd27fc4476a3bd3f16d1fbbee4647b633f242b
parentcf26f620707be4bd9f8bc30a733eb4a987894421 (diff)
downloadscala-a17a4dc15730ce004ca8c9495c850dfca1062c24.tar.gz
scala-a17a4dc15730ce004ca8c9495c850dfca1062c24.tar.bz2
scala-a17a4dc15730ce004ca8c9495c850dfca1062c24.zip
Since pickled data moved into annotations ShowP...
Since pickled data moved into annotations ShowPickled has been confusedly scratching its head. Made tools/showPickled work again. In the process created a simple interface for creating command line tools for the (majority of) commands which would just like to specify a handful of options. No review.
-rw-r--r--src/compiler/scala/tools/cmd/CommandLine.scala31
-rw-r--r--src/compiler/scala/tools/cmd/Demo.scala7
-rw-r--r--src/compiler/scala/tools/cmd/Instance.scala3
-rw-r--r--src/compiler/scala/tools/cmd/Interpolation.scala6
-rw-r--r--src/compiler/scala/tools/cmd/Meta.scala21
-rw-r--r--src/compiler/scala/tools/cmd/Opt.scala8
-rw-r--r--src/compiler/scala/tools/cmd/Reference.scala3
-rw-r--r--src/compiler/scala/tools/cmd/Spec.scala11
-rw-r--r--src/compiler/scala/tools/cmd/program/Simple.scala81
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ByteCode.scala7
-rw-r--r--src/compiler/scala/tools/nsc/util/ShowPickled.scala17
-rw-r--r--src/partest/scala/tools/partest/PartestSpec.scala3
-rw-r--r--src/scalap/scala/tools/scalap/Decode.scala27
13 files changed, 165 insertions, 60 deletions
diff --git a/src/compiler/scala/tools/cmd/CommandLine.scala b/src/compiler/scala/tools/cmd/CommandLine.scala
index deedf38e93..9b8bef4a9a 100644
--- a/src/compiler/scala/tools/cmd/CommandLine.scala
+++ b/src/compiler/scala/tools/cmd/CommandLine.scala
@@ -8,18 +8,19 @@ package cmd
import scala.collection.mutable.ListBuffer
+trait CommandLineConfig {
+ def enforceArity: Boolean = true
+ def onlyKnownOptions: Boolean = true
+}
+
/** An instance of a command line, parsed according to a Spec.
*/
-class CommandLine(val spec: Reference, val originalArgs: List[String]) {
+class CommandLine(val spec: Reference, val originalArgs: List[String]) extends CommandLineConfig {
def this(spec: Reference, line: String) = this(spec, Parser tokenize line)
def this(spec: Reference, args: Array[String]) = this(spec, args.toList)
import spec.{ isAnyOption, isUnaryOption, isBinaryOption, isExpandOption }
- def assumeBinary = true
- def enforceArity = true
- def onlyKnownOptions = false
-
val Terminator = "--"
val ValueForUnaryOption = "true" // so if --opt is given, x(--opt) = true
@@ -88,23 +89,3 @@ class CommandLine(val spec: Reference, val originalArgs: List[String]) {
override def toString() = argMap.toString + " " + residualArgs.toString
}
-
-object CommandLine {
- def apply(args: List[String], unary: List[String], binary: List[String]) = {
- /** XXX Temporarily assembling a fake spec so we can continue to
- * do ad-hoc parsing based on a list of unary and binary args.
- * Should either clean this up or do it differently.
- */
- object NoSpec extends Reference {
- unary foreach (_ --? )
- binary foreach (_ --| )
-
- protected def creator(args: List[String]) = error("No Spec")
- def programInfo = Spec.Names("", "")
- lazy val referenceSpec = this
- }
-
- new CommandLine(NoSpec, args)
- }
-}
-
diff --git a/src/compiler/scala/tools/cmd/Demo.scala b/src/compiler/scala/tools/cmd/Demo.scala
index 7014e6b4d7..22cf50bd58 100644
--- a/src/compiler/scala/tools/cmd/Demo.scala
+++ b/src/compiler/scala/tools/cmd/Demo.scala
@@ -10,7 +10,7 @@ package cmd
* First take advantage of the meta-options:
*
* // this command creates an executable runner script "demo"
- * % scala scala.tools.cmd.Demo --generate-runner demo
+ * % scala scala.tools.cmd.Demo --self-update demo
*
* // this one creates and sources a completion file - note backticks
* % `./demo --bash`
@@ -19,13 +19,13 @@ package cmd
* % ./demo --<tab>
* --action --defint --int
* --bash --defstr --str
- * --defenv --generate-runner --unary
+ * --defenv --self-update --unary
*
* The normal option configuration is plausibly self-explanatory.
*/
trait DemoSpec extends Spec with Meta.StdOpts with Interpolation {
lazy val referenceSpec = DemoSpec
- lazy val programInfo = Spec.Names("demo", "scala.tools.cmd.Demo")
+ lazy val programInfo = Spec.Info("demo", "Usage: demo [<options>]", "scala.tools.cmd.Demo")
help("""Usage: demo [<options>]""")
heading("Unary options:")
@@ -48,7 +48,6 @@ object DemoSpec extends DemoSpec with Property {
type ThisCommandLine = SpecCommandLine
def creator(args: List[String]) =
new SpecCommandLine(args) {
- override def onlyKnownOptions = true
override def errorFn(msg: String) = { println("Error: " + msg) ; System.exit(0) }
}
}
diff --git a/src/compiler/scala/tools/cmd/Instance.scala b/src/compiler/scala/tools/cmd/Instance.scala
index 4d319b98cc..3c0dbbaa1f 100644
--- a/src/compiler/scala/tools/cmd/Instance.scala
+++ b/src/compiler/scala/tools/cmd/Instance.scala
@@ -16,7 +16,8 @@ trait Instance extends Spec {
protected def help(str: => String): Unit = ()
def isSet(s: String) = parsed isSet toOpt(s)
- def originalArgs = parsed.originalArgs
+ def originalArgs = parsed.originalArgs // the full original list
+ def residualArgs = parsed.residualArgs // only args which were not options or args to options
type OptionMagic = Opt.Instance
protected implicit def optionMagicAdditions(name: String) = new Opt.Instance(programInfo, parsed, name)
diff --git a/src/compiler/scala/tools/cmd/Interpolation.scala b/src/compiler/scala/tools/cmd/Interpolation.scala
index 6b86a35bb9..a326d48f64 100644
--- a/src/compiler/scala/tools/cmd/Interpolation.scala
+++ b/src/compiler/scala/tools/cmd/Interpolation.scala
@@ -52,8 +52,6 @@ object Interpolation {
|#!/bin/sh
|#
|
- |scala @@MAINCLASS@@ $*
- |
- """.stripMargin
+ |scala @@MAINCLASS@@ "$@"
+ |""".stripMargin.trim + "\n"
}
-
diff --git a/src/compiler/scala/tools/cmd/Meta.scala b/src/compiler/scala/tools/cmd/Meta.scala
index 5a09766b13..8609db3d50 100644
--- a/src/compiler/scala/tools/cmd/Meta.scala
+++ b/src/compiler/scala/tools/cmd/Meta.scala
@@ -22,11 +22,11 @@ object Meta {
trait StdOpts {
self: Spec with Interpolation =>
- Bash.name --> runAndExit(Bash.action())
- val runnerFileName = Runner.name --| ;
+ Bash.name --> runAndExit(Bash.action())
+ val selfUpdateName = SelfUpdate.name --| ;
- if (runnerFileName.isDefined)
- runAndExit(Runner.action())
+ if (selfUpdateName.isDefined)
+ runAndExit(SelfUpdate.action())
/** I think we're as close as we can get to bundling completion with
* the program given the constraints imposed by bash. This outputs
@@ -47,12 +47,17 @@ object Meta {
}
}
- /** A very basic runner script.
+ /** Generates a very basic runner script. It's called SelfUpdate
+ * because once it exists you can do something like
+ *
+ * tools/scmp --self-update tools/scmp
+ *
+ * and it will overwrite itself with the current version.
*/
- object Runner extends Opt {
- val name = "generate-runner"
+ object SelfUpdate extends Opt {
+ val name = "self-update"
val action = () => {
- val file = File(runnerFileName.get)
+ val file = File(selfUpdateName.get)
file writeAll interpolate(runnerTemplate)
file setExecutable true
()
diff --git a/src/compiler/scala/tools/cmd/Opt.scala b/src/compiler/scala/tools/cmd/Opt.scala
index 9e3c324deb..beea590492 100644
--- a/src/compiler/scala/tools/cmd/Opt.scala
+++ b/src/compiler/scala/tools/cmd/Opt.scala
@@ -7,7 +7,7 @@ package scala.tools
package cmd
import nsc.Properties.envOrElse
-import Spec.Names
+import Spec.Info
/** Machinery for what amounts to a command line specification DSL.
* It is designed so the same specification trait can be used for
@@ -25,7 +25,7 @@ object Opt {
trait Implicit {
def name: String
- def programInfo: Names
+ def programInfo: Info
protected def opt = toOpt(name)
def --? : Boolean // --opt is set
@@ -47,7 +47,7 @@ object Opt {
def /(descr: String): String // --opt has help description 'descr'
}
- class Reference(val programInfo: Names, val options: Reference.Accumulators, val name: String) extends Implicit {
+ class Reference(val programInfo: Info, val options: Reference.Accumulators, val name: String) extends Implicit {
import options._
def --? = { addUnary(opt) ; false }
@@ -63,7 +63,7 @@ object Opt {
def /(descr: String) = returning(name)(_ => addHelp(() => helpFormatStr.format(opt, descr)))
}
- class Instance(val programInfo: Names, val parsed: CommandLine, val name: String) extends Implicit with Error {
+ class Instance(val programInfo: Info, val parsed: CommandLine, val name: String) extends Implicit with Error {
def --? = parsed isSet opt
def --> (body: => Unit) = if (parsed isSet opt) body
def --| = parsed get opt
diff --git a/src/compiler/scala/tools/cmd/Reference.scala b/src/compiler/scala/tools/cmd/Reference.scala
index 695868191b..3f3712766b 100644
--- a/src/compiler/scala/tools/cmd/Reference.scala
+++ b/src/compiler/scala/tools/cmd/Reference.scala
@@ -32,7 +32,8 @@ trait Reference extends Spec {
protected def help(str: => String) = addHelp(() => str)
- type ThisCommandLine <: SpecCommandLine
+ type ThisCommandLine <: CommandLine
+
class SpecCommandLine(args: List[String]) extends CommandLine(Reference.this, args) { }
protected def creator(args: List[String]): ThisCommandLine
final def apply(args: String*): ThisCommandLine = creator(propertyArgs ++ args flatMap expandArg)
diff --git a/src/compiler/scala/tools/cmd/Spec.scala b/src/compiler/scala/tools/cmd/Spec.scala
index c8283165d9..794bb3303f 100644
--- a/src/compiler/scala/tools/cmd/Spec.scala
+++ b/src/compiler/scala/tools/cmd/Spec.scala
@@ -12,7 +12,7 @@ package cmd
*/
trait Spec {
def referenceSpec: Reference
- def programInfo: Spec.Names
+ def programInfo: Spec.Info
protected def help(str: => String): Unit
protected def heading(str: => String): Unit = help("\n " + str)
@@ -22,7 +22,14 @@ trait Spec {
}
object Spec {
- case class Names(runner: String, mainClass: String) { }
+ class Info(
+ val runner: String,
+ val usage: String,
+ val mainClass: String
+ )
+ object Info {
+ def apply(runner: String, help: String, mainClass: String): Info = new Info(runner, help, mainClass)
+ }
class Accumulator[T: FromString]() {
private var _buf: List[T] = Nil
diff --git a/src/compiler/scala/tools/cmd/program/Simple.scala b/src/compiler/scala/tools/cmd/program/Simple.scala
new file mode 100644
index 0000000000..641be31c9e
--- /dev/null
+++ b/src/compiler/scala/tools/cmd/program/Simple.scala
@@ -0,0 +1,81 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package cmd
+package program
+
+import Spec.Info
+
+/** A boilerplate reducer for commands with simple requirements. For examples,
+ * see Scmp and Tokens in this package.
+ */
+object Simple {
+ type CommandLineTransform = SimpleCommandLine => SimpleCommandLine
+
+ abstract class SimpleSpec(val programInfo: Info) extends Spec with Meta.StdOpts with Interpolation
+
+ trait SimpleInstance extends SimpleSpec with Instance {
+ val parsed: CommandLine
+ }
+
+ class SimpleReference(
+ programInfo: Info,
+ unary: List[(String, String)] = Nil,
+ binary: List[(String, String)] = Nil,
+ postCreation: CommandLineTransform = null
+ ) extends SimpleSpec(programInfo) with Reference {
+
+ spec =>
+
+ if (programInfo.usage != "") help(programInfo.usage)
+ unary foreach { case (option, help) => option / help --? }
+ binary foreach { case (option, help) => option / help --| }
+
+ type ThisCommandLine = SimpleCommandLine
+
+ def creator(args: List[String]) = new SimpleCommandLine(spec, args)
+ def instance(args: Array[String]): SimpleInstance = instance(args.toList)
+ def instance(args: List[String]): SimpleInstance =
+ new {
+ val parsed = spec(args: _*)
+ } with SimpleSpec(programInfo) with SimpleInstance {
+ lazy val referenceSpec = spec
+ }
+
+ lazy val referenceSpec = spec
+ }
+
+ def apply(info: Info, unary: List[(String, String)], binary: List[(String, String)], postCreation: CommandLineTransform): SimpleReference = {
+ new SimpleReference(info, unary, binary, postCreation) {
+ override def creator(args: List[String]) = {
+ val obj = super.creator(args)
+ if (postCreation == null) obj
+ else postCreation(obj)
+ }
+ }
+ }
+
+ def scalaProgramInfo(name: String, help: String) =
+ Spec.Info(name, help, "scala.tools.cmd.program." + name.capitalize)
+
+ /** You can't override a def with a var unless a setter exists. We cleverly
+ * sidestep this by mixing in a trait with dummy setters which will be
+ * inaccessible due to the overriding var.
+ */
+ trait Ticket2338WontFixWorkaround {
+ def enforceArity_=(x: Boolean): Unit = error("unreachable")
+ def onlyKnownOptions_=(x: Boolean): Unit = error("unreachable")
+ }
+
+ /** Configurability simplicity achieved by turning defs into vars and letting
+ * the spec creator apply a transformation. This way there's no need to create
+ * custom subclasses of CommandLine.
+ */
+ class SimpleCommandLine(spec: Reference, args: List[String]) extends CommandLine(spec, args) with Ticket2338WontFixWorkaround {
+ override var enforceArity: Boolean = true
+ override var onlyKnownOptions: Boolean = true
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
index a998f9dfc8..a42b8347a7 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
@@ -10,7 +10,8 @@ import java.io.File
import java.lang.reflect
import java.util.jar.{ JarEntry, JarFile }
import java.util.concurrent.ConcurrentHashMap
-import util.ScalaClassLoader.getSystemLoader
+import util.ScalaClassLoader
+import ScalaClassLoader.getSystemLoader
object ByteCode {
/** Until I figure out why I can't get scalap onto the classpath such
@@ -34,8 +35,8 @@ object ByteCode {
def scalaSigBytesForPath(path: String) =
for {
module <- DECODER
- method <- decoderMethod("scalaSigBytes", classOf[String], classOf[ClassLoader])
- names <- method.invoke(module, path, this.getClass.getClassLoader).asInstanceOf[Option[Array[Byte]]]
+ method <- decoderMethod("scalaSigAnnotationBytes", classOf[String])
+ names <- method.invoke(module, path).asInstanceOf[Option[Array[Byte]]]
}
yield names
diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala
index 740e42192b..b87d603570 100644
--- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala
+++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala
@@ -13,6 +13,7 @@ import java.lang.Long.toHexString
import java.lang.Float.intBitsToFloat
import java.lang.Double.longBitsToDouble
+import cmd.program.Simple
import symtab.{ Flags, Names }
import scala.reflect.generic.{ PickleBuffer, PickleFormat }
import interpreter.ByteCode.scalaSigBytesForPath
@@ -288,15 +289,23 @@ object ShowPickled extends Names {
printFile(pickle, Console.out, bare)
}
+ private lazy val ShowPickledSpec =
+ Simple(
+ Simple.scalaProgramInfo("showPickled", "Usage: showPickled [--bare] <classname>"),
+ List("--bare" -> "suppress numbers in output"),
+ Nil,
+ null
+ )
+
/** Option --bare suppresses numbers so the output can be diffed.
*/
def main(args: Array[String]) {
- val parsed = cmd.CommandLine(args.toList, List("--bare"), Nil)
- def isBare = parsed isSet "--bare"
+ val runner = ShowPickledSpec instance args
+ import runner._
- parsed.residualArgs foreach { arg =>
+ residualArgs foreach { arg =>
(fromFile(arg) orElse fromName(arg)) match {
- case Some(pb) => show(arg, pb, isBare)
+ case Some(pb) => show(arg, pb, parsed isSet "--bare")
case _ => Console.println("Cannot read " + arg)
}
}
diff --git a/src/partest/scala/tools/partest/PartestSpec.scala b/src/partest/scala/tools/partest/PartestSpec.scala
index a89c30a14d..c25119b3af 100644
--- a/src/partest/scala/tools/partest/PartestSpec.scala
+++ b/src/partest/scala/tools/partest/PartestSpec.scala
@@ -17,7 +17,7 @@ import cmd._
*/
trait PartestSpec extends Spec with Meta.StdOpts with Interpolation {
def referenceSpec = PartestSpec
- def programInfo = Spec.Names("partest", "scala.tools.partest.Runner")
+ def programInfo = Spec.Info("partest", "", "scala.tools.partest.Runner")
private val kind = new Spec.Accumulator[String]()
protected def testKinds = kind.get
@@ -95,7 +95,6 @@ object PartestSpec extends PartestSpec with Property {
type ThisCommandLine = PartestCommandLine
class PartestCommandLine(args: List[String]) extends SpecCommandLine(args) {
- override def onlyKnownOptions = true
override def errorFn(msg: String) = printAndExit("Error: " + msg)
def propertyArgs = PartestSpec.propertyArgs
diff --git a/src/scalap/scala/tools/scalap/Decode.scala b/src/scalap/scala/tools/scalap/Decode.scala
index e9f9a390c5..5189009584 100644
--- a/src/scalap/scala/tools/scalap/Decode.scala
+++ b/src/scalap/scala/tools/scalap/Decode.scala
@@ -12,7 +12,10 @@ package scala.tools.scalap
import scala.tools.scalap.scalax.rules.scalasig._
import scala.tools.nsc.util.ScalaClassLoader
import scala.tools.nsc.util.ScalaClassLoader.getSystemLoader
-import Main.SCALA_SIG
+import scala.reflect.generic.ByteCodecs
+
+import ClassFileParser.{ ConstValueIndex, Annotation }
+import Main.{ SCALA_SIG, SCALA_SIG_ANNOTATION, BYTES_VALUE }
/** Temporary decoder. This would be better off in the scala.tools.nsc
* but right now the compiler won't acknowledge scala.tools.scalap
@@ -25,7 +28,8 @@ object Decode {
case _ => NoSymbol
}
- /** Return the classfile bytes representing the scala sig attribute.
+ /** Return the classfile bytes representing the scala sig classfile attribute.
+ * This has been obsoleted by the switch to annotations.
*/
def scalaSigBytes(name: String): Option[Array[Byte]] = scalaSigBytes(name, getSystemLoader())
def scalaSigBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = {
@@ -35,6 +39,25 @@ object Decode {
cf.scalaSigAttribute map (_.data)
}
+ /** Return the bytes representing the annotation
+ */
+ def scalaSigAnnotationBytes(name: String): Option[Array[Byte]] = scalaSigAnnotationBytes(name, getSystemLoader())
+ def scalaSigAnnotationBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = {
+ val bytes = classLoader.findBytesForClassName(name)
+ val byteCode = ByteCode(bytes)
+ val classFile = ClassFileParser.parse(byteCode)
+ import classFile._
+
+ classFile annotation SCALA_SIG_ANNOTATION map { case Annotation(_, els) =>
+ val bytesElem = els find (x => constant(x.elementNameIndex) == BYTES_VALUE) get
+ val _bytes = bytesElem.elementValue match { case ConstValueIndex(x) => constantWrapped(x) }
+ val bytes = _bytes.asInstanceOf[StringBytesPair].bytes
+ val length = ByteCodecs.decode(bytes)
+
+ bytes take length
+ }
+ }
+
/** private[scala] so nobody gets the idea this is a supported interface.
*/
private[scala] def caseParamNames(path: String): Option[List[String]] = {