diff options
author | Paul Phillips <paulp@improving.org> | 2010-04-11 00:32:00 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-04-11 00:32:00 +0000 |
commit | e93c1a93a2c8a40265b34bb9f1dd61b9470c908d (patch) | |
tree | b9f13ffbe1d1ef59380e32f74380f9797b7fd2cb /src/compiler/scala/tools/cmd/CommandLine.scala | |
parent | 71b6aca681ab697304590a96b13847b9bba141dc (diff) | |
download | scala-e93c1a93a2c8a40265b34bb9f1dd61b9470c908d.tar.gz scala-e93c1a93a2c8a40265b34bb9f1dd61b9470c908d.tar.bz2 scala-e93c1a93a2c8a40265b34bb9f1dd61b9470c908d.zip |
Introduces scala.tools.cmd providing command li...
Introduces scala.tools.cmd providing command line tool infrastructure.
For a quick look at what can be done, see
scala.tools.cmd.Demo
For a more involved, potentially eye-straining look, see
scala.tools.partest.PartestSpec
To experience it through the eyes of Joe Partest User, run
test/partest
Review by community.
Diffstat (limited to 'src/compiler/scala/tools/cmd/CommandLine.scala')
-rw-r--r-- | src/compiler/scala/tools/cmd/CommandLine.scala | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/cmd/CommandLine.scala b/src/compiler/scala/tools/cmd/CommandLine.scala new file mode 100644 index 0000000000..8cb4c00b14 --- /dev/null +++ b/src/compiler/scala/tools/cmd/CommandLine.scala @@ -0,0 +1,107 @@ +/* NEST (New Scala Test) + * Copyright 2007-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package cmd + +import scala.collection.mutable.ListBuffer + +/** An instance of a command line, parsed according to a Spec. + */ +class CommandLine(val spec: Reference, val originalArgs: List[String]) { + 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 + + def mapForUnary(opt: String) = Map(opt -> ValueForUnaryOption) + def errorFn(msg: String) = println(msg) + + /** argMap is option -> argument (or "" if it is a unary argument) + * residualArgs are what is left after removing the options and their args. + */ + lazy val (argMap, residualArgs) = { + val residualBuffer = new ListBuffer[String] + + def isOption(s: String) = isAnyOption(s) || ((s startsWith "-") && !onlyKnownOptions) + + def unknownOption(opt: String) = + errorFn("Option '%s' not recognized.".format(opt)) + def missingArg(opt: String, what: String) = + errorFn("Option '%s' requires argument, found %s instead.".format(opt, what)) + + def loop(args: List[String]): Map[String, String] = { + def residual(xs: List[String]) = { residualBuffer ++= xs ; Map[String, String]() } + + /** Returns Some(List(args)) if this option expands to an + * argument list and it's not returning only the same arg. + */ + def expand(s1: String) = { + if (isExpandOption(s1)) { + val s2 = spec expandArg s1 + if (s2 == List(s1)) None + else Some(s2) + } + else None + } + + args match { + case Nil => Map() + case Terminator :: xs => residual(xs) + case x :: Nil => + expand(x) foreach (exp => return loop(exp)) + if (isBinaryOption(x) && enforceArity) + missingArg(x, "EOF") + + if (isUnaryOption(x)) mapForUnary(x) + else residual(args) + case x1 :: x2 :: xs => + expand(x1) foreach (exp => return loop(exp ++ args.tail)) + + if (x2 == Terminator) mapForUnary(x1) ++ residual(xs) + else if (isUnaryOption(x1)) mapForUnary(x1) ++ loop(args.tail) + else if (isBinaryOption(x1)) Map(x1 -> x2) ++ loop(xs) + else residual(List(x1)) ++ loop(args.tail) + } + } + + (loop(originalArgs), residualBuffer map stripQuotes toList) + } + + def apply(arg: String) = argMap(arg) + def get(arg: String) = argMap get arg + def isSet(arg: String) = argMap contains arg + + def getOrElse(arg: String, orElse: => String) = if (isSet(arg)) apply(arg) else orElse + + 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) + } +} + |