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