Skip to content

Commit 04ac312

Browse files
authored
Merge pull request #2765 from dotty-staging/fix-2759
Fix #2759: support params like @file.txt for dotc
2 parents 618f826 + a885671 commit 04ac312

File tree

3 files changed

+81
-8
lines changed

3 files changed

+81
-8
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package dotty.tools.dotc
2+
package config
3+
4+
import scala.annotation.tailrec
5+
import dotty.tools.sharable
6+
7+
/** A simple (overly so) command line parser.
8+
* !!! This needs a thorough test suite to make sure quoting is
9+
* done correctly and portably.
10+
*/
11+
object CommandLineParser {
12+
// splits a string into a quoted prefix and the rest of the string,
13+
// taking escaping into account (using \)
14+
// `"abc"def` will match as `DoubleQuoted(abc, def)`
15+
private class QuotedExtractor(quote: Char) {
16+
def unapply(in: String): Option[(String, String)] = {
17+
val del = quote.toString
18+
if (in startsWith del) {
19+
var escaped = false
20+
val (quoted, next) = (in substring 1) span {
21+
case `quote` if !escaped => false
22+
case '\\' if !escaped => escaped = true; true
23+
case _ => escaped = false; true
24+
}
25+
// the only way to get out of the above loop is with an empty next or !escaped
26+
// require(next.isEmpty || !escaped)
27+
if (next startsWith del) Some((quoted, next substring 1))
28+
else None
29+
} else None
30+
}
31+
}
32+
private object DoubleQuoted extends QuotedExtractor('"')
33+
private object SingleQuoted extends QuotedExtractor('\'')
34+
@sharable private val Word = """(\S+)(.*)""".r
35+
36+
// parse `in` for an argument, return it and the remainder of the input (or an error message)
37+
// (argument may be in single/double quotes, taking escaping into account, quotes are stripped)
38+
private def argument(in: String): Either[String, (String, String)] = in match {
39+
case DoubleQuoted(arg, rest) => Right((arg, rest))
40+
case SingleQuoted(arg, rest) => Right((arg, rest))
41+
case Word(arg, rest) => Right((arg, rest))
42+
case _ => Left(s"Illegal argument: $in")
43+
}
44+
45+
// parse a list of whitespace-separated arguments (ignoring whitespace in quoted arguments)
46+
@tailrec private def commandLine(in: String, accum: List[String] = Nil): Either[String, (List[String], String)] = {
47+
val trimmed = in.trim
48+
if (trimmed.isEmpty) Right((accum.reverse, ""))
49+
else argument(trimmed) match {
50+
case Right((arg, next)) =>
51+
(next span Character.isWhitespace) match {
52+
case("", rest) if rest.nonEmpty => Left("Arguments should be separated by whitespace.") // TODO: can this happen?
53+
case(ws, rest) => commandLine(rest, arg :: accum)
54+
}
55+
case Left(msg) => Left(msg)
56+
}
57+
}
58+
59+
class ParseException(msg: String) extends RuntimeException(msg)
60+
61+
def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
62+
def tokenize(line: String, errorFn: String => Unit): List[String] = {
63+
commandLine(line) match {
64+
case Right((args, _)) => args
65+
case Left(msg) => errorFn(msg) ; Nil
66+
}
67+
}
68+
}

compiler/src/dotty/tools/dotc/config/CompilerCommand.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package dotty.tools.dotc
22
package config
33

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

46-
settings splitParams (file.lines() map stripComment mkString " ")
47-
}*/
46+
import scala.collection.JavaConversions._
47+
val lines = Files.readAllLines(path) // default to UTF-8 encoding
48+
49+
val params = lines map stripComment mkString " "
50+
CommandLineParser.tokenize(params)
51+
}
4852

4953
// expand out @filename to the contents of that filename
5054
def expandedArguments = args.toList flatMap {

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ class CompilationTests extends ParallelTesting {
219219
defaultOutputDir + "lib/src/:" +
220220
// as well as bootstrapped compiler:
221221
defaultOutputDir + "dotty1/dotty/:" +
222-
Jars.dottyInterfaces
222+
Jars.dottyInterfaces,
223+
"-Ycheck-reentrant"
223224
)
224225

225226
def lib =

0 commit comments

Comments
 (0)