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