Skip to content

Fix #2759: support params like @file.txt for dotc #2765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions compiler/src/dotty/tools/dotc/config/CommandLineParser.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dotty.tools.dotc
package config

import scala.annotation.tailrec
import dotty.tools.sharable

/** 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('\'')
@sharable 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(s"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
}
}
}
18 changes: 11 additions & 7 deletions compiler/src/dotty/tools/dotc/config/CompilerCommand.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dotty.tools.dotc
package config

import java.io.File
import java.nio.file.{Files, Paths}
import Settings._
import core.Contexts._
import util.DotClass
Expand Down Expand Up @@ -37,14 +37,18 @@ object CompilerCommand extends DotClass {
* Expands all arguments starting with @ to the contents of the
* file named like each argument.
*/
def expandArg(arg: String): List[String] = unsupported("expandArg")/*{
def expandArg(arg: String): List[String] = {
def stripComment(s: String) = s takeWhile (_ != '#')
val file = File(arg stripPrefix "@")
if (!file.exists)
throw new java.io.FileNotFoundException("argument file %s could not be found" format file.name)
val path = Paths.get(arg stripPrefix "@")
if (!Files.exists(path))
throw new java.io.FileNotFoundException("argument file %s could not be found" format path.getFileName)

settings splitParams (file.lines() map stripComment mkString " ")
}*/
import scala.collection.JavaConversions._
val lines = Files.readAllLines(path) // default to UTF-8 encoding

val params = lines map stripComment mkString " "
CommandLineParser.tokenize(params)
}

// expand out @filename to the contents of that filename
def expandedArguments = args.toList flatMap {
Expand Down
3 changes: 2 additions & 1 deletion compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ class CompilationTests extends ParallelTesting {
defaultOutputDir + "lib/src/:" +
// as well as bootstrapped compiler:
defaultOutputDir + "dotty1/dotty/:" +
Jars.dottyInterfaces
Jars.dottyInterfaces,
"-Ycheck-reentrant"
)

def lib =
Expand Down