aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-02-27 17:44:02 +0100
committerMartin Odersky <odersky@gmail.com>2017-04-04 13:29:38 +0200
commit91a26b3f42d1218015acb9b7e1bfc180e3ed779b (patch)
tree63ba813e4b2a806da9f170624f03bad72d0e08dd
parentcf10e28a54aaeab124f9a939f71da7e09d299bcb (diff)
downloaddotty-91a26b3f42d1218015acb9b7e1bfc180e3ed779b.tar.gz
dotty-91a26b3f42d1218015acb9b7e1bfc180e3ed779b.tar.bz2
dotty-91a26b3f42d1218015acb9b7e1bfc180e3ed779b.zip
Support comma-separated enum constants
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala18
-rw-r--r--compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala35
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala19
-rw-r--r--docs/docs/internals/syntax.md2
-rw-r--r--tests/run/enum-Color.scala4
5 files changed, 48 insertions, 30 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 575af97f4..04834b04b 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -576,11 +576,23 @@ object desugar {
/** val p1, ..., pN: T = E
* ==>
* makePatDef[[val p1: T1 = E]]; ...; makePatDef[[val pN: TN = E]]
+ *
+ * case e1, ..., eN
+ * ==>
+ * expandSimpleEnumCase([case e1]); ...; expandSimpleEnumCase([case eN])
*/
- def patDef(pdef: PatDef)(implicit ctx: Context): Tree = {
+ def patDef(pdef: PatDef)(implicit ctx: Context): Tree = flatTree {
val PatDef(mods, pats, tpt, rhs) = pdef
- val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
- flatTree(pats1 map (makePatDef(pdef, mods, _, rhs)))
+ if (mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(pdef))
+ pats map {
+ case id: Ident =>
+ expandSimpleEnumCase(id.name.asTermName, mods,
+ Position(pdef.pos.start, id.pos.end, id.pos.start))
+ }
+ else {
+ val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
+ pats1 map (makePatDef(pdef, mods, _, rhs))
+ }
}
/** If `pat` is a variable pattern,
diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
index 8bd3c8580..7fdff0e2d 100644
--- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
+++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
@@ -24,14 +24,15 @@ object DesugarEnums {
result
}
- def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean = {
- tree.mods.hasMod[Mod.EnumCase] &&
- ( ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass)
+ def isLegalEnumCase(tree: MemberDef)(implicit ctx: Context): Boolean =
+ tree.mods.hasMod[Mod.EnumCase] && enumCaseIsLegal(tree)
+
+ def enumCaseIsLegal(tree: Tree)(implicit ctx: Context): Boolean = (
+ ctx.owner.is(ModuleClass) && enumClass.derivesFrom(defn.EnumClass)
|| { ctx.error(em"case not allowed here, since owner ${ctx.owner} is not an `enum' object", tree.pos)
false
}
)
- }
/** Type parameters reconstituted from the constructor
* of the `enum' class corresponding to an enum case.
@@ -104,23 +105,25 @@ object DesugarEnums {
List(privateValuesDef, valueOfDef, withNameDef, valuesDef, newDef)
}
- def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = {
- def nameLit = Literal(Constant(name.toString))
- if (impl.parents.isEmpty) {
- if (reconstitutedEnumTypeParams(pos).nonEmpty)
- ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos)
- val tag = nextEnumTag
- val prefix = if (tag == 0) enumScaffolding else Nil
- val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), nameLit))
- val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos)
- flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos)
- } else {
+ def expandEnumModule(name: TermName, impl: Template, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree =
+ if (impl.parents.isEmpty)
+ expandSimpleEnumCase(name, mods, pos)
+ else {
def toStringMeth =
- DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), nameLit)
+ DefDef(nme.toString_, Nil, Nil, TypeTree(defn.StringType), Literal(Constant(name.toString)))
.withFlags(Override)
val impl1 = cpy.Template(impl)(body =
impl.body ++ List(enumTagMeth, toStringMeth))
ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final).withPos(pos)
}
+
+ def expandSimpleEnumCase(name: TermName, mods: Modifiers, pos: Position)(implicit ctx: Context): Tree = {
+ if (reconstitutedEnumTypeParams(pos).nonEmpty)
+ ctx.error(i"illegal enum value of generic $enumClass: an explicit `extends' clause is needed", pos)
+ val tag = nextEnumTag
+ val prefix = if (tag == 0) enumScaffolding else Nil
+ val creator = Apply(Ident(nme.DOLLAR_NEW), List(Literal(Constant(tag)), Literal(Constant(name.toString))))
+ val vdef = ValDef(name, enumClassRef, creator).withMods(mods | Final).withPos(pos)
+ flatTree(prefix ::: vdef :: Nil).withPos(pos.startPos)
}
}
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index ee736179a..9864281a5 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -2149,8 +2149,8 @@ object Parsers {
}
/** EnumCaseStats = EnumCaseStat {semi EnumCaseStat */
- def enumCaseStats(): List[MemberDef] = {
- val cases = new ListBuffer[MemberDef] += enumCaseStat()
+ def enumCaseStats(): List[DefTree] = {
+ val cases = new ListBuffer[DefTree] += enumCaseStat()
while (in.token != RBRACE) {
acceptStatSep()
cases += enumCaseStat()
@@ -2159,19 +2159,24 @@ object Parsers {
}
/** EnumCaseStat = {Annotation [nl]} {Modifier} EnumCase */
- def enumCaseStat(): MemberDef =
+ def enumCaseStat(): DefTree =
enumCase(in.offset, defAnnotsMods(modifierTokens))
/** EnumCase = `case' (EnumClassDef | ObjectDef) */
- def enumCase(start: Offset, mods: Modifiers): MemberDef = {
+ def enumCase(start: Offset, mods: Modifiers): DefTree = {
val mods1 = mods.withAddedMod(atPos(in.offset)(Mod.EnumCase())) | Case
accept(CASE)
atPos(start, nameStart) {
- val name = ident()
+ val id = termIdent()
if (in.token == LBRACKET || in.token == LPAREN)
- classDefRest(start, mods1, name.toTypeName)
+ classDefRest(start, mods1, id.name.toTypeName)
+ else if (in.token == COMMA) {
+ in.nextToken()
+ val ids = commaSeparated(termIdent)
+ PatDef(mods1, id :: ids, TypeTree(), EmptyTree)
+ }
else
- objectDefRest(start, mods1, name)
+ objectDefRest(start, mods1, id.name.asTermName)
}
}
diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md
index c7f282dc1..e4285e20f 100644
--- a/docs/docs/internals/syntax.md
+++ b/docs/docs/internals/syntax.md
@@ -341,7 +341,7 @@ ObjectDef ::= id TemplateOpt
EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumDef(mods, name, tparams, template)
[nl] ‘{’ EnumCaseStat {semi EnumCaseStat} ‘}’
EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase
-EnumCase ::= `case' (EnumClassDef | ObjectDef)
+EnumCase ::= `case' (EnumClassDef | ObjectDef | ids)
EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause] ClassDef(mods, name, tparams, templ)
ClsParamClauses TemplateOpt
TemplateOpt ::= [‘extends’ Template | [nl] TemplateBody]
diff --git a/tests/run/enum-Color.scala b/tests/run/enum-Color.scala
index 24916abee..1a077bf8e 100644
--- a/tests/run/enum-Color.scala
+++ b/tests/run/enum-Color.scala
@@ -1,7 +1,5 @@
enum Color {
- case Red
- case Green
- case Blue
+ case Red, Green, Blue
}
object Test {