@@ -249,8 +249,13 @@ object Parsers {
249
249
250
250
/** Skip on error to next safe point.
251
251
*/
252
- protected def skip (stopAtComma : Boolean ): Unit =
252
+ protected def skip (): Unit =
253
253
val lastRegion = in.currentRegion
254
+ val stopAtComma = lastRegion match {
255
+ case InParens (_, _, commaSeparated) => commaSeparated
256
+ case InBraces (_, commaSeparated) => commaSeparated
257
+ case _ => true
258
+ }
254
259
def atStop =
255
260
in.token == EOF
256
261
|| ((stopAtComma && in.token == COMMA ) || skipStopTokens.contains(in.token)) && (in.currentRegion eq lastRegion)
@@ -278,13 +283,13 @@ object Parsers {
278
283
if (in.token == EOF ) incompleteInputError(msg)
279
284
else
280
285
syntaxError(msg, offset)
281
- skip(stopAtComma = true )
286
+ skip()
282
287
283
288
def syntaxErrorOrIncomplete (msg : Message , span : Span ): Unit =
284
289
if (in.token == EOF ) incompleteInputError(msg)
285
290
else
286
291
syntaxError(msg, span)
287
- skip(stopAtComma = true )
292
+ skip()
288
293
289
294
/** Consume one token of the specified type, or
290
295
* signal an error if it is not there.
@@ -352,7 +357,7 @@ object Parsers {
352
357
false // it's a statement that might be legal in an outer context
353
358
else
354
359
in.nextToken() // needed to ensure progress; otherwise we might cycle forever
355
- skip(stopAtComma = false )
360
+ skip()
356
361
true
357
362
358
363
in.observeOutdented()
@@ -559,19 +564,55 @@ object Parsers {
559
564
def inDefScopeBraces [T ](body : => T , rewriteWithColon : Boolean = false ): T =
560
565
inBracesOrIndented(body, rewriteWithColon)
561
566
562
- /** part { `separator` part }
563
- */
564
- def tokenSeparated [T ](separator : Int , part : () => T ): List [T ] = {
565
- val ts = new ListBuffer [T ] += part()
566
- while (in.token == separator) {
567
+ /** part { `,` part }
568
+ * @param delimited If true, this comma-separated list must surrounded by brackets, parens, or braces.
569
+ */
570
+ def commaSeparated [T ](part : () => T , delimited : Boolean = true , readFirst : Boolean = true ): List [T ] = {
571
+ val expectedEnd = if (delimited) {
572
+ in.currentRegion match {
573
+ case InParens (t, outer, _) =>
574
+ in.currentRegion = InParens (t, outer, commaSeparated = true )
575
+ t match {
576
+ case LPAREN => RPAREN
577
+ case LBRACKET => RBRACKET
578
+ case _ => EMPTY
579
+ }
580
+ case InBraces (outer, _) =>
581
+ in.currentRegion = InBraces (outer, commaSeparated = true )
582
+ RBRACE
583
+ case _ => EMPTY
584
+ }
585
+ } else EMPTY
586
+ val ts = new ListBuffer [T ]
587
+ if (readFirst) ts += part()
588
+ var done = false
589
+ while (in.token == COMMA && ! done) {
567
590
in.nextToken()
568
- ts += part()
591
+ if (in.isAfterLineEnd && (in.token == OUTDENT || (expectedEnd != EMPTY && in.token == expectedEnd))) {
592
+ // skip the trailing comma
593
+ done = true
594
+ } else {
595
+ ts += part()
596
+ }
597
+ }
598
+ if (expectedEnd != EMPTY && in.token != expectedEnd) {
599
+ // As a side effect, will skip to the nearest safe point, which might be a comma
600
+ syntaxErrorOrIncomplete(ExpectedTokenButFound (expectedEnd, in.token))
601
+ if (in.token == COMMA ) {
602
+ ts ++= commaSeparated(part, delimited)
603
+ }
604
+ }
605
+ if (delimited) {
606
+ in.currentRegion match {
607
+ case InParens (t, outer, true ) =>
608
+ in.currentRegion = InParens (t, outer, commaSeparated = false )
609
+ case InBraces (outer, true ) => in.currentRegion = InBraces (outer, commaSeparated = false )
610
+ case _ =>
611
+ }
569
612
}
570
613
ts.toList
571
614
}
572
615
573
- def commaSeparated [T ](part : () => T ): List [T ] = tokenSeparated(COMMA , part)
574
-
575
616
def inSepRegion [T ](f : Region => Region )(op : => T ): T =
576
617
val cur = in.currentRegion
577
618
in.currentRegion = f(cur)
@@ -1387,14 +1428,7 @@ object Parsers {
1387
1428
else
1388
1429
Function (params, t)
1389
1430
}
1390
- def funTypeArgsRest (first : Tree , following : () => Tree ) = {
1391
- val buf = new ListBuffer [Tree ] += first
1392
- while (in.token == COMMA ) {
1393
- in.nextToken()
1394
- buf += following()
1395
- }
1396
- buf.toList
1397
- }
1431
+
1398
1432
var isValParamList = false
1399
1433
1400
1434
val t =
@@ -1410,11 +1444,10 @@ object Parsers {
1410
1444
val ts = funArgType() match {
1411
1445
case Ident (name) if name != tpnme.WILDCARD && in.isColon() =>
1412
1446
isValParamList = true
1413
- funTypeArgsRest(
1414
- typedFunParam(paramStart, name.toTermName, imods),
1415
- () => typedFunParam(in.offset, ident(), imods))
1447
+ typedFunParam(paramStart, name.toTermName, imods) :: commaSeparated(
1448
+ () => typedFunParam(in.offset, ident(), imods), readFirst = false )
1416
1449
case t =>
1417
- funTypeArgsRest(t, funArgType)
1450
+ t :: commaSeparated( funArgType,readFirst = false )
1418
1451
}
1419
1452
accept(RPAREN )
1420
1453
if isValParamList || in.isArrow then
@@ -2539,7 +2572,7 @@ object Parsers {
2539
2572
if (leading == LBRACE || in.token == CASE )
2540
2573
enumerators()
2541
2574
else {
2542
- val pats = patternsOpt()
2575
+ val pats = patternsOpt(delimited = false )
2543
2576
val pat =
2544
2577
if (in.token == RPAREN || pats.length > 1 ) {
2545
2578
wrappedEnums = false
@@ -2731,7 +2764,7 @@ object Parsers {
2731
2764
case USCORE =>
2732
2765
wildcardIdent()
2733
2766
case LPAREN =>
2734
- atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) }
2767
+ atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt(delimited = true ))) }
2735
2768
case QUOTE =>
2736
2769
simpleExpr(Location .InPattern )
2737
2770
case XMLSTART =>
@@ -2767,11 +2800,11 @@ object Parsers {
2767
2800
2768
2801
/** Patterns ::= Pattern [`,' Pattern]
2769
2802
*/
2770
- def patterns (location : Location = Location .InPattern ): List [Tree ] =
2771
- commaSeparated(() => pattern(location))
2803
+ def patterns (delimited : Boolean = false , location : Location = Location .InPattern ): List [Tree ] =
2804
+ commaSeparated(() => pattern(location), delimited )
2772
2805
2773
- def patternsOpt (location : Location = Location .InPattern ): List [Tree ] =
2774
- if (in.token == RPAREN ) Nil else patterns(location)
2806
+ def patternsOpt (delimited : Boolean , location : Location = Location .InPattern ): List [Tree ] =
2807
+ if (in.token == RPAREN ) Nil else patterns(delimited, location)
2775
2808
2776
2809
/** ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
2777
2810
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
@@ -3120,7 +3153,7 @@ object Parsers {
3120
3153
*/
3121
3154
def importClause (leading : Token , mkTree : ImportConstr ): List [Tree ] = {
3122
3155
val offset = accept(leading)
3123
- commaSeparated(importExpr(mkTree)) match {
3156
+ commaSeparated(importExpr(mkTree), delimited = false ) match {
3124
3157
case t :: rest =>
3125
3158
// The first import should start at the start offset of the keyword.
3126
3159
val firstPos =
@@ -3197,9 +3230,9 @@ object Parsers {
3197
3230
}
3198
3231
else ImportSelector (from)
3199
3232
3200
- def importSelectors (idOK : Boolean ): List [ ImportSelector ] =
3233
+ def importSelector (idOK : Boolean )() : ImportSelector =
3201
3234
val isWildcard = in.token == USCORE || in.token == GIVEN || isIdent(nme.raw.STAR )
3202
- val selector = atSpan(in.offset) {
3235
+ atSpan(in.offset) {
3203
3236
in.token match
3204
3237
case USCORE => wildcardSelector()
3205
3238
case GIVEN => givenSelector()
@@ -3209,13 +3242,6 @@ object Parsers {
3209
3242
if ! idOK then syntaxError(i " named imports cannot follow wildcard imports " )
3210
3243
namedSelector(termIdent())
3211
3244
}
3212
- val rest =
3213
- if in.token == COMMA then
3214
- in.nextToken()
3215
- importSelectors(idOK = idOK && ! isWildcard)
3216
- else
3217
- Nil
3218
- selector :: rest
3219
3245
3220
3246
def importSelection (qual : Tree ): Tree =
3221
3247
if in.isIdent(nme.as) && qual.isInstanceOf [RefTree ] then
@@ -3233,7 +3259,7 @@ object Parsers {
3233
3259
case GIVEN =>
3234
3260
mkTree(qual, givenSelector() :: Nil )
3235
3261
case LBRACE =>
3236
- mkTree(qual, inBraces(importSelectors( idOK = true )))
3262
+ mkTree(qual, inBraces(commaSeparated(importSelector( idOK = true ) )))
3237
3263
case _ =>
3238
3264
if isIdent(nme.raw.STAR ) then
3239
3265
mkTree(qual, wildcardSelector() :: Nil )
@@ -3290,7 +3316,7 @@ object Parsers {
3290
3316
var lhs = first match {
3291
3317
case id : Ident if in.token == COMMA =>
3292
3318
in.nextToken()
3293
- id :: commaSeparated(() => termIdent())
3319
+ id :: commaSeparated(() => termIdent(), delimited = false )
3294
3320
case _ =>
3295
3321
first :: Nil
3296
3322
}
@@ -3561,7 +3587,7 @@ object Parsers {
3561
3587
val id = termIdent()
3562
3588
if (in.token == COMMA ) {
3563
3589
in.nextToken()
3564
- val ids = commaSeparated(() => termIdent())
3590
+ val ids = commaSeparated(() => termIdent(), delimited = false )
3565
3591
PatDef (mods1, id :: ids, TypeTree (), EmptyTree )
3566
3592
}
3567
3593
else {
@@ -3765,7 +3791,7 @@ object Parsers {
3765
3791
val derived =
3766
3792
if (isIdent(nme.derives )) {
3767
3793
in.nextToken()
3768
- tokenSeparated( COMMA , () => convertToTypeId(qualId()))
3794
+ commaSeparated( () => convertToTypeId(qualId()), delimited = false )
3769
3795
}
3770
3796
else Nil
3771
3797
possibleTemplateStart()
0 commit comments