Skip to content

Commit 0aafca1

Browse files
authored
Merge pull request #14695 from dotty-staging/syntax-error-recovery
Syntax error recovery
2 parents 84fc139 + 8364bb2 commit 0aafca1

21 files changed

+370
-104
lines changed

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

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ object Parsers {
225225
|| allowedMods.contains(in.token)
226226
|| in.isSoftModifierInModifierPosition && !excludedSoftModifiers.contains(in.name)
227227

228-
def isStatSep: Boolean = in.isNewLine || in.token == SEMI
228+
def isStatSep: Boolean = in.isStatSep
229229

230230
/** A '$' identifier is treated as a splice if followed by a `{`.
231231
* A longer identifier starting with `$` is treated as a splice/id combination
@@ -252,13 +252,8 @@ object Parsers {
252252

253253
/** Skip on error to next safe point.
254254
*/
255-
protected def skip(stopAtComma: Boolean): Unit =
256-
val lastRegion = in.currentRegion
257-
def atStop =
258-
in.token == EOF
259-
|| ((stopAtComma && in.token == COMMA) || skipStopTokens.contains(in.token)) && (in.currentRegion eq lastRegion)
260-
while !atStop do
261-
in.nextToken()
255+
def skip(): Unit =
256+
in.skip()
262257
lastErrorOffset = in.offset
263258

264259
def warning(msg: Message, sourcePos: SourcePosition): Unit =
@@ -272,35 +267,37 @@ object Parsers {
272267

273268
/** Issue an error at current offset that input is incomplete */
274269
def incompleteInputError(msg: Message): Unit =
275-
report.incompleteInputError(msg, source.atSpan(Span(in.offset)))
270+
if in.offset != lastErrorOffset then
271+
report.incompleteInputError(msg, source.atSpan(Span(in.offset)))
276272

277273
/** If at end of file, issue an incompleteInputError.
278274
* Otherwise issue a syntax error and skip to next safe point.
279275
*/
280276
def syntaxErrorOrIncomplete(msg: Message, offset: Int = in.offset): Unit =
281-
if (in.token == EOF) incompleteInputError(msg)
277+
if in.token == EOF then
278+
incompleteInputError(msg)
282279
else
283280
syntaxError(msg, offset)
284-
skip(stopAtComma = true)
281+
skip()
285282

286283
def syntaxErrorOrIncomplete(msg: Message, span: Span): Unit =
287-
if (in.token == EOF) incompleteInputError(msg)
284+
if in.token == EOF then
285+
incompleteInputError(msg)
288286
else
289287
syntaxError(msg, span)
290-
skip(stopAtComma = true)
288+
skip()
291289

292290
/** Consume one token of the specified type, or
293291
* signal an error if it is not there.
294292
*
295293
* @return The offset at the start of the token to accept
296294
*/
297-
def accept(token: Int): Int = {
295+
def accept(token: Int): Int =
298296
val offset = in.offset
299-
if (in.token != token)
297+
if in.token != token then
300298
syntaxErrorOrIncomplete(ExpectedTokenButFound(token, in.token))
301-
if (in.token == token) in.nextToken()
299+
if in.token == token then in.nextToken()
302300
offset
303-
}
304301

305302
def accept(name: Name): Int = {
306303
val offset = in.offset
@@ -355,7 +352,7 @@ object Parsers {
355352
false // it's a statement that might be legal in an outer context
356353
else
357354
in.nextToken() // needed to ensure progress; otherwise we might cycle forever
358-
skip(stopAtComma=false)
355+
skip()
359356
true
360357

361358
in.observeOutdented()
@@ -562,18 +559,14 @@ object Parsers {
562559
def inDefScopeBraces[T](body: => T, rewriteWithColon: Boolean = false): T =
563560
inBracesOrIndented(body, rewriteWithColon)
564561

565-
/** part { `separator` part }
566-
*/
567-
def tokenSeparated[T](separator: Int, part: () => T): List[T] = {
568-
val ts = new ListBuffer[T] += part()
569-
while (in.token == separator) {
570-
in.nextToken()
571-
ts += part()
562+
def commaSeparated[T](part: () => T): List[T] =
563+
in.currentRegion.withCommasExpected {
564+
val ts = new ListBuffer[T] += part()
565+
while in.token == COMMA do
566+
in.nextToken()
567+
ts += part()
568+
ts.toList
572569
}
573-
ts.toList
574-
}
575-
576-
def commaSeparated[T](part: () => T): List[T] = tokenSeparated(COMMA, part)
577570

578571
def inSepRegion[T](f: Region => Region)(op: => T): T =
579572
val cur = in.currentRegion
@@ -3766,7 +3759,7 @@ object Parsers {
37663759
val derived =
37673760
if (isIdent(nme.derives)) {
37683761
in.nextToken()
3769-
tokenSeparated(COMMA, () => convertToTypeId(qualId()))
3762+
commaSeparated(() => convertToTypeId(qualId()))
37703763
}
37713764
else Nil
37723765
possibleTemplateStart()

0 commit comments

Comments
 (0)