From d863c7152cf8c363b4f9c086c62d28b37baf07ea Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 24 Jun 2013 13:55:02 -0700 Subject: Remove dependency on combinators from CommandLinerParser. tools.cmd.CommandLineParser uses a small hand-rolled parser TODO: replace partest's usage of scala.tools.nsc.util.CommandLine by scala.tools.cmd.CommandLine --- .../scala/tools/nsc/util/CommandLine.scala | 98 +++++++++++++++ .../scala/tools/nsc/util/CommandLineParser.scala | 139 --------------------- 2 files changed, 98 insertions(+), 139 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/util/CommandLine.scala delete mode 100644 src/compiler/scala/tools/nsc/util/CommandLineParser.scala (limited to 'src/compiler/scala/tools/nsc/util') diff --git a/src/compiler/scala/tools/nsc/util/CommandLine.scala b/src/compiler/scala/tools/nsc/util/CommandLine.scala new file mode 100644 index 0000000000..ef28f6dc53 --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/CommandLine.scala @@ -0,0 +1,98 @@ +/* NEST (New Scala Test) + * Copyright 2007-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package nsc.util + +import scala.collection.mutable.ListBuffer + +/** + * 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. + */ +case class CommandLine( + args: List[String], + unaryArguments: List[String], + binaryArguments: List[String] +) { + def this(args: List[String]) = this(args, Nil, Nil) + def this(args: Array[String]) = this(args.toList, 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) + + 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 stripQuotes(s: String) = { + def isQuotedBy(c: Char) = s.length > 0 && s.head == c && s.last == c + if (List('"', '\'') exists isQuotedBy) s.tail.init else s + } + + def isValidOption(s: String) = !onlyKnownOptions || (unaryArguments contains s) || (binaryArguments contains s) + def isOption(s: String) = (s startsWith "-") && (isValidOption(s) || { unknownOption(s) ; false }) + def isUnary(s: String) = isOption(s) && (unaryArguments contains s) + def isBinary(s: String) = isOption(s) && !isUnary(s) && (assumeBinary || (binaryArguments contains s)) + + 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]() } + if (args.isEmpty) return Map() + val hd :: rest = args + if (rest.isEmpty) { + if (isBinary(hd) && enforceArity) + missingArg(hd, "EOF") + + if (isOption(hd)) mapForUnary(hd) else residual(args) + } + else + if (hd == Terminator) residual(rest) + else { + val hd1 :: hd2 :: rest = args + + if (hd2 == Terminator) mapForUnary(hd1) ++ residual(rest) + else if (isUnary(hd1)) mapForUnary(hd1) ++ loop(hd2 :: rest) + else if (isBinary(hd1)) { + // Disabling this check so + // --scalacopts "-verbose" works. We can't tell if it's quoted, + // the shell does us in. + // + // if (isOption(hd2) && enforceArity) + // missingArg(hd1, hd2) + + Map(hd1 -> hd2) ++ loop(rest) + } + else { residual(List(hd1)) ++ loop(hd2 :: rest) } + } + } + + (loop(args), residualBuffer map stripQuotes toList) + } + + def isSet(arg: String) = args contains arg + def get(arg: String) = argMap get arg + def apply(arg: String) = argMap(arg) + + override def toString() = "CommandLine(\n%s)\n" format (args map (" " + _ + "\n") mkString) +} diff --git a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala b/src/compiler/scala/tools/nsc/util/CommandLineParser.scala deleted file mode 100644 index e8f962a9e2..0000000000 --- a/src/compiler/scala/tools/nsc/util/CommandLineParser.scala +++ /dev/null @@ -1,139 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package 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], - binaryArguments: List[String] -) { - 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 withUnaryArgs(xs: List[String]) = copy(unaryArguments = xs) - def withBinaryArgs(xs: List[String]) = copy(binaryArguments = xs) - - 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 stripQuotes(s: String) = { - def isQuotedBy(c: Char) = s.length > 0 && s.head == c && s.last == c - if (List('"', '\'') exists isQuotedBy) s.tail.init else s - } - - def isValidOption(s: String) = !onlyKnownOptions || (unaryArguments contains s) || (binaryArguments contains s) - def isOption(s: String) = (s startsWith "-") && (isValidOption(s) || { unknownOption(s) ; false }) - def isUnary(s: String) = isOption(s) && (unaryArguments contains s) - def isBinary(s: String) = isOption(s) && !isUnary(s) && (assumeBinary || (binaryArguments contains s)) - - 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]() } - if (args.isEmpty) return Map() - val hd :: rest = args - if (rest.isEmpty) { - if (isBinary(hd) && enforceArity) - missingArg(hd, "EOF") - - if (isOption(hd)) mapForUnary(hd) else residual(args) - } - else - if (hd == Terminator) residual(rest) - else { - val hd1 :: hd2 :: rest = args - - if (hd2 == Terminator) mapForUnary(hd1) ++ residual(rest) - else if (isUnary(hd1)) mapForUnary(hd1) ++ loop(hd2 :: rest) - else if (isBinary(hd1)) { - // Disabling this check so - // --scalacopts "-verbose" works. We can't tell if it's quoted, - // the shell does us in. - // - // if (isOption(hd2) && enforceArity) - // missingArg(hd1, hd2) - - Map(hd1 -> hd2) ++ loop(rest) - } - else { residual(List(hd1)) ++ loop(hd2 :: rest) } - } - } - - (loop(args), residualBuffer map stripQuotes toList) - } - - def isSet(arg: String) = args contains arg - def get(arg: String) = argMap get arg - def apply(arg: String) = argMap(arg) - - 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)) -} -- cgit v1.2.3