Skip to content

Commit aa24efe

Browse files
committed
Change parser to new enum syntax
1 parent 6a36ccc commit aa24efe

File tree

5 files changed

+64
-76
lines changed

5 files changed

+64
-76
lines changed

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

Lines changed: 53 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -308,14 +308,21 @@ object Parsers {
308308
* class constructor
309309
*/
310310
private[this] var inClassConstrAnnots = false
311-
312311
private def fromWithinClassConstr[T](body: => T): T = {
313312
val saved = inClassConstrAnnots
314313
inClassConstrAnnots = true
315314
try body
316315
finally inClassConstrAnnots = saved
317316
}
318317

318+
private[this] var inEnum = false
319+
private def withinEnum[T](isEnum: Boolean)(body: => T): T = {
320+
val saved = inEnum
321+
inEnum = isEnum
322+
try body
323+
finally inEnum = saved
324+
}
325+
319326
def migrationWarningOrError(msg: String, offset: Int = in.offset) =
320327
if (in.isScala2Mode)
321328
ctx.migrationWarning(msg, source atPos Position(offset))
@@ -1975,7 +1982,7 @@ object Parsers {
19751982
* | var ValDcl
19761983
* | def DefDcl
19771984
* | type {nl} TypeDcl
1978-
* EnumCase ::= `case' (EnumClassDef | ObjectDef)
1985+
* EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
19791986
*/
19801987
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
19811988
case VAL =>
@@ -1990,7 +1997,7 @@ object Parsers {
19901997
defDefOrDcl(start, posMods(start, mods))
19911998
case TYPE =>
19921999
typeDefOrDcl(start, posMods(start, mods))
1993-
case CASE =>
2000+
case CASE if inEnum =>
19942001
enumCase(start, mods)
19952002
case _ =>
19962003
tmplDef(start, mods)
@@ -2135,7 +2142,7 @@ object Parsers {
21352142
}
21362143
}
21372144

2138-
/** TmplDef ::= ([`case' | `enum]'] ‘class’ | trait’) ClassDef
2145+
/** TmplDef ::= ([`case'] ‘class’ | trait’) ClassDef
21392146
* | [`case'] `object' ObjectDef
21402147
* | `enum' EnumDef
21412148
*/
@@ -2152,9 +2159,7 @@ object Parsers {
21522159
case CASEOBJECT =>
21532160
objectDef(start, posMods(start, mods | Case | Module))
21542161
case ENUM =>
2155-
val enumMod = atPos(in.skipToken()) { Mod.Enum() }
2156-
if (in.token == CLASS) tmplDef(start, addMod(mods, enumMod))
2157-
else enumDef(start, mods, enumMod)
2162+
enumDef(start, mods, atPos(in.skipToken()) { Mod.Enum() })
21582163
case _ =>
21592164
syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition())
21602165
EmptyTree
@@ -2198,55 +2203,18 @@ object Parsers {
21982203
ModuleDef(name, template).withMods(mods).setComment(in.getDocComment(start))
21992204
}
22002205

2201-
/** id ClassConstr [`extends' [ConstrApps]]
2202-
* [nl] ‘{’ EnumCaseStats ‘}’
2206+
/** EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumBody
22032207
*/
2204-
def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): Thicket = {
2205-
val point = nameStart
2208+
def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): TypeDef = atPos(start, nameStart) {
22062209
val modName = ident()
22072210
val clsName = modName.toTypeName
22082211
val constr = classConstr(clsName)
2209-
val parents =
2210-
if (in.token == EXTENDS) {
2211-
in.nextToken();
2212-
newLineOptWhenFollowedBy(LBRACE)
2213-
if (in.token == LBRACE) Nil else tokenSeparated(WITH, constrApp)
2214-
}
2215-
else Nil
2216-
val clsDef = atPos(start, point) {
2217-
TypeDef(clsName, Template(constr, parents, EmptyValDef, Nil))
2218-
.withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start))
2219-
}
2220-
newLineOptWhenFollowedBy(LBRACE)
2221-
val modDef = atPos(in.offset) {
2222-
val body = inBraces(enumCaseStats())
2223-
ModuleDef(modName, Template(emptyConstructor, Nil, EmptyValDef, body))
2224-
.withMods(mods)
2225-
}
2226-
Thicket(clsDef :: modDef :: Nil)
2227-
}
2228-
2229-
/** EnumCaseStats = EnumCaseStat {semi EnumCaseStat} */
2230-
def enumCaseStats(): List[DefTree] = {
2231-
val cases = new ListBuffer[DefTree] += enumCaseStat()
2232-
var exitOnError = false
2233-
while (!isStatSeqEnd && !exitOnError) {
2234-
acceptStatSep()
2235-
if (isCaseIntro)
2236-
cases += enumCaseStat()
2237-
else if (!isStatSep) {
2238-
exitOnError = mustStartStat
2239-
syntaxErrorOrIncomplete("illegal start of case")
2240-
}
2241-
}
2242-
cases.toList
2212+
val impl = templateOpt(constr, isEnum = true)
2213+
TypeDef(clsName, impl).withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start))
22432214
}
22442215

2245-
/** EnumCaseStat = {Annotation [nl]} {Modifier} EnumCase */
2246-
def enumCaseStat(): DefTree =
2247-
enumCase(in.offset, defAnnotsMods(modifierTokens))
2248-
2249-
/** EnumCase = `case' (EnumClassDef | ObjectDef) */
2216+
/** EnumCase = `case' (id ClassConstr [`extends' ConstrApps] | ids)
2217+
*/
22502218
def enumCase(start: Offset, mods: Modifiers): DefTree = {
22512219
val mods1 = mods.withAddedMod(atPos(in.offset)(Mod.EnumCase())) | Case
22522220
accept(CASE)
@@ -2257,18 +2225,36 @@ object Parsers {
22572225

22582226
atPos(start, nameStart) {
22592227
val id = termIdent()
2260-
if (in.token == LBRACKET || in.token == LPAREN)
2261-
classDefRest(start, mods1, id.name.toTypeName)
2262-
else if (in.token == COMMA) {
2228+
if (in.token == COMMA) {
22632229
in.nextToken()
22642230
val ids = commaSeparated(() => termIdent())
22652231
PatDef(mods1, id :: ids, TypeTree(), EmptyTree)
22662232
}
2267-
else
2268-
objectDefRest(start, mods1, id.name.asTermName)
2233+
else {
2234+
val caseDef =
2235+
if (in.token == LBRACKET || in.token == LPAREN || in.token == AT || isModifier) {
2236+
val clsName = id.name.toTypeName
2237+
val constr = classConstr(clsName, isCaseClass = true)
2238+
TypeDef(clsName, caseTemplate(constr))
2239+
}
2240+
else
2241+
ModuleDef(id.name.toTermName, caseTemplate(emptyConstructor))
2242+
caseDef.withMods(mods).setComment(in.getDocComment(start))
2243+
}
22692244
}
22702245
}
22712246

2247+
/** [`extends' ConstrApps] */
2248+
def caseTemplate(constr: DefDef): Template = {
2249+
val parents =
2250+
if (in.token == EXTENDS) {
2251+
in.nextToken()
2252+
tokenSeparated(WITH, constrApp)
2253+
}
2254+
else Nil
2255+
Template(constr, parents, EmptyValDef, Nil)
2256+
}
2257+
22722258
/* -------- TEMPLATES ------------------------------------------- */
22732259

22742260
/** ConstrApp ::= SimpleType {ParArgumentExprs}
@@ -2285,32 +2271,34 @@ object Parsers {
22852271
* @return a pair consisting of the template, and a boolean which indicates
22862272
* whether the template misses a body (i.e. no {...} part).
22872273
*/
2288-
def template(constr: DefDef): (Template, Boolean) = {
2274+
def template(constr: DefDef, isEnum: Boolean = false): (Template, Boolean) = {
22892275
newLineOptWhenFollowedBy(LBRACE)
2290-
if (in.token == LBRACE) (templateBodyOpt(constr, Nil), false)
2276+
if (in.token == LBRACE) (templateBodyOpt(constr, Nil, isEnum), false)
22912277
else {
22922278
val parents = tokenSeparated(WITH, constrApp)
22932279
newLineOptWhenFollowedBy(LBRACE)
2280+
if (isEnum && in.token != LBRACE)
2281+
syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token))
22942282
val missingBody = in.token != LBRACE
2295-
(templateBodyOpt(constr, parents), missingBody)
2283+
(templateBodyOpt(constr, parents, isEnum), missingBody)
22962284
}
22972285
}
22982286

22992287
/** TemplateOpt = [`extends' Template | TemplateBody]
23002288
*/
2301-
def templateOpt(constr: DefDef): Template =
2302-
if (in.token == EXTENDS) { in.nextToken(); template(constr)._1 }
2289+
def templateOpt(constr: DefDef, isEnum: Boolean = false): Template =
2290+
if (in.token == EXTENDS) { in.nextToken(); template(constr, isEnum)._1 }
23032291
else {
23042292
newLineOptWhenFollowedBy(LBRACE)
2305-
if (in.token == LBRACE) template(constr)._1
2293+
if (in.token == LBRACE) template(constr, isEnum)._1
23062294
else Template(constr, Nil, EmptyValDef, Nil)
23072295
}
23082296

23092297
/** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
23102298
*/
2311-
def templateBodyOpt(constr: DefDef, parents: List[Tree]) = {
2299+
def templateBodyOpt(constr: DefDef, parents: List[Tree], isEnum: Boolean) = {
23122300
val (self, stats) =
2313-
if (in.token == LBRACE) templateBody() else (EmptyValDef, Nil)
2301+
if (in.token == LBRACE) withinEnum(isEnum)(templateBody()) else (EmptyValDef, Nil)
23142302
Template(constr, parents, self, stats)
23152303
}
23162304

@@ -2378,9 +2366,10 @@ object Parsers {
23782366
* TemplateStat ::= Import
23792367
* | Annotations Modifiers Def
23802368
* | Annotations Modifiers Dcl
2381-
* | EnumCaseStat
23822369
* | Expr1
23832370
* |
2371+
* EnumStat ::= TemplateStat
2372+
* | Annotations Modifiers EnumCase
23842373
*/
23852374
def templateStatSeq(): (ValDef, List[Tree]) = checkNoEscapingPlaceholders {
23862375
var self: ValDef = EmptyValDef

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ SelfType ::= id [‘:’ InfixType] ‘=>’
354354
EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
355355
EnumStat ::= TemplateStat
356356
| {Annotation [nl]} {Modifier} EnumCase
357-
EnumCase ::= `case' (id [ClsTpeParamClause] {ClsParamClause} | ids)
357+
EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
358358
359359
TopStatSeq ::= TopStat {semi TopStat}
360360
TopStat ::= {Annotation [nl]} {Modifier} TmplDef

docs/docs/reference/enums/adts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ The changes are specified below as deltas with respect to the Scala syntax given
109109

110110
2. Cases of enums are defined as follows:
111111

112-
EnumCase ::= `case' (id [ClsTpeParamClause] {ClsParamClause} | ids)
112+
EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
113113

114114
### Reference
115115

tests/patmat/enum-Tree.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ enum Tree[T] {
55
case Succ(n: Tree[Int]) extends Tree[Int]
66
case Pred(n: Tree[Int]) extends Tree[Int]
77
case IsZero(n: Tree[Int]) extends Tree[Boolean]
8-
case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T])
8+
case If(cond: Tree[Boolean], thenp: Tree[T], elsep: Tree[T]) extends Tree[T]
99
}
1010

1111
object Test {

tests/run/enum-Option.scala

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
enum class Option[+T >: Null] extends Serializable {
2-
def isDefined: Boolean
1+
enum Option[+T >: Null] extends Serializable {
2+
case Some(x: T)
3+
case None
4+
5+
def isDefined: Boolean = this match {
6+
case None => false
7+
case some => true
8+
}
39
}
410
object Option {
511
def apply[T >: Null](x: T): Option[T] = if (x == null) None else Some(x)
6-
7-
case Some[+T >: Null](x: T) {
8-
def isDefined = true
9-
}
10-
case None {
11-
def isDefined = false
12-
}
1312
}
1413

1514
object Test {

0 commit comments

Comments
 (0)