Skip to content

Commit b174eff

Browse files
committed
Command line parser respects outer escaped quote
1 parent 75d8eea commit b174eff

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ object CommandLineParser:
2929
inline def bump() = pos += 1
3030
inline def done = pos >= line.length
3131

32+
// Skip to the next quote as given; false on no more input.
3233
def skipToQuote(q: Int): Boolean =
3334
var escaped = false
3435
def terminal = cur match
@@ -39,13 +40,18 @@ object CommandLineParser:
3940
while !terminal do bump()
4041
!done
4142

42-
@tailrec def skipToDelim(): Boolean =
43+
// Skip to a word boundary, where words can be quoted and quotes can be escaped; false on missing quote.
44+
def skipToDelim(): Boolean =
45+
var escaped = false
4346
inline def quote() = { qpos += pos ; bump() }
44-
cur match
47+
def advance(): Boolean = cur match
48+
case _ if escaped => escaped = false ; bump() ; advance()
49+
case '\\' => escaped = true ; bump() ; advance()
4550
case q @ (DQ | SQ) => { quote() ; skipToQuote(q) } && { quote() ; skipToDelim() }
4651
case -1 => true
4752
case c if isWhitespace(c) => true
4853
case _ => bump(); skipToDelim()
54+
advance()
4955

5056
def copyText(): String =
5157
val buf = new java.lang.StringBuilder
@@ -74,7 +80,7 @@ object CommandLineParser:
7480

7581
inline def badquote() = errorFn(s"Unmatched quote [${qpos.last}](${line.charAt(qpos.last)})")
7682

77-
inline def skipWhitespace() = while isWhitespace(cur) do pos += 1
83+
inline def skipWhitespace() = while isWhitespace(cur) do bump()
7884

7985
@tailrec def loop(): List[String] =
8086
skipWhitespace()
@@ -85,7 +91,7 @@ object CommandLineParser:
8591
badquote()
8692
Nil
8793
else
88-
accum = text() :: accum
94+
accum ::= text()
8995
loop()
9096
end loop
9197

compiler/test/dotty/tools/dotc/config/CommandLineParserTest.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ class CommandLineParserTest:
4444
// missing quotes
4545
checkFails(""""x""", "Unmatched quote [0](\")") // was assertEquals(List("\"x"), tokenize(""""x"""))
4646
checkFails("""x'""", "Unmatched quote [1](')")
47+
48+
@Test def `leading quote is escaped`: Unit =
49+
check("echo", """\"hello""", """world!\"""")("""echo \"hello world!\" """)
50+
check("""a\"b\"c""")("""a\"b\"c""")
51+
check("a", "\\'b", "\\'", "c")("""a \'b \' c""")
52+
check("a", "\\\\b ", "c")("""a \\'b ' c""")

0 commit comments

Comments
 (0)