summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/cmd/CommandLine.scala2
-rw-r--r--src/compiler/scala/tools/cmd/CommandLineParser.scala72
-rw-r--r--src/compiler/scala/tools/cmd/Parser.scala52
-rw-r--r--src/compiler/scala/tools/cmd/package.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/CommandLine.scala (renamed from src/compiler/scala/tools/nsc/util/CommandLineParser.scala)49
6 files changed, 79 insertions, 100 deletions
diff --git a/src/compiler/scala/tools/cmd/CommandLine.scala b/src/compiler/scala/tools/cmd/CommandLine.scala
index e8ac882ee6..e44752eb6e 100644
--- a/src/compiler/scala/tools/cmd/CommandLine.scala
+++ b/src/compiler/scala/tools/cmd/CommandLine.scala
@@ -16,7 +16,7 @@ trait CommandLineConfig {
/** An instance of a command line, parsed according to a Spec.
*/
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, line: String) = this(spec, CommandLineParser tokenize line)
def this(spec: Reference, args: Array[String]) = this(spec, args.toList)
import spec.{ isUnaryOption, isBinaryOption, isExpandOption }
diff --git a/src/compiler/scala/tools/cmd/CommandLineParser.scala b/src/compiler/scala/tools/cmd/CommandLineParser.scala
new file mode 100644
index 0000000000..ef55178594
--- /dev/null
+++ b/src/compiler/scala/tools/cmd/CommandLineParser.scala
@@ -0,0 +1,72 @@
+/* NEST (New Scala Test)
+ * Copyright 2007-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package cmd
+
+import scala.annotation.tailrec
+
+/** A simple (overly so) command line parser.
+ * !!! This needs a thorough test suite to make sure quoting is
+ * done correctly and portably.
+ */
+object CommandLineParser {
+ // splits a string into a quoted prefix and the rest of the string,
+ // taking escaping into account (using \)
+ // `"abc"def` will match as `DoubleQuoted(abc, def)`
+ private class QuotedExtractor(quote: Char) {
+ def unapply(in: String): Option[(String, String)] = {
+ val del = quote.toString
+ if (in startsWith del) {
+ var escaped = false
+ val (quoted, next) = (in substring 1) span {
+ case `quote` if !escaped => false
+ case '\\' if !escaped => escaped = true; true
+ case _ => escaped = false; true
+ }
+ // the only way to get out of the above loop is with an empty next or !escaped
+ // require(next.isEmpty || !escaped)
+ if (next startsWith del) Some((quoted, next substring 1))
+ else None
+ } else None
+ }
+ }
+ private object DoubleQuoted extends QuotedExtractor('"')
+ private object SingleQuoted extends QuotedExtractor('\'')
+ private val Word = """(\S+)(.*)""".r
+
+ // parse `in` for an argument, return it and the remainder of the input (or an error message)
+ // (argument may be in single/double quotes, taking escaping into account, quotes are stripped)
+ private def argument(in: String): Either[String, (String, String)] = in match {
+ case DoubleQuoted(arg, rest) => Right(arg, rest)
+ case SingleQuoted(arg, rest) => Right(arg, rest)
+ case Word(arg, rest) => Right(arg, rest)
+ case _ => Left("Illegal argument: "+ in)
+ }
+
+ // parse a list of whitespace-separated arguments (ignoring whitespace in quoted arguments)
+ @tailrec private def commandLine(in: String, accum: List[String] = Nil): Either[String, (List[String], String)] = {
+ val trimmed = in.trim
+ if (trimmed.isEmpty) Right(accum.reverse, "")
+ else argument(trimmed) match {
+ case Right((arg, next)) =>
+ (next span Character.isWhitespace) match {
+ case("", rest) if rest.nonEmpty => Left("Arguments should be separated by whitespace.") // TODO: can this happen?
+ case(ws, rest) => commandLine(rest, arg :: accum)
+ }
+ case Left(msg) => Left(msg)
+ }
+ }
+
+ class ParseException(msg: String) extends RuntimeException(msg)
+
+ def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
+ def tokenize(line: String, errorFn: String => Unit): List[String] = {
+ commandLine(line) match {
+ case Right((args, _)) => args
+ case Left(msg) => errorFn(msg) ; Nil
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/cmd/Parser.scala b/src/compiler/scala/tools/cmd/Parser.scala
deleted file mode 100644
index 6e2afa41c4..0000000000
--- a/src/compiler/scala/tools/cmd/Parser.scala
+++ /dev/null
@@ -1,52 +0,0 @@
-/* NEST (New Scala Test)
- * Copyright 2007-2013 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools
-package cmd
-
-import scala.util.parsing.combinator._
-import scala.util.parsing.input.CharArrayReader.EofCh
-
-/** A simple (overly so) command line parser.
- * !!! This needs a thorough test suite to make sure quoting is
- * done correctly and portably.
- */
-trait ParserUtil extends Parsers {
- class ParserPlus[+T](underlying: Parser[T]) {
- def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b }
- def <~![U](p: => Parser[U]): Parser[T] = (underlying ~! p) ^^ { case a~b => a }
- }
- protected implicit def parser2parserPlus[T](p: Parser[T]): ParserPlus[T] = new ParserPlus(p)
-}
-
-object Parser extends RegexParsers with ParserUtil {
- override def skipWhitespace = false
-
- def elemExcept(xs: Elem*): Parser[Elem] = elem("elemExcept", x => x != EofCh && !(xs contains x))
- def elemOf(xs: Elem*): Parser[Elem] = elem("elemOf", xs contains _)
- def escaped(ch: Char): Parser[String] = "\\" + ch
- def mkQuoted(ch: Char): Parser[String] = (
- elem(ch) !~> rep(escaped(ch) | elemExcept(ch)) <~ ch ^^ (_.mkString)
- | failure("Unmatched %s in input." format ch)
- )
-
- /** Apparently windows can't deal with the quotes sticking around. */
- lazy val squoted: Parser[String] = mkQuoted('\'') // ^^ (x => "'%s'" format x)
- lazy val dquoted: Parser[String] = mkQuoted('"') // ^^ (x => "\"" + x + "\"")
- lazy val token: Parser[String] = """\S+""".r
-
- lazy val argument: Parser[String] = squoted | dquoted | token
- lazy val commandLine: Parser[List[String]] = phrase(repsep(argument, whiteSpace))
-
- class ParseException(msg: String) extends RuntimeException(msg)
-
- def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
- def tokenize(line: String, errorFn: String => Unit): List[String] = {
- parse(commandLine, line.trim) match {
- case Success(args, _) => args
- case NoSuccess(msg, rest) => errorFn(msg) ; Nil
- }
- }
-}
diff --git a/src/compiler/scala/tools/cmd/package.scala b/src/compiler/scala/tools/cmd/package.scala
index c62a977950..7d67fa738b 100644
--- a/src/compiler/scala/tools/cmd/package.scala
+++ b/src/compiler/scala/tools/cmd/package.scala
@@ -22,7 +22,7 @@ package object cmd {
def toOpt(s: String) = if (s startsWith "--") s else "--" + s
def fromOpt(s: String) = s stripPrefix "--"
- def toArgs(line: String) = Parser tokenize line
+ def toArgs(line: String) = CommandLineParser tokenize line
def fromArgs(args: List[String]) = args mkString " "
def stripQuotes(s: String) = {
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index cd23ad74e4..b5cc89c0c8 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -107,7 +107,7 @@ class MutableSettings(val errorFn: String => Unit)
/** Split the given line into parameters.
*/
- def splitParams(line: String) = cmd.Parser.tokenize(line, errorFn)
+ def splitParams(line: String) = cmd.CommandLineParser.tokenize(line, errorFn)
/** Returns any unprocessed arguments.
*/
diff --git a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala b/src/compiler/scala/tools/nsc/util/CommandLine.scala
index e8f962a9e2..ef28f6dc53 100644
--- a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala
+++ b/src/compiler/scala/tools/nsc/util/CommandLine.scala
@@ -3,27 +3,16 @@
* @author Paul Phillips
*/
-package scala.tools.nsc
-package util
+package scala.tools
+package nsc.util
-import scala.util.parsing.combinator._
-import scala.util.parsing.input.CharArrayReader.EofCh
import scala.collection.mutable.ListBuffer
-/** A simple command line parser to replace the several different
- * simple ones spread around trunk.
- *
+/**
* XXX Note this has been completely obsolesced by scala.tools.cmd.
* I checked it back in as part of rolling partest back a month
* rather than go down the rabbit hole of unravelling dependencies.
*/
-
-trait ParserUtil extends Parsers {
- protected implicit class ParserPlus[+T](underlying: Parser[T]) {
- def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b }
- }
-}
-
case class CommandLine(
args: List[String],
unaryArguments: List[String],
@@ -31,7 +20,7 @@ case class CommandLine(
) {
def this(args: List[String]) = this(args, Nil, Nil)
def this(args: Array[String]) = this(args.toList, Nil, Nil)
- def this(line: String) = this(CommandLineParser tokenize line, Nil, Nil)
+ def this(line: String) = this(cmd.CommandLineParser tokenize line, Nil, Nil)
def withUnaryArgs(xs: List[String]) = copy(unaryArguments = xs)
def withBinaryArgs(xs: List[String]) = copy(binaryArguments = xs)
@@ -107,33 +96,3 @@ case class CommandLine(
override def toString() = "CommandLine(\n%s)\n" format (args map (" " + _ + "\n") mkString)
}
-
-object CommandLineParser extends RegexParsers with ParserUtil {
- override def skipWhitespace = false
-
- def elemExcept(xs: Elem*): Parser[Elem] = elem("elemExcept", x => x != EofCh && !(xs contains x))
- def escaped(ch: Char): Parser[String] = "\\" + ch
- def mkQuoted(ch: Char): Parser[String] = (
- elem(ch) !~> rep(escaped(ch) | elemExcept(ch)) <~ ch ^^ (_.mkString)
- | failure("Unmatched %s in input." format ch)
- )
-
- /** Apparently windows can't deal with the quotes sticking around. */
- lazy val squoted: Parser[String] = mkQuoted('\'') // ^^ (x => "'%s'" format x)
- lazy val dquoted: Parser[String] = mkQuoted('"') // ^^ (x => "\"" + x + "\"")
- lazy val token: Parser[String] = """\S+""".r
-
- lazy val argument: Parser[String] = squoted | dquoted | token
- lazy val commandLine: Parser[List[String]] = phrase(repsep(argument, whiteSpace))
-
- class ParseException(msg: String) extends RuntimeException(msg)
-
- def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
- def tokenize(line: String, errorFn: String => Unit): List[String] = {
- parse(commandLine, line.trim) match {
- case Success(args, _) => args
- case NoSuccess(msg, rest) => errorFn(msg) ; Nil
- }
- }
- def apply(line: String) = new CommandLine(tokenize(line))
-}