Skip to content

Commit 28b33fd

Browse files
committed
Syntax change for single cases
Allow a single case clause after a match or catch without requiring braces or indent tokens around it. E.g. try ... catch case ex: Ex => ... s match case p => ... Ratiionale: With indentation syntax, it feels natural to shorten try ... catch case ex: Ex => ... to try ... catch case ex: Ex => ...
1 parent 22e64e2 commit 28b33fd

File tree

3 files changed

+35
-18
lines changed

3 files changed

+35
-18
lines changed

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

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,9 @@ object Parsers {
12481248
// note: next is defined here because current == NEWLINE
12491249
if (in.token == NEWLINE && in.next.token == token) in.nextToken()
12501250

1251+
def newLinesOptWhenFollowedBy(token: Int): Unit =
1252+
if in.isNewLine && in.next.token == token then in.nextToken()
1253+
12511254
def newLinesOptWhenFollowedBy(name: Name): Unit =
12521255
if in.isNewLine && in.next.token == IDENTIFIER && in.next.name == name then
12531256
in.nextToken()
@@ -1742,8 +1745,7 @@ object Parsers {
17421745
* | [SimpleExpr `.'] id `=' Expr
17431746
* | SimpleExpr1 ArgumentExprs `=' Expr
17441747
* | Expr2
1745-
* | [‘inline’] Expr2 `match' `{' CaseClauses `}'
1746-
* | `given' `match' `{' ImplicitCaseClauses `}'
1748+
* | [‘inline’] Expr2 `match' (`{' CaseClauses `}' | CaseClause)
17471749
* Bindings ::= `(' [Binding {`,' Binding}] `)'
17481750
* Binding ::= (id | `_') [`:' Type]
17491751
* Expr2 ::= PostfixExpr [Ascription]
@@ -1829,11 +1831,12 @@ object Parsers {
18291831
atSpan(in.skipToken()) {
18301832
val body = expr()
18311833
val (handler, handlerStart) =
1832-
if (in.token == CATCH) {
1834+
if in.token == CATCH then
18331835
val span = in.offset
18341836
in.nextToken()
1835-
(subExpr(), span)
1836-
}
1837+
(if in.token == CASE then Match(EmptyTree, caseClause() :: Nil)
1838+
else subExpr(),
1839+
span)
18371840
else (EmptyTree, -1)
18381841

18391842
handler match {
@@ -1955,20 +1958,20 @@ object Parsers {
19551958
mkIf(cond, thenp, elsep)
19561959
}
19571960

1958-
/** `match' { CaseClauses }
1961+
/** `match' (`{' CaseClauses `}' | CaseClause)
19591962
*/
19601963
def matchExpr(t: Tree, start: Offset, mkMatch: (Tree, List[CaseDef]) => Match) =
19611964
indentRegion(MATCH) {
19621965
atSpan(start, in.skipToken()) {
1963-
mkMatch(t, inBracesOrIndented(caseClauses(caseClause)))
1966+
mkMatch(t, casesExpr(caseClause))
19641967
}
19651968
}
19661969

1967-
/** `match' { TypeCaseClauses }
1970+
/** `match' (`{' TypeCaseClauses `}' | TypeCaseClause)
19681971
*/
19691972
def matchType(t: Tree): MatchTypeTree =
19701973
atSpan(t.span.start, accept(MATCH)) {
1971-
inBracesOrIndented(MatchTypeTree(EmptyTree, t, caseClauses(typeCaseClause)))
1974+
MatchTypeTree(EmptyTree, t, casesExpr(typeCaseClause))
19721975
}
19731976

19741977
/** FunParams ::= Bindings
@@ -2399,8 +2402,11 @@ object Parsers {
23992402
}
24002403
}
24012404

2405+
def casesExpr(clause: () => CaseDef): List[CaseDef] =
2406+
if in.token == CASE then clause() :: Nil
2407+
else inBracesOrIndented(caseClauses(clause))
2408+
24022409
/** CaseClauses ::= CaseClause {CaseClause}
2403-
* ImplicitCaseClauses ::= ImplicitCaseClause {ImplicitCaseClause}
24042410
* TypeCaseClauses ::= TypeCaseClause {TypeCaseClause}
24052411
*/
24062412
def caseClauses(clause: () => CaseDef): List[CaseDef] = {
@@ -2410,9 +2416,8 @@ object Parsers {
24102416
buf.toList
24112417
}
24122418

2413-
/** CaseClause ::= ‘case’ Pattern [Guard] `=>' Block
2414-
* ImplicitCaseClause ::= ‘case’ PatVar [Ascription] [Guard] `=>' Block
2415-
*/
2419+
/** CaseClause ::= ‘case’ Pattern [Guard] `=>' Block
2420+
*/
24162421
val caseClause: () => CaseDef = () => atSpan(in.offset) {
24172422
val (pat, grd) = inSepRegion(LPAREN, RPAREN) {
24182423
accept(CASE)
@@ -2430,7 +2435,7 @@ object Parsers {
24302435
}
24312436
CaseDef(pat, EmptyTree, atSpan(accept(ARROW)) {
24322437
val t = typ()
2433-
if (isStatSep) in.nextToken()
2438+
newLinesOptWhenFollowedBy(CASE)
24342439
t
24352440
})
24362441
}

docs/docs/internals/syntax.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ FunArgTypes ::= InfixType
147147
| ‘(’ [ ‘[given]’ FunArgType {‘,’ FunArgType } ] ‘)’
148148
| ‘(’ ‘[given]’ TypedFunParam {‘,’ TypedFunParam } ‘)’
149149
TypedFunParam ::= id ‘:’ Type
150-
MatchType ::= InfixType `match` TypeCaseClauses
150+
MatchType ::= InfixType `match`
151+
(‘{’ TypeCaseClauses ‘}’ | TypeCaseClause)
151152
InfixType ::= RefinedType {id [nl] RefinedType} InfixOp(t1, op, t2)
152153
RefinedType ::= WithType {[nl | ‘with’] Refinement} RefinedTypeTree(t, ds)
153154
WithType ::= AnnotType {‘with’ AnnotType} (deprecated)
@@ -198,12 +199,12 @@ Expr1 ::= ‘if’ ‘(’ Expr ‘)’ {nl}
198199
| [SimpleExpr ‘.’] id ‘=’ Expr Assign(expr, expr)
199200
| SimpleExpr1 ArgumentExprs ‘=’ Expr Assign(expr, expr)
200201
| Expr2
201-
| [‘inline’] Expr2 ‘match’ ‘{’ CaseClauses ‘}’ Match(expr, cases) -- point on match
202-
| ‘given’ ‘match’ ‘{’ ImplicitCaseClauses ‘}’
202+
| [‘inline’] Expr2 ‘match’
203+
(‘{’ CaseClauses ‘}’ | CaseClause) Match(expr, cases) -- point on match
203204
Expr2 ::= PostfixExpr [Ascription]
204205
Ascription ::= ‘:’ InfixType Typed(expr, tp)
205206
| ‘:’ Annotation {Annotation} Typed(expr, Annotated(EmptyTree, annot)*)
206-
Catches ::= ‘catch’ Expr
207+
Catches ::= ‘catch’ (Expr | CaseClause)
207208
PostfixExpr ::= InfixExpr [id] PostfixOp(expr, op)
208209
InfixExpr ::= PrefixExpr
209210
| InfixExpr id [nl] InfixExpr InfixOp(expr, op, expr)

tests/pos/single-case.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
object test with
2+
3+
type T[X] = X match case Int => X
4+
5+
try
6+
println("hi")
7+
catch case ex: java.io.IOException => println("ho")
8+
9+
1 match case x: Int => println(x)
10+
11+

0 commit comments

Comments
 (0)