@@ -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
0 commit comments