Skip to content

Commit 1100d43

Browse files
committed
Refactor statement loops
1 parent 542258b commit 1100d43

File tree

5 files changed

+41
-15
lines changed

5 files changed

+41
-15
lines changed

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

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ object Parsers {
254254
|| skipStopTokens.contains(in.token) && (in.currentRegion eq lastRegion)
255255
while !atStop do
256256
in.nextToken()
257+
lastErrorOffset = in.offset
257258

258259
def warning(msg: Message, sourcePos: SourcePosition): Unit =
259260
report.warning(msg, sourcePos)
@@ -273,11 +274,9 @@ object Parsers {
273274
*/
274275
def syntaxErrorOrIncomplete(msg: Message, offset: Int = in.offset): Unit =
275276
if (in.token == EOF) incompleteInputError(msg)
276-
else {
277+
else
277278
syntaxError(msg, offset)
278279
skip()
279-
lastErrorOffset = in.offset
280-
}
281280

282281
/** Consume one token of the specified type, or
283282
* signal an error if it is not there.
@@ -312,6 +311,35 @@ object Parsers {
312311
def acceptStatSep(): Unit =
313312
if in.isNewLine then in.nextToken() else accept(SEMI)
314313

314+
def exitStats[T <: Tree](stats: ListBuffer[T], altEnd: Token = EOF, noPrevStat: Boolean): Boolean =
315+
def recur(sepSeen: Boolean, endSeen: Boolean): Boolean =
316+
if isStatSep then
317+
in.nextToken()
318+
recur(true, endSeen)
319+
else if in.token == END then
320+
if endSeen then syntaxError("duplicate end marker")
321+
checkEndMarker(stats)
322+
recur(sepSeen, true)
323+
else if isStatSeqEnd || in.token == altEnd then
324+
true
325+
else if sepSeen || endSeen then
326+
false
327+
else
328+
val found = in.token
329+
syntaxError(
330+
if noPrevStat then IllegalStartOfStatement(isModifier)
331+
else i"end of statement expected but ${showToken(found)} found")
332+
if mustStartStatTokens.contains(found) then
333+
true // it's a statement that might be legal in an outer context
334+
else
335+
in.nextToken() // needed to ensure progress; otherwise we might cycle forever
336+
skip()
337+
false
338+
339+
in.observeOutdented()
340+
recur(false, false)
341+
end exitStats
342+
315343
def acceptStatSepUnlessAtEnd[T <: Tree](stats: ListBuffer[T], altEnd: Token = EOF): Unit =
316344
def skipEmptyStats(): Unit =
317345
while (in.token == SEMI || in.token == NEWLINE || in.token == NEWLINES) do in.nextToken()
@@ -3891,8 +3919,8 @@ object Parsers {
38913919
*/
38923920
def blockStatSeq(): List[Tree] = checkNoEscapingPlaceholders {
38933921
val stats = new ListBuffer[Tree]
3894-
var exitOnError = false
3895-
while (!isStatSeqEnd && in.token != CASE && !exitOnError) {
3922+
while
3923+
var empty = false
38963924
if (in.token == IMPORT)
38973925
stats ++= importClause(IMPORT, mkImport())
38983926
else if (isExprIntro)
@@ -3903,12 +3931,10 @@ object Parsers {
39033931
stats += extension()
39043932
else if isDefIntro(localModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then
39053933
stats +++= localDef(in.offset)
3906-
else if (!isStatSep && (in.token != CASE)) {
3907-
exitOnError = mustStartStat
3908-
syntaxErrorOrIncomplete(IllegalStartOfStatement(isModifier))
3909-
}
3910-
acceptStatSepUnlessAtEnd(stats, CASE)
3911-
}
3934+
else
3935+
empty = true
3936+
!exitStats(stats, CASE, empty)
3937+
do ()
39123938
stats.toList
39133939
}
39143940

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1826,7 +1826,7 @@ import transform.SymUtils._
18261826

18271827
class IllegalStartOfStatement(isModifier: Boolean)(using Context) extends SyntaxMsg(IllegalStartOfStatementID) {
18281828
def msg = {
1829-
val addendum = if (isModifier) ": no modifiers allowed here" else ""
1829+
val addendum = if (isModifier) ": this modifier is not allowed here" else ""
18301830
"Illegal start of statement" + addendum
18311831
}
18321832
def explain = "A statement is either an import, a definition or an expression."

tests/neg-macros/i7603.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import scala.quoted.*
22
class Foo {
33
def f[T2: Type](e: Expr[T2])(using Quotes) = e match {
44
case '{ $x: ${'[List[$t]]} } => // error
5-
case '{ $x: ${y @ '[List[$t]]} } => // error // error
5+
case '{ $x: ${y @ '[List[$t]]} } => // error
66
}
77
}

tests/neg/indent.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ object Test {
22

33
extension (x: Int) def gt(y: Int) = x > y
44
val y3 =
5-
if (1) max 10 gt 0 // error: end of statement expected but integer literal found // error // error // error
5+
if (1) max 10 gt 0 // error: end of statement expected but integer literal found // error // error
66
1
77
else
88
2

tests/neg/multiLineOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ val b1 = {
66
22
77
* 22 // ok
88
*/*one more*/22 // error: end of statement expected // error: not found: *
9-
} // error: ';' expected, but '}' found
9+
}
1010

1111
val b2: Boolean = {
1212
println(x)

0 commit comments

Comments
 (0)