@@ -559,19 +559,28 @@ object Parsers {
559
559
def inDefScopeBraces [T ](body : => T , rewriteWithColon : Boolean = false ): T =
560
560
inBracesOrIndented(body, rewriteWithColon)
561
561
562
- /** part { `separator` part }
563
- */
564
- def tokenSeparated [T ](separator : Int , part : () => T ): List [T ] = {
562
+ /** part { `,` part }
563
+ * @param expectedEnd If set to something other than [[EMPTY ]],
564
+ * assume this comma separated list must be followed by this token.
565
+ * If the parser consumes a `part` that is not followed by a comma or this expected
566
+ * token, issue a syntax error and try to recover at the next safe point.
567
+ */
568
+ def commaSeparated [T ](part : () => T , expectedEnd : Token = EMPTY ): List [T ] = {
565
569
val ts = new ListBuffer [T ] += part()
566
- while (in.token == separator ) {
570
+ while (in.token == COMMA ) {
567
571
in.nextToken()
568
572
ts += part()
569
573
}
574
+ if (expectedEnd != EMPTY && in.token != expectedEnd) {
575
+ // As a side effect, will skip to the nearest safe point, which might be a comma
576
+ syntaxErrorOrIncomplete(ExpectedTokenButFound (expectedEnd, in.token))
577
+ if (in.token == COMMA ) {
578
+ ts ++= commaSeparated(part, expectedEnd)
579
+ }
580
+ }
570
581
ts.toList
571
582
}
572
583
573
- def commaSeparated [T ](part : () => T ): List [T ] = tokenSeparated(COMMA , part)
574
-
575
584
def inSepRegion [T ](f : Region => Region )(op : => T ): T =
576
585
val cur = in.currentRegion
577
586
in.currentRegion = f(cur)
@@ -1515,7 +1524,7 @@ object Parsers {
1515
1524
/** FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
1516
1525
*/
1517
1526
def funParamClause (): List [ValDef ] =
1518
- inParens(commaSeparated(() => typedFunParam(in.offset, ident())))
1527
+ inParens(commaSeparated(() => typedFunParam(in.offset, ident()), RPAREN ))
1519
1528
1520
1529
def funParamClauses (): List [List [ValDef ]] =
1521
1530
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
@@ -1628,7 +1637,7 @@ object Parsers {
1628
1637
else
1629
1638
def singletonArgs (t : Tree ): Tree =
1630
1639
if in.token == LPAREN && in.featureEnabled(Feature .dependent)
1631
- then singletonArgs(AppliedTypeTree (t, inParens(commaSeparated(singleton))))
1640
+ then singletonArgs(AppliedTypeTree (t, inParens(commaSeparated(singleton, RPAREN ))))
1632
1641
else t
1633
1642
singletonArgs(simpleType1())
1634
1643
@@ -1644,7 +1653,7 @@ object Parsers {
1644
1653
def simpleType1 () = simpleTypeRest {
1645
1654
if in.token == LPAREN then
1646
1655
atSpan(in.offset) {
1647
- makeTupleOrParens(inParens(argTypes(namedOK = false , wildOK = true )))
1656
+ makeTupleOrParens(inParens(argTypes(namedOK = false , wildOK = true , RPAREN )))
1648
1657
}
1649
1658
else if in.token == LBRACE then
1650
1659
atSpan(in.offset) { RefinedTypeTree (EmptyTree , refinement(indentOK = false )) }
@@ -1728,7 +1737,7 @@ object Parsers {
1728
1737
* | NamedTypeArg {`,' NamedTypeArg}
1729
1738
* NamedTypeArg ::= id `=' Type
1730
1739
*/
1731
- def argTypes (namedOK : Boolean , wildOK : Boolean ): List [Tree ] = {
1740
+ def argTypes (namedOK : Boolean , wildOK : Boolean , expectedEnd : Token ): List [Tree ] = {
1732
1741
1733
1742
def argType () = {
1734
1743
val t = typ()
@@ -1745,7 +1754,7 @@ object Parsers {
1745
1754
val rest =
1746
1755
if (in.token == COMMA ) {
1747
1756
in.nextToken()
1748
- commaSeparated(arg)
1757
+ commaSeparated(arg, expectedEnd )
1749
1758
}
1750
1759
else Nil
1751
1760
first :: rest
@@ -1758,7 +1767,7 @@ object Parsers {
1758
1767
case firstArg =>
1759
1768
otherArgs(firstArg, () => argType())
1760
1769
}
1761
- else commaSeparated(() => argType())
1770
+ else commaSeparated(() => argType(), expectedEnd )
1762
1771
}
1763
1772
1764
1773
/** FunArgType ::= Type | `=>' Type
@@ -1787,7 +1796,7 @@ object Parsers {
1787
1796
/** TypeArgs ::= `[' Type {`,' Type} `]'
1788
1797
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
1789
1798
*/
1790
- def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] = inBrackets(argTypes(namedOK, wildOK))
1799
+ def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] = inBrackets(argTypes(namedOK, wildOK, RBRACKET ))
1791
1800
1792
1801
/** Refinement ::= `{' RefineStatSeq `}'
1793
1802
*/
@@ -2151,7 +2160,7 @@ object Parsers {
2151
2160
var mods1 = mods
2152
2161
if isErased then mods1 = addModifier(mods1)
2153
2162
try
2154
- commaSeparated(() => binding(mods1))
2163
+ commaSeparated(() => binding(mods1), RPAREN )
2155
2164
finally
2156
2165
accept(RPAREN )
2157
2166
else {
@@ -2383,7 +2392,7 @@ object Parsers {
2383
2392
/** ExprsInParens ::= ExprInParens {`,' ExprInParens}
2384
2393
*/
2385
2394
def exprsInParensOpt (): List [Tree ] =
2386
- if (in.token == RPAREN ) Nil else commaSeparated(exprInParens)
2395
+ if (in.token == RPAREN ) Nil else commaSeparated(exprInParens, RPAREN )
2387
2396
2388
2397
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
2389
2398
* | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
@@ -2393,9 +2402,9 @@ object Parsers {
2393
2402
(Nil , false )
2394
2403
else if isIdent(nme.using) then
2395
2404
in.nextToken()
2396
- (commaSeparated(argumentExpr), true )
2405
+ (commaSeparated(argumentExpr, RPAREN ), true )
2397
2406
else
2398
- (commaSeparated(argumentExpr), false )
2407
+ (commaSeparated(argumentExpr, RPAREN ), false )
2399
2408
}
2400
2409
2401
2410
/** ArgumentExprs ::= ParArgumentExprs
@@ -2539,7 +2548,7 @@ object Parsers {
2539
2548
if (leading == LBRACE || in.token == CASE )
2540
2549
enumerators()
2541
2550
else {
2542
- val pats = patternsOpt()
2551
+ val pats = patternsOpt(EMPTY )
2543
2552
val pat =
2544
2553
if (in.token == RPAREN || pats.length > 1 ) {
2545
2554
wrappedEnums = false
@@ -2731,7 +2740,7 @@ object Parsers {
2731
2740
case USCORE =>
2732
2741
wildcardIdent()
2733
2742
case LPAREN =>
2734
- atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) }
2743
+ atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt(RPAREN ))) }
2735
2744
case QUOTE =>
2736
2745
simpleExpr(Location .InPattern )
2737
2746
case XMLSTART =>
@@ -2767,17 +2776,17 @@ object Parsers {
2767
2776
2768
2777
/** Patterns ::= Pattern [`,' Pattern]
2769
2778
*/
2770
- def patterns (location : Location = Location .InPattern ): List [Tree ] =
2771
- commaSeparated(() => pattern(location))
2779
+ def patterns (expectedEnd : Token = EMPTY , location : Location = Location .InPattern ): List [Tree ] =
2780
+ commaSeparated(() => pattern(location), expectedEnd )
2772
2781
2773
- def patternsOpt (location : Location = Location .InPattern ): List [Tree ] =
2774
- if (in.token == RPAREN ) Nil else patterns(location)
2782
+ def patternsOpt (expectedEnd : Token , location : Location = Location .InPattern ): List [Tree ] =
2783
+ if (in.token == RPAREN ) Nil else patterns(expectedEnd, location)
2775
2784
2776
2785
/** ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
2777
2786
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
2778
2787
*/
2779
2788
def argumentPatterns (): List [Tree ] =
2780
- inParens(patternsOpt(Location .InPatternArgs ))
2789
+ inParens(patternsOpt(RPAREN , Location .InPatternArgs ))
2781
2790
2782
2791
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
2783
2792
@@ -2958,7 +2967,7 @@ object Parsers {
2958
2967
TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
2959
2968
}
2960
2969
}
2961
- commaSeparated(() => typeParam())
2970
+ commaSeparated(() => typeParam(), RBRACKET )
2962
2971
}
2963
2972
2964
2973
def typeParamClauseOpt (ownerKind : ParamOwner .Value ): List [TypeDef ] =
@@ -2967,7 +2976,7 @@ object Parsers {
2967
2976
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
2968
2977
*/
2969
2978
def contextTypes (ofClass : Boolean , nparams : Int , impliedMods : Modifiers ): List [ValDef ] =
2970
- val tps = commaSeparated(funArgType)
2979
+ val tps = commaSeparated(funArgType, RPAREN )
2971
2980
var counter = nparams
2972
2981
def nextIdx = { counter += 1 ; counter }
2973
2982
val paramFlags = if ofClass then Private | Local | ParamAccessor else Param
@@ -3071,7 +3080,7 @@ object Parsers {
3071
3080
! impliedMods.is(Given )
3072
3081
|| startParamTokens.contains(in.token)
3073
3082
|| isIdent && (in.name == nme.inline || in.lookahead.isColon())
3074
- if isParams then commaSeparated(() => param())
3083
+ if isParams then commaSeparated(() => param(), RPAREN )
3075
3084
else contextTypes(ofClass, nparams, impliedMods)
3076
3085
checkVarArgsRules(clause)
3077
3086
clause
@@ -3765,7 +3774,7 @@ object Parsers {
3765
3774
val derived =
3766
3775
if (isIdent(nme.derives )) {
3767
3776
in.nextToken()
3768
- tokenSeparated( COMMA , () => convertToTypeId(qualId()))
3777
+ commaSeparated( () => convertToTypeId(qualId()))
3769
3778
}
3770
3779
else Nil
3771
3780
possibleTemplateStart()
0 commit comments