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