Skip to content

Commit 01c8179

Browse files
committed
Allow case in front of generators (syntax and parsing)
1 parent e99a32c commit 01c8179

File tree

7 files changed

+52
-36
lines changed

7 files changed

+52
-36
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,25 +1356,25 @@ object desugar {
13561356
enums match {
13571357
case (gen: GenFrom) :: Nil =>
13581358
Apply(rhsSelect(gen, mapName), makeLambda(gen.pat, body))
1359-
case (gen: GenFrom) :: (rest @ (GenFrom(_, _) :: _)) =>
1359+
case (gen: GenFrom) :: (rest @ (GenFrom(_, _, _) :: _)) =>
13601360
val cont = makeFor(mapName, flatMapName, rest, body)
13611361
Apply(rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont))
1362-
case (GenFrom(pat, rhs)) :: (rest @ GenAlias(_, _) :: _) =>
1362+
case (gen @ GenFrom(pat, rhs, _)) :: (rest @ GenAlias(_, _) :: _) =>
13631363
val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
13641364
val pats = valeqs map { case GenAlias(pat, _) => pat }
13651365
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
13661366
val (defpat0, id0) = makeIdPat(pat)
13671367
val (defpats, ids) = (pats map makeIdPat).unzip
13681368
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _))
1369-
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
1369+
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs, gen.filtering) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
13701370
val allpats = pat :: pats
13711371
val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1)
13721372
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
13731373
case (gen: GenFrom) :: test :: rest =>
13741374
val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test))
13751375
val genFrom =
13761376
if (isIrrefutableGenFrom(gen)) new IrrefutableGenFrom(gen.pat, filtered)
1377-
else GenFrom(gen.pat, filtered)
1377+
else GenFrom(gen.pat, filtered, filtering = false)
13781378
makeFor(mapName, flatMapName, genFrom :: rest, body)
13791379
case _ =>
13801380
EmptyTree //may happen for erroneous input
@@ -1563,5 +1563,5 @@ object desugar {
15631563
}
15641564

15651565
private class IrrefutableGenFrom(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile)
1566-
extends GenFrom(pat, expr)
1566+
extends GenFrom(pat, expr, false)
15671567
}

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
9999
case class DoWhile(body: Tree, cond: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
100100
case class ForYield(enums: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
101101
case class ForDo(enums: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
102-
case class GenFrom(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
102+
case class GenFrom(pat: Tree, expr: Tree, filtering: Boolean)(implicit @constructorOnly src: SourceFile) extends Tree
103103
case class GenAlias(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
104104
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree
105105
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
@@ -525,9 +525,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
525525
case tree: ForDo if (enums eq tree.enums) && (body eq tree.body) => tree
526526
case _ => finalize(tree, untpd.ForDo(enums, body)(tree.source))
527527
}
528-
def GenFrom(tree: Tree)(pat: Tree, expr: Tree)(implicit ctx: Context): Tree = tree match {
529-
case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) => tree
530-
case _ => finalize(tree, untpd.GenFrom(pat, expr)(tree.source))
528+
def GenFrom(tree: Tree)(pat: Tree, expr: Tree, filtering: Boolean)(implicit ctx: Context): Tree = tree match {
529+
case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) && (filtering == tree.filtering) => tree
530+
case _ => finalize(tree, untpd.GenFrom(pat, expr, filtering)(tree.source))
531531
}
532532
def GenAlias(tree: Tree)(pat: Tree, expr: Tree)(implicit ctx: Context): Tree = tree match {
533533
case tree: GenAlias if (pat eq tree.pat) && (expr eq tree.expr) => tree
@@ -589,8 +589,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
589589
cpy.ForYield(tree)(transform(enums), transform(expr))
590590
case ForDo(enums, body) =>
591591
cpy.ForDo(tree)(transform(enums), transform(body))
592-
case GenFrom(pat, expr) =>
593-
cpy.GenFrom(tree)(transform(pat), transform(expr))
592+
case GenFrom(pat, expr, filtering) =>
593+
cpy.GenFrom(tree)(transform(pat), transform(expr), filtering)
594594
case GenAlias(pat, expr) =>
595595
cpy.GenAlias(tree)(transform(pat), transform(expr))
596596
case ContextBounds(bounds, cxBounds) =>
@@ -644,7 +644,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
644644
this(this(x, enums), expr)
645645
case ForDo(enums, body) =>
646646
this(this(x, enums), body)
647-
case GenFrom(pat, expr) =>
647+
case GenFrom(pat, expr, _) =>
648648
this(this(x, pat), expr)
649649
case GenAlias(pat, expr) =>
650650
this(this(x, pat), expr)

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

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,18 +1701,24 @@ object Parsers {
17011701
*/
17021702
def enumerator(): Tree =
17031703
if (in.token == IF) guard()
1704+
else if (in.token == CASE) generator()
17041705
else {
17051706
val pat = pattern1()
17061707
if (in.token == EQUALS) atSpan(startOffset(pat), in.skipToken()) { GenAlias(pat, expr()) }
1707-
else generatorRest(pat)
1708+
else generatorRest(pat, filtering = false)
17081709
}
17091710

1710-
/** Generator ::= Pattern `<-' Expr
1711+
/** Generator ::= [‘case’] Pattern `<-' Expr
17111712
*/
1712-
def generator(): Tree = generatorRest(pattern1())
1713+
def generator(): Tree = {
1714+
val filtering =
1715+
if (in.token == CASE) { in.skipCASE(); true }
1716+
else !ctx.settings.strict.value // don't filter under -strict
1717+
generatorRest(pattern1(), filtering)
1718+
}
17131719

1714-
def generatorRest(pat: Tree): GenFrom =
1715-
atSpan(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr()) }
1720+
def generatorRest(pat: Tree, filtering: Boolean): GenFrom =
1721+
atSpan(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr(), filtering) }
17161722

17171723
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
17181724
* {nl} [`yield'] Expr
@@ -1725,16 +1731,20 @@ object Parsers {
17251731
else if (in.token == LPAREN) {
17261732
val lparenOffset = in.skipToken()
17271733
openParens.change(LPAREN, 1)
1728-
val pats = patternsOpt()
1729-
val pat =
1730-
if (in.token == RPAREN || pats.length > 1) {
1731-
wrappedEnums = false
1732-
accept(RPAREN)
1733-
openParens.change(LPAREN, -1)
1734-
atSpan(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
1734+
val res =
1735+
if (in.token == CASE) enumerators()
1736+
else {
1737+
val pats = patternsOpt()
1738+
val pat =
1739+
if (in.token == RPAREN || pats.length > 1) {
1740+
wrappedEnums = false
1741+
accept(RPAREN)
1742+
openParens.change(LPAREN, -1)
1743+
atSpan(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
1744+
}
1745+
else pats.head
1746+
generatorRest(pat, filtering = false) :: enumeratorsRest()
17351747
}
1736-
else pats.head
1737-
val res = generatorRest(pat) :: enumeratorsRest()
17381748
if (wrappedEnums) {
17391749
accept(RPAREN)
17401750
openParens.change(LPAREN, -1)
@@ -2616,11 +2626,7 @@ object Parsers {
26162626
*/
26172627
def enumCase(start: Offset, mods: Modifiers): DefTree = {
26182628
val mods1 = addMod(mods, atSpan(in.offset)(Mod.Enum())) | Case
2619-
accept(CASE)
2620-
2621-
in.adjustSepRegions(ARROW)
2622-
// Scanner thinks it is in a pattern match after seeing the `case`.
2623-
// We need to get it out of that mode by telling it we are past the `=>`
2629+
in.skipCASE()
26242630

26252631
atSpan(start, nameStart) {
26262632
val id = termIdent()

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,16 @@ object Scanners {
306306
case _ =>
307307
}
308308

309+
/** Advance beyond a case token without marking the CASE in sepRegions.
310+
* This method should be called to skip beyond CASE tokens that are
311+
* not part of matches, i.e. no ARROW is expected after them.
312+
*/
313+
def skipCASE() = {
314+
assert(token == CASE)
315+
nextToken()
316+
sepRegions = sepRegions.tail
317+
}
318+
309319
/** Produce next token, filling TokenData fields of Scanner.
310320
*/
311321
def nextToken(): Unit = {

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
564564
forText(enums, expr, keywordStr(" yield "))
565565
case ForDo(enums, expr) =>
566566
forText(enums, expr, keywordStr(" do "))
567-
case GenFrom(pat, expr) =>
568-
toText(pat) ~ " <- " ~ toText(expr)
567+
case GenFrom(pat, expr, filtering) =>
568+
(Str("case ") provided filtering) ~ toText(pat) ~ " <- " ~ toText(expr)
569569
case GenAlias(pat, expr) =>
570570
toText(pat) ~ " = " ~ toText(expr)
571571
case ContextBounds(bounds, cxBounds) =>

compiler/test/dotty/tools/dotc/parsing/parsePackage.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ object parsePackage extends ParserTest {
4949
ForYield(enums map transform, transform(expr))
5050
case ForDo(enums, expr) =>
5151
ForDo(enums map transform, transform(expr))
52-
case GenFrom(pat, expr) =>
53-
GenFrom(transform(pat), transform(expr))
52+
case GenFrom(pat, expr, filtering) =>
53+
GenFrom(transform(pat), transform(expr), filtering)
5454
case GenAlias(pat, expr) =>
5555
GenAlias(transform(pat), transform(expr))
5656
case PatDef(mods, pats, tpt, expr) =>

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ Enumerators ::= Generator {semi Enumerator | Guard}
245245
Enumerator ::= Generator
246246
| Guard
247247
| Pattern1 ‘=’ Expr GenAlias(pat, expr)
248-
Generator ::= Pattern1 ‘<-’ Expr GenFrom(pat, expr)
248+
Generator ::= [‘case’] Pattern1 ‘<-’ Expr GenFrom(pat, expr)
249249
Guard ::= ‘if’ PostfixExpr
250250
251251
CaseClauses ::= CaseClause { CaseClause } Match(EmptyTree, cases)

0 commit comments

Comments
 (0)