Skip to content

Commit 60b2d74

Browse files
committed
Reorganize rewrite flags
and fixes to rewrite rules in Parser # Conflicts: # compiler/src/dotty/tools/dotc/parsing/Scanners.scala
1 parent b4aa856 commit 60b2d74

File tree

4 files changed

+150
-57
lines changed

4 files changed

+150
-57
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ class ScalaSettings extends Settings.SettingGroup {
2525
val priorityclasspath: Setting[String] = PathSetting("-priorityclasspath", "class path that takes precedence over all other paths (or testing only)", "") withAbbreviation "--priority-class-path"
2626

2727
/** Other settings */
28-
val cleansyntax: Setting[Boolean] = BooleanSetting("-cleansyntax", "allow control expressions without parentheses")
29-
val revertClean: Setting[Boolean] = BooleanSetting("-revertclean", "when used with -rewrite, rewrite from clean syntax to classical (...) syntax")
3028
val deprecation: Setting[Boolean] = BooleanSetting("-deprecation", "Emit warning and location for usages of deprecated APIs.") withAbbreviation "--deprecation"
3129
val migration: Setting[Boolean] = BooleanSetting("-migration", "Emit warning and location for migration issues from Scala 2.") withAbbreviation "--migration"
3230
val encoding: Setting[String] = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding) withAbbreviation "--encoding"
@@ -50,6 +48,9 @@ class ScalaSettings extends Settings.SettingGroup {
5048
val silentWarnings: Setting[Boolean] = BooleanSetting("-nowarn", "Silence all warnings.") withAbbreviation "--no-warnings"
5149
val fromTasty: Setting[Boolean] = BooleanSetting("-from-tasty", "Compile classes from tasty in classpath. The arguments are used as class names.") withAbbreviation "--from-tasty"
5250

51+
val cStyle: Setting[Boolean] = BooleanSetting("-c-style", "when used with -rewrite, produces control expressions with parentheses")
52+
val pascalStyle: Setting[Boolean] = BooleanSetting("-pascal-style", "when used with -rewrite, produces control expressions without parentheses")
53+
5354
/** Decompiler settings */
5455
val printTasty: Setting[Boolean] = BooleanSetting("-print-tasty", "Prints the raw tasty.") withAbbreviation "--print-tasty"
5556
val printLines: Setting[Boolean] = BooleanSetting("-print-lines", "Show source code line numbers.") withAbbreviation "--print-lines"

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -576,12 +576,13 @@ object Parsers {
576576
/** Drop (...) or { ... }, replacing the closing element with `endStr` */
577577
def dropParensOrBraces(start: Offset, endStr: String): Unit = {
578578
patch(source, Span(start, start + 1), "")
579-
val filler = if (in.lastOffset == in.offset) " " else ""
580579
val closingStartsLine = testChar(skipBlanks(in.lastOffset - 2, -1), Chars.LF)
580+
val preFill = if (closingStartsLine || endStr.isEmpty) "" else " "
581+
val postFill = if (in.lastOffset == in.offset) " " else ""
581582
val (startClosing, endClosing) =
582583
if (closingStartsLine && endStr.isEmpty) closingElimRegion()
583584
else (in.lastOffset - 1, in.lastOffset)
584-
patch(source, Span(startClosing, endClosing), s"$endStr$filler")
585+
patch(source, Span(startClosing, endClosing), s"$preFill$endStr$postFill")
585586
}
586587

587588
/** rewrite code with (...) around the source code of `t` */
@@ -1346,19 +1347,21 @@ object Parsers {
13461347
if (in.token == LPAREN) {
13471348
var t: Tree = atSpan(in.offset) { Parens(inParens(exprInParens())) }
13481349
if (in.token != altToken && followedByToken(altToken))
1349-
t = inSepRegion(LPAREN, RPAREN)(
1350-
expr1Rest(postfixExprRest(simpleExprRest(t)), Location.ElseWhere))
1350+
t = inSepRegion(LPAREN, RPAREN) {
1351+
newLineOpt()
1352+
expr1Rest(postfixExprRest(simpleExprRest(t)), Location.ElseWhere)
1353+
}
13511354
if (in.token == altToken) {
13521355
in.nextToken()
1353-
if (in.revertCleanRewrite) revertToParens(t)
1356+
if (in.rewriteC) revertToParens(t)
13541357
}
1355-
else if (in.cleanRewrite)
1356-
dropParensOrBraces(t.span.start, s" ${tokenString(altToken)}")
1358+
else if (in.rewritePascal)
1359+
dropParensOrBraces(t.span.start, s"${tokenString(altToken)}")
13571360
t
13581361
} else {
13591362
val t = inSepRegion(LPAREN, RPAREN)(expr())
13601363
accept(altToken)
1361-
if (in.revertCleanRewrite) revertToParens(t)
1364+
if (in.rewriteC) revertToParens(t)
13621365
t
13631366
}
13641367
}
@@ -1451,7 +1454,7 @@ object Parsers {
14511454
in.errorOrMigrationWarning(
14521455
i"""`do <body> while <cond>' is no longer supported,
14531456
|use `while ({<body> ; <cond>}) ()' instead.
1454-
|The statement can be rewritten automatically under -language:Scala2 -migration -rewrite.
1457+
|The statement can be rewritten automatically under -language:Scala2 -rewrite.
14551458
""")
14561459
val start = in.skipToken()
14571460
atSpan(start) {
@@ -1460,7 +1463,7 @@ object Parsers {
14601463
val whileStart = in.offset
14611464
accept(WHILE)
14621465
val cond = expr()
1463-
if (ctx.settings.migration.value) {
1466+
if (in.isScala2Mode) {
14641467
patch(source, Span(start, start + 2), "while ({")
14651468
patch(source, Span(whileStart, whileStart + 5), ";")
14661469
cond match {
@@ -1919,8 +1922,13 @@ object Parsers {
19191922
def enumerators(): List[Tree] = generator() :: enumeratorsRest()
19201923

19211924
def enumeratorsRest(): List[Tree] =
1922-
if (isStatSep) { in.nextToken(); enumerator() :: enumeratorsRest() }
1923-
else if (in.token == IF) guard() :: enumeratorsRest()
1925+
if (isStatSep) {
1926+
in.nextToken()
1927+
if (in.token == DO || in.token == YIELD || in.token == RBRACE) Nil
1928+
else enumerator() :: enumeratorsRest()
1929+
}
1930+
else if (in.token == IF)
1931+
guard() :: enumeratorsRest()
19241932
else Nil
19251933

19261934
/** Enumerator ::= Generator
@@ -1959,62 +1967,76 @@ object Parsers {
19591967
def forExpr(): Tree = atSpan(in.skipToken()) {
19601968
var wrappedEnums = true
19611969
val start = in.offset
1962-
val oldSyntax = in.token == LBRACE || in.token == LPAREN && parensEncloseGenerators
1970+
val forEnd = in.lastOffset
1971+
val leading = in.token
19631972
val enums =
1964-
if (oldSyntax)
1965-
if (in.token == LBRACE)
1966-
inBraces(enumerators())
1967-
else {
1968-
val lparenOffset = in.skipToken()
1969-
openParens.change(LPAREN, 1)
1970-
val res =
1971-
if (in.token == CASE) enumerators()
1972-
else {
1973-
val pats = patternsOpt()
1974-
val pat =
1975-
if (in.token == RPAREN || pats.length > 1) {
1976-
wrappedEnums = false
1977-
accept(RPAREN)
1978-
openParens.change(LPAREN, -1)
1979-
atSpan(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
1980-
}
1981-
else pats.head
1982-
generatorRest(pat, casePat = false) :: enumeratorsRest()
1983-
}
1984-
if (wrappedEnums) {
1985-
accept(RPAREN)
1986-
openParens.change(LPAREN, -1)
1973+
if (leading == LBRACE || leading == LPAREN && parensEncloseGenerators) {
1974+
var enumsOnNewLine = in.isAfterLineEnd() // if true, enums start on new line after `for`, so newlines are significant under Pascal-style syntax
1975+
in.nextToken()
1976+
enumsOnNewLine |= in.isAfterLineEnd()
1977+
openParens.change(leading, 1)
1978+
val res =
1979+
if (leading == LBRACE || in.token == CASE)
1980+
enumerators()
1981+
else {
1982+
val pats = patternsOpt()
1983+
val pat =
1984+
if (in.token == RPAREN || pats.length > 1) {
1985+
wrappedEnums = false
1986+
accept(RPAREN)
1987+
openParens.change(LPAREN, -1)
1988+
atSpan(start) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
1989+
}
1990+
else pats.head
1991+
generatorRest(pat, casePat = false) :: enumeratorsRest()
1992+
}
1993+
if (wrappedEnums) {
1994+
val closingOnNewLine = in.isAfterLineEnd()
1995+
accept(leading + 1)
1996+
openParens.change(leading, -1)
1997+
if (in.rewritePascal && enumsOnNewLine == (leading == LBRACE)) { // Don't rewrite if that would change meaning of newlines
1998+
newLinesOpt()
1999+
dropParensOrBraces(start, if (in.token == YIELD || in.token == DO) "" else "do")
19872000
}
1988-
res
19892001
}
2002+
res
2003+
}
19902004
else {
19912005
wrappedEnums = false
1992-
1993-
/*if (in.token == INDENT) inBracesOrIndented(enumerators())
1994-
else*/ {
1995-
val ts = // If we use indent syntax, the distinction below should no longer be necessary
1996-
if (in.isAfterLineEnd()) enumerators()
1997-
else inSepRegion(LPAREN, RPAREN)(enumerators())
1998-
if (in.revertCleanRewrite && ts.nonEmpty) {
2006+
val impliedBraces = in.isAfterLineEnd()
2007+
2008+
/*if (in.token == INDENT) inBracesOrIndented(enumerators()) else*/
2009+
val ts = // If we use indent syntax, the distinction below should no longer be necessary
2010+
if (impliedBraces) enumerators()
2011+
else inSepRegion(LPAREN, RPAREN)(enumerators())
2012+
if (in.rewriteC && ts.nonEmpty) {
2013+
if (impliedBraces) {
2014+
patch(source, Span(forEnd), " {")
2015+
patch(source, Span(in.offset), "} ")
2016+
}
2017+
else {
19992018
patch(source, ts.head.span.startPos, "(")
20002019
patch(source, ts.last.span.endPos, ")")
20012020
}
2002-
ts
20032021
}
2022+
ts
20042023
}
2005-
if (in.cleanRewrite && oldSyntax) {
2006-
dropParensOrBraces(start, if (in.token == YIELD) "" else " do")
2007-
}
20082024
newLinesOpt()
20092025
if (in.token == YIELD) {
20102026
in.nextToken()
20112027
ForYield(enums, expr())
20122028
}
20132029
else if (in.token == DO) {
2014-
if (in.revertCleanRewrite) {
2015-
var endPos = in.lastCharOffset
2016-
//if (testChar(endPos, ' ')) endPos += 1
2017-
patch(source, Span(in.offset - 1, endPos), "")
2030+
if (in.rewriteC) {
2031+
var startOffset = in.offset
2032+
var endOffset = in.lastCharOffset
2033+
if (in.isAfterLineEnd()) {
2034+
if (testChar(endOffset, ' ')) endOffset += 1
2035+
}
2036+
else {
2037+
if (testChar(startOffset - 1, ' ')) startOffset -= 1
2038+
}
2039+
patch(source, Span(startOffset, endOffset), "")
20182040
}
20192041
in.nextToken()
20202042
ForDo(enums, expr())
@@ -2147,6 +2169,7 @@ object Parsers {
21472169
case _ =>
21482170
if (isLiteral) literal(inPattern = true)
21492171
else {
2172+
println(i"$in found")
21502173
syntaxErrorOrIncomplete(IllegalStartOfSimplePattern(), expectedOffset)
21512174
errorTermTree
21522175
}

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ object Scanners {
222222
/** A switch whether operators at the start of lines can be infix operators */
223223
private var allowLeadingInfixOperators = true
224224

225-
private val rewrite = ctx.settings.rewrite.value.isDefined
226-
val cleanRewrite = ctx.settings.cleansyntax.value && rewrite
227-
val revertCleanRewrite = ctx.settings.revertClean.value && rewrite
225+
val rewrite = ctx.settings.rewrite.value.isDefined
226+
val rewritePascal = rewrite && ctx.settings.pascalStyle.value
227+
val rewriteC = rewrite && ctx.settings.cStyle.value
228228

229229
/** All doc comments kept by their end position in a `Map` */
230230
private[this] var docstringMap: SortedMap[Int, Comment] = SortedMap.empty

tests/pos/syntaxRewrites.scala

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
object Test {
2+
3+
val xs = List(1, 2, 3)
4+
5+
for (x <- xs) yield x * 2
6+
7+
for (x <- xs)
8+
yield x * 2
9+
10+
for { x <- xs; y <- xs } yield x * y
11+
12+
for {
13+
x <- xs
14+
y <- xs
15+
} yield x * y
16+
17+
for {
18+
x <- xs
19+
y <- xs
20+
} yield x * y
21+
22+
for { x <- xs }
23+
yield x * 2
24+
25+
// -----------------------------------------------
26+
27+
for (x <- xs) println(x)
28+
29+
for (x <- xs)
30+
println(x)
31+
32+
for { x <- xs; y <- xs } println(x * y)
33+
34+
for {
35+
x <- xs
36+
y <- xs
37+
}
38+
println(x * y)
39+
40+
for {
41+
x <- xs
42+
y <- xs
43+
} println(x * y)
44+
45+
for { x <- xs }
46+
println(x)
47+
48+
if (xs == Nil) println("yes")
49+
50+
if (xs == Nil)
51+
println("yes")
52+
53+
if (xs == Nil
54+
&& xs.length == 0)
55+
println("yes")
56+
57+
while (xs == Nil) println("yes")
58+
59+
while ({
60+
val ys = xs ++ xs
61+
ys.nonEmpty
62+
}) println("yes")
63+
64+
while ({
65+
val ys = xs ++ xs
66+
ys.nonEmpty
67+
})
68+
println("yes")
69+
}

0 commit comments

Comments
 (0)