Skip to content

Commit e188590

Browse files
committed
Move trailing comma handling to Parser
1 parent f76e5ed commit e188590

File tree

8 files changed

+209
-53
lines changed

8 files changed

+209
-53
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,9 +567,15 @@ object Parsers {
567567
in.currentRegion.withCommasExpected {
568568
val ts = new ListBuffer[T]
569569
if (readFirst) ts += part()
570-
while in.token == COMMA do
570+
var done = false
571+
while in.token == COMMA && !done do
572+
val start = in.offset
571573
in.nextToken()
572-
ts += part()
574+
if in.isAfterLineEnd && (in.token == RPAREN || in.token == RBRACKET || in.token == RBRACE || in.token == OUTDENT) then
575+
// skip the trailing comma
576+
done = true
577+
else
578+
ts += part()
573579
ts.toList
574580
}
575581

@@ -3271,7 +3277,7 @@ object Parsers {
32713277
*/
32723278
def patDefOrDcl(start: Offset, mods: Modifiers): Tree = atSpan(start, nameStart) {
32733279
val first = pattern2()
3274-
var lhs = first match {
3280+
val lhs = first match {
32753281
case id: Ident if in.token == COMMA =>
32763282
in.nextToken()
32773283
id :: commaSeparated(() => termIdent())

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -698,13 +698,6 @@ object Scanners {
698698
case r: Indented if isEnclosedInParens(r.outer) =>
699699
insert(OUTDENT, offset)
700700
case _ =>
701-
lookAhead()
702-
if isAfterLineEnd
703-
&& (token == RPAREN || token == RBRACKET || token == RBRACE || token == OUTDENT)
704-
then
705-
() /* skip the trailing comma */
706-
else
707-
reset()
708701
case END =>
709702
if !isEndMarker then token = IDENTIFIER
710703
case COLON =>

docs/_docs/internals/syntax.md

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ comment ::= ‘/*’ “any sequence of characters; nested comments ar
8585
8686
nl ::= “new line character”
8787
semi ::= ‘;’ | nl {nl}
88+
89+
// trailing comma support
90+
<(> ::= ‘(’
91+
<)> ::= [ ‘,’ nl ] ‘)’
92+
<[> ::= ‘[’
93+
<]> ::= [ ‘,’ nl ] ‘]’
94+
<{> ::= ‘{’
95+
<}> ::= [ ‘,’ nl ] ‘}’
96+
8897
```
8998

9099

@@ -166,9 +175,9 @@ Type ::= FunType
166175
FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type Function(ts, t)
167176
| HKTypeParamClause '=>' Type PolyFunction(ps, t)
168177
FunTypeArgs ::= InfixType
169-
| ‘(’ [ FunArgTypes ] ‘)’
178+
| <(> [ FunArgTypes ] <)>
170179
| FunParamClause
171-
FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
180+
FunParamClause ::= <(> TypedFunParam {‘,’ TypedFunParam } <)>
172181
TypedFunParam ::= id ‘:’ Type
173182
MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
174183
InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2)
@@ -181,7 +190,7 @@ SimpleType ::= SimpleLiteral
181190
SimpleType1 ::= id Ident(name)
182191
| Singleton ‘.’ id Select(t, name)
183192
| Singleton ‘.’ ‘type’ SingletonTypeTree(p)
184-
| ‘(’ Types ‘)’ Tuple(ts)
193+
| <(> Types <)> Tuple(ts)
185194
| Refinement RefinedTypeTree(EmptyTree, refinement)
186195
| ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern
187196
| ‘$’ ‘{’ Pattern ‘}’ -- only inside quoted pattern
@@ -196,7 +205,7 @@ FunArgType ::= Type
196205
FunArgTypes ::= FunArgType { ‘,’ FunArgType }
197206
ParamType ::= [‘=>’] ParamValueType
198207
ParamValueType ::= Type [‘*’] PostfixOp(t, "*")
199-
TypeArgs ::= ‘[’ Types ‘]’ ts
208+
TypeArgs ::= <[> Types <)> ts
200209
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds
201210
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
202211
TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)
@@ -249,7 +258,7 @@ SimpleExpr ::= SimpleRef
249258
| quoteId -- only inside splices
250259
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody] New(constr | templ)
251260
| ‘new’ TemplateBody
252-
| ‘(’ ExprsInParens ‘)’ Parens(exprs)
261+
| <(> ExprsInParens <)> Parens(exprs)
253262
| SimpleExpr ‘.’ id Select(expr, id)
254263
| SimpleExpr ‘.’ MatchClause
255264
| SimpleExpr TypeArgs TypeApply(expr, args)
@@ -264,8 +273,8 @@ Quoted ::= ‘'’ ‘{’ Block ‘}’
264273
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}
265274
ExprInParens ::= PostfixExpr ‘:’ Type -- normal Expr allows only RefinedType here
266275
| Expr
267-
ParArgumentExprs ::= ‘(’ [‘using’] ExprsInParens ‘)’ exprs
268-
| ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘*’ ‘)’ exprs :+ Typed(expr, Ident(wildcardStar))
276+
ParArgumentExprs ::= <(> [‘using’] ExprsInParens <)> exprs
277+
| <(> [ExprsInParens ‘,’] PostfixExpr ‘*’ <)> exprs :+ Typed(expr, Ident(wildcardStar))
269278
ArgumentExprs ::= ParArgumentExprs
270279
| BlockExpr
271280
BlockExpr ::= <<< CaseClauses | Block >>>
@@ -299,7 +308,7 @@ Pattern2 ::= [id ‘@’] InfixPattern
299308
InfixPattern ::= SimplePattern { id [nl] SimplePattern } InfixOp(pat, op, pat)
300309
SimplePattern ::= PatVar Ident(wildcard)
301310
| Literal Bind(name, Ident(wildcard))
302-
| ‘(’ [Patterns] ‘)’ Parens(pats) Tuple(pats)
311+
| <(> [Patterns] <)> Parens(pats) Tuple(pats)
303312
| Quoted
304313
| XmlPattern (to be dropped)
305314
| SimplePattern1 [TypeArgs] [ArgumentPatterns]
@@ -309,44 +318,44 @@ SimplePattern1 ::= SimpleRef
309318
PatVar ::= varid
310319
| ‘_’
311320
Patterns ::= Pattern {‘,’ Pattern}
312-
ArgumentPatterns ::= ‘(’ [Patterns] ‘)’ Apply(fn, pats)
313-
| ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
321+
ArgumentPatterns ::= <(> [Patterns] <)> Apply(fn, pats)
322+
| <(> [Patterns ‘,’] PatVar ‘*’ <)>
314323
```
315324

316325
### Type and Value Parameters
317326
```ebnf
318-
ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
327+
ClsTypeParamClause::= <[> ClsTypeParam {‘,’ ClsTypeParam} <]>
319328
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] TypeDef(Modifiers, name, tparams, bounds)
320329
id [HkTypeParamClause] TypeParamBounds Bound(below, above, context)
321330
322-
DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
331+
DefTypeParamClause::= <[> DefTypeParam {‘,’ DefTypeParam} <]>
323332
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
324333
325-
TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
334+
TypTypeParamClause::= <[> TypTypeParam {‘,’ TypTypeParam} <]>
326335
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds
327336
328-
HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
337+
HkTypeParamClause ::= <[> HkTypeParam {‘,’ HkTypeParam} <]>
329338
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypeParamClause] | ‘_’)
330339
TypeBounds
331340
332-
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
333-
ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
334-
| [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’
341+
ClsParamClauses ::= {ClsParamClause} [[nl] <(> [‘implicit’] ClsParams <)>]
342+
ClsParamClause ::= [nl] <(> ClsParams <)>
343+
| [nl] <(> ‘using’ (ClsParams | FunArgTypes) <)>
335344
ClsParams ::= ClsParam {‘,’ ClsParam}
336345
ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var
337346
[{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
338347
Param ::= id ‘:’ ParamType [‘=’ Expr]
339348
340-
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
341-
DefParamClause ::= [nl] ‘(’ DefParams ‘)’ | UsingParamClause
342-
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefParams | FunArgTypes) ‘)’
349+
DefParamClauses ::= {DefParamClause} [[nl] <(> [‘implicit’] DefParams <)>]
350+
DefParamClause ::= [nl] <(> DefParams <)> | UsingParamClause
351+
UsingParamClause ::= [nl] <(> ‘using’ (DefParams | FunArgTypes) <)>
343352
DefParams ::= DefParam {‘,’ DefParam}
344353
DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
345354
```
346355

347356
### Bindings and Imports
348357
```ebnf
349-
Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’
358+
Bindings ::= <(> [Binding {‘,’ Binding} <)>
350359
Binding ::= (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)
351360
352361
Modifier ::= LocalModifier
@@ -371,7 +380,7 @@ ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
371380
| SimpleRef ‘as’ id Import(EmptyTree, ImportSelector(ref, id))
372381
ImportSpec ::= NamedSelector
373382
| WildcardSelector
374-
| ‘{’ ImportSelectors) ‘}’
383+
| <{> ImportSelectors <}>
375384
NamedSelector ::= id [‘as’ (id | ‘_’)]
376385
WildCardSelector ::= ‘*' | ‘given’ [InfixType]
377386
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]

docs/_docs/reference/syntax.md

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ comment ::= ‘/*’ “any sequence of characters; nested comments ar
8686
8787
nl ::= “new line character”
8888
semi ::= ‘;’ | nl {nl}
89+
90+
// trailing comma support
91+
<(> ::= ‘(’
92+
<)> ::= [ ‘,’ nl ] ‘)’
93+
<[> ::= ‘[’
94+
<]> ::= [ ‘,’ nl ] ‘]’
95+
<{> ::= ‘{’
96+
<}> ::= [ ‘,’ nl ] ‘}’
8997
```
9098

9199
## Optional Braces
@@ -166,9 +174,9 @@ Type ::= FunType
166174
FunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
167175
| HKTypeParamClause '=>' Type
168176
FunTypeArgs ::= InfixType
169-
| ‘(’ [ FunArgTypes ] ‘)’
177+
| <(> [ FunArgTypes ] <)>
170178
| FunParamClause
171-
FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
179+
FunParamClause ::= <(> TypedFunParam {‘,’ TypedFunParam } <)>
172180
TypedFunParam ::= id ‘:’ Type
173181
MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
174182
InfixType ::= RefinedType {id [nl] RefinedType}
@@ -180,7 +188,7 @@ SimpleType ::= SimpleLiteral
180188
| id
181189
| Singleton ‘.’ id
182190
| Singleton ‘.’ ‘type’
183-
| ‘(’ Types ‘)’
191+
| <(> Types <)>
184192
| Refinement
185193
| ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern
186194
| ‘$’ ‘{’ Pattern ‘}’ -- only inside quoted pattern
@@ -195,7 +203,7 @@ FunArgType ::= Type
195203
FunArgTypes ::= FunArgType { ‘,’ FunArgType }
196204
ParamType ::= [‘=>’] ParamValueType
197205
ParamValueType ::= Type [‘*’]
198-
TypeArgs ::= ‘[’ Types ‘]’
206+
TypeArgs ::= <[> Types <]>
199207
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’
200208
TypeBounds ::= [‘>:’ Type] [‘<:’ Type]
201209
TypeParamBounds ::= TypeBounds {‘:’ Type}
@@ -247,7 +255,7 @@ SimpleExpr ::= SimpleRef
247255
| quoteId -- only inside splices
248256
| ‘new’ ConstrApp {‘with’ ConstrApp} [TemplateBody]
249257
| ‘new’ TemplateBody
250-
| ‘(’ ExprsInParens ‘)’
258+
| <(> ExprsInParens <)>
251259
| SimpleExpr ‘.’ id
252260
| SimpleExpr ‘.’ MatchClause
253261
| SimpleExpr TypeArgs
@@ -257,8 +265,8 @@ Quoted ::= ‘'’ ‘{’ Block ‘}’
257265
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}
258266
ExprInParens ::= PostfixExpr ‘:’ Type
259267
| Expr
260-
ParArgumentExprs ::= ‘(’ [‘using’] ExprsInParens ‘)’
261-
| ‘(’ [ExprsInParens ‘,’] PostfixExpr ‘*’ ‘)’
268+
ParArgumentExprs ::= <(> [‘using’] ExprsInParens <)>
269+
| <(> [ExprsInParens ‘,’] PostfixExpr ‘*’ <)>
262270
ArgumentExprs ::= ParArgumentExprs
263271
| BlockExpr
264272
BlockExpr ::= <<< (CaseClauses | Block) >>>
@@ -301,41 +309,41 @@ SimplePattern1 ::= SimpleRef
301309
PatVar ::= varid
302310
| ‘_’
303311
Patterns ::= Pattern {‘,’ Pattern}
304-
ArgumentPatterns ::= ‘(’ [Patterns] ‘)’
305-
| ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
312+
ArgumentPatterns ::= <(> [Patterns] <)>
313+
| <(> [Patterns ‘,’] PatVar ‘*’ <)>
306314
```
307315

308316
### Type and Value Parameters
309317
```
310-
ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
318+
ClsTypeParamClause::= <[> ClsTypeParam {‘,’ ClsTypeParam} <]>
311319
ClsTypeParam ::= {Annotation} [‘+’ | ‘-’] id [HkTypeParamClause] TypeParamBounds
312320
313-
DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
321+
DefTypeParamClause::= <[> DefTypeParam {‘,’ DefTypeParam} <]>
314322
DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
315323
316-
TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
324+
TypTypeParamClause::= <[> TypTypeParam {‘,’ TypTypeParam} <]>
317325
TypTypeParam ::= {Annotation} id [HkTypeParamClause] TypeBounds
318326
319-
HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
327+
HkTypeParamClause ::= <[> HkTypeParam {‘,’ HkTypeParam} <]>
320328
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypeParamClause] | ‘_’) TypeBounds
321329
322-
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
323-
ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
324-
| [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’
330+
ClsParamClauses ::= {ClsParamClause} [[nl] <(> [‘implicit’] ClsParams <)>]
331+
ClsParamClause ::= [nl] <(> ClsParams <)>
332+
| [nl] <(> ‘using’ (ClsParams | FunArgTypes) <)>
325333
ClsParams ::= ClsParam {‘,’ ClsParam}
326334
ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
327335
Param ::= id ‘:’ ParamType [‘=’ Expr]
328336
329-
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
330-
DefParamClause ::= [nl] ‘(’ DefParams ‘)’ | UsingParamClause
331-
UsingParamClause ::= [nl] ‘(’ ‘using’ (DefParams | FunArgTypes) ‘)’
337+
DefParamClauses ::= {DefParamClause} [[nl] <(> [‘implicit’] DefParams <)>]
338+
DefParamClause ::= [nl] <(> DefParams <)> | UsingParamClause
339+
UsingParamClause ::= [nl] <(> ‘using’ (DefParams | FunArgTypes) <)>
332340
DefParams ::= DefParam {‘,’ DefParam}
333341
DefParam ::= {Annotation} [‘inline’] Param
334342
```
335343

336344
### Bindings and Imports
337345
```
338-
Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’
346+
Bindings ::= <(> [Binding {‘,’ Binding}] <)>
339347
Binding ::= (id | ‘_’) [‘:’ Type]
340348
341349
Modifier ::= LocalModifier
@@ -360,7 +368,7 @@ ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
360368
| SimpleRef ‘as’ id
361369
ImportSpec ::= NamedSelector
362370
| WildcardSelector
363-
| ‘{’ ImportSelectors) ‘}’
371+
| <{> ImportSelectors <}>
364372
NamedSelector ::= id [‘as’ (id | ‘_’)]
365373
WildCardSelector ::= ‘*' | ‘given’ [InfixType]
366374
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]

tests/neg/t11900.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-- Error: tests/neg/t11900.scala:44:16 ---------------------------------------------------------------------------------
2+
44 | a => a + 1, // error: weird comma
3+
| ^
4+
| end of statement expected but ',' found
5+
-- Error: tests/neg/t11900.scala:48:16 ---------------------------------------------------------------------------------
6+
48 | println("a"), // error: weird comma
7+
| ^
8+
| end of statement expected but ',' found
9+
-- Error: tests/neg/t11900.scala:52:16 ---------------------------------------------------------------------------------
10+
52 | println("b"), // error: weird comma
11+
| ^
12+
| end of statement expected but ',' found
13+
-- [E032] Syntax Error: tests/neg/t11900.scala:64:8 --------------------------------------------------------------------
14+
64 | _*, // error
15+
| ^
16+
| pattern expected
17+
|
18+
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)