Skip to content

Commit 5b91815

Browse files
committed
Add enum syntax
Modify syntax.md and Tokens/Parser/untpd to support enums.
1 parent f727bcd commit 5b91815

File tree

4 files changed

+115
-29
lines changed

4 files changed

+115
-29
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
3939
def withName(name: Name)(implicit ctx: Context) = cpy.ModuleDef(this)(name.toTermName, impl)
4040
}
4141

42+
/** mods case name impl */
43+
case class EnumDef(name: TypeName, impl: Template) extends MemberDef
44+
4245
case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree
4346

4447
case class SymbolLit(str: String) extends TermTree
@@ -132,6 +135,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
132135
case class Inline() extends Mod(Flags.Inline)
133136

134137
case class Type() extends Mod(Flags.EmptyFlags)
138+
139+
case class Enum() extends Mod(Flags.EmptyFlags)
140+
141+
case class EnumCase() extends Mod(Flags.EmptyFlags)
135142
}
136143

137144
/** Modifiers and annotations for definitions

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

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,15 +1876,16 @@ object Parsers {
18761876
mods1
18771877
}
18781878

1879-
/** Def ::= val PatDef
1880-
* | var VarDef
1881-
* | def DefDef
1882-
* | type {nl} TypeDcl
1883-
* | TmplDef
1884-
* Dcl ::= val ValDcl
1885-
* | var ValDcl
1886-
* | def DefDcl
1887-
* | type {nl} TypeDcl
1879+
/** Def ::= val PatDef
1880+
* | var VarDef
1881+
* | def DefDef
1882+
* | type {nl} TypeDcl
1883+
* | TmplDef
1884+
* Dcl ::= val ValDcl
1885+
* | var ValDcl
1886+
* | def DefDcl
1887+
* | type {nl} TypeDcl
1888+
* EnumCase ::= `case' (EnumClassDef | ObjectDef)
18881889
*/
18891890
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
18901891
case VAL =>
@@ -1899,6 +1900,8 @@ object Parsers {
18991900
defDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
19001901
case TYPE =>
19011902
typeDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
1903+
case CASE =>
1904+
enumCase(start, mods, in.getDocComment(start))
19021905
case _ =>
19031906
tmplDef(start, mods)
19041907
}
@@ -2029,8 +2032,9 @@ object Parsers {
20292032
}
20302033
}
20312034

2032-
/** TmplDef ::= ([`case'] `class' | `trait') ClassDef
2033-
* | [`case'] `object' ObjectDef
2035+
/** TmplDef ::= ([`case' | `enum]'] ‘class’ | [`enum'] trait’) ClassDef
2036+
* | [`case' | `enum'] `object' ObjectDef
2037+
* | `enum' EnumDef
20342038
*/
20352039
def tmplDef(start: Int, mods: Modifiers): Tree = {
20362040
val docstring = in.getDocComment(start)
@@ -2045,29 +2049,39 @@ object Parsers {
20452049
objectDef(start, posMods(start, mods | Module), docstring)
20462050
case CASEOBJECT =>
20472051
objectDef(start, posMods(start, mods | Case | Module), docstring)
2052+
case ENUM =>
2053+
val mods1 = addMod(mods, atPos(in.skipToken()) { Mod.Enum() })
2054+
in.token match {
2055+
case CLASS | TRAIT | OBJECT => tmplDef(start, mods1)
2056+
case _ => enumDef(start, mods, docstring)
2057+
}
20482058
case _ =>
20492059
syntaxErrorOrIncomplete("expected start of definition")
20502060
EmptyTree
20512061
}
20522062
}
20532063

2054-
/** ClassDef ::= id [ClsTypeParamClause]
2055-
* [ConstrMods] ClsParamClauses TemplateOpt
2064+
/** ClassDef ::= id ClassConstr TemplateOpt
20562065
*/
20572066
def classDef(start: Offset, mods: Modifiers, docstring: Option[Comment]): TypeDef = atPos(start, nameStart) {
2058-
val name = ident().toTypeName
2059-
val constr = atPos(in.lastOffset) {
2060-
val tparams = typeParamClauseOpt(ParamOwner.Class)
2061-
val cmods = constrModsOpt()
2062-
val vparamss = paramClauses(name, mods is Case)
2067+
classDefRest(start, mods, docstring, ident().toTypeName)
2068+
}
20632069

2064-
makeConstructor(tparams, vparamss).withMods(cmods)
2065-
}
2070+
def classDefRest(start: Offset, mods: Modifiers, docstring: Option[Comment], name: TypeName): TypeDef = {
2071+
val constr = classConstr(name, isCaseClass = mods is Case)
20662072
val templ = templateOpt(constr)
2067-
20682073
TypeDef(name, templ).withMods(mods).setComment(docstring)
20692074
}
20702075

2076+
/** ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses
2077+
*/
2078+
def classConstr(owner: Name, isCaseClass: Boolean = false): DefDef = atPos(in.lastOffset) {
2079+
val tparams = typeParamClauseOpt(ParamOwner.Class)
2080+
val cmods = constrModsOpt()
2081+
val vparamss = paramClauses(owner, isCaseClass)
2082+
makeConstructor(tparams, vparamss).withMods(cmods)
2083+
}
2084+
20712085
/** ConstrMods ::= AccessModifier
20722086
* | Annotation {Annotation} (AccessModifier | `this')
20732087
*/
@@ -2082,12 +2096,64 @@ object Parsers {
20822096
/** ObjectDef ::= id TemplateOpt
20832097
*/
20842098
def objectDef(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): ModuleDef = atPos(start, nameStart) {
2085-
val name = ident()
2086-
val template = templateOpt(emptyConstructor)
2099+
objectDefRest(start, mods, docstring, ident())
2100+
}
20872101

2102+
def objectDefRest(start: Offset, mods: Modifiers, docstring: Option[Comment] = None, name: TermName): ModuleDef = {
2103+
val template = templateOpt(emptyConstructor)
20882104
ModuleDef(name, template).withMods(mods).setComment(docstring)
20892105
}
20902106

2107+
/** id ClassConstr [`extends' [ConstrApps]]
2108+
* [nl] ‘{’ EnumCaseStats ‘}’
2109+
*/
2110+
def enumDef(start: Offset, mods: Modifiers, docstring: Option[Comment] = None): EnumDef = atPos(start, nameStart) {
2111+
val name = ident().toTypeName
2112+
val constr = classConstr(name)
2113+
val parents =
2114+
if (in.token == EXTENDS) {
2115+
in.nextToken();
2116+
newLineOptWhenFollowedBy(LBRACE)
2117+
if (in.token == LBRACE) Nil else tokenSeparated(WITH, constrApp)
2118+
}
2119+
else Nil
2120+
newLineOptWhenFollowedBy(LBRACE)
2121+
val body = inBraces(enumCaseStats)
2122+
EnumDef(name, Template(constr, Nil, EmptyValDef, body))
2123+
.withMods(mods).setComment(in.getDocComment(start)).asInstanceOf[EnumDef]
2124+
}
2125+
2126+
/** EnumCaseStats = EnumCaseStat {semi EnumCaseStat */
2127+
def enumCaseStats(): List[MemberDef] = {
2128+
val cases = new ListBuffer[MemberDef] += enumCaseStat()
2129+
while (in.token != RBRACE) {
2130+
acceptStatSep()
2131+
cases += enumCaseStat()
2132+
}
2133+
cases.toList
2134+
}
2135+
2136+
/** EnumCaseStat = {Annotation [nl]} {Modifier} EnumCase */
2137+
def enumCaseStat(): MemberDef = {
2138+
val start = in.offset
2139+
val docstring = in.getDocComment(start)
2140+
val mods = defAnnotsMods(modifierTokens)
2141+
enumCase(start, mods, docstring)
2142+
}
2143+
2144+
/** EnumCase = `case' (EnumClassDef | ObjectDef) */
2145+
def enumCase(start: Offset, mods: Modifiers, docstring: Option[Comment]): MemberDef = {
2146+
val mods1 = mods.withAddedMod(atPos(in.offset)(Mod.EnumCase())) | Case
2147+
accept(CASE)
2148+
atPos(start, nameStart) {
2149+
val name = ident()
2150+
if (in.token == LBRACKET || in.token == LPAREN)
2151+
classDefRest(start, mods1, docstring, name.toTypeName)
2152+
else
2153+
objectDefRest(start, mods1, docstring, name)
2154+
}
2155+
}
2156+
20912157
/* -------- TEMPLATES ------------------------------------------- */
20922158

20932159
/** ConstrApp ::= SimpleType {ParArgumentExprs}
@@ -2197,8 +2263,8 @@ object Parsers {
21972263
* TemplateStat ::= Import
21982264
* | Annotations Modifiers Def
21992265
* | Annotations Modifiers Dcl
2266+
* | EnumCaseStat
22002267
* | Expr1
2201-
* | super ArgumentExprs {ArgumentExprs}
22022268
* |
22032269
*/
22042270
def templateStatSeq(): (ValDef, List[Tree]) = checkNoEscapingPlaceholders {
@@ -2228,7 +2294,7 @@ object Parsers {
22282294
stats ++= importClause()
22292295
else if (isExprIntro)
22302296
stats += expr1()
2231-
else if (isDefIntro(modifierTokens))
2297+
else if (isDefIntro(modifierTokensOrCase))
22322298
stats += defOrDcl(in.offset, defAnnotsMods(modifierTokens))
22332299
else if (!isStatSep) {
22342300
exitOnError = mustStartStat

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ abstract class TokensCommon {
9292
//final val THEN = 60; enter(THEN, "then")
9393
//final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
9494
//final val INLINE = 62; enter(INLINE, "inline")
95+
//final val ENUM = 63; enter(ENUM, "enum")
9596

9697
/** special symbols */
9798
final val COMMA = 70; enter(COMMA, "','")
@@ -173,6 +174,7 @@ object Tokens extends TokensCommon {
173174
final val THEN = 60; enter(THEN, "then")
174175
final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
175176
final val INLINE = 62; enter(INLINE, "inline")
177+
final val ENUM = 63; enter(ENUM, "enum")
176178

177179
/** special symbols */
178180
final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
@@ -226,6 +228,8 @@ object Tokens extends TokensCommon {
226228
final val modifierTokens = localModifierTokens | accessModifierTokens | BitSet(
227229
OVERRIDE)
228230

231+
final val modifierTokensOrCase = modifierTokens | BitSet(CASE)
232+
229233
/** Is token only legal as start of statement (eof also included)? */
230234
final val mustStartStatTokens = defIntroTokens | modifierTokens | BitSet(
231235
IMPORT, PACKAGE)

docs/docs/internals/syntax.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ TemplateBody ::= [nl] ‘{’ [SelfType] TemplateStat {semi TemplateStat}
289289
TemplateStat ::= Import
290290
| {Annotation [nl]} {Modifier} Def
291291
| {Annotation [nl]} {Modifier} Dcl
292+
| EnumCaseStat
292293
| Expr1
294+
|
293295
SelfType ::= id [‘:’ InfixType] ‘=>’ ValDef(_, name, tpt, _)
294296
| ‘this’ ‘:’ InfixType ‘=>’
295297
@@ -328,13 +330,20 @@ DefDef ::= DefSig [‘:’ Type] ‘=’ Expr
328330
| ‘this’ DefParamClause DefParamClauses DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
329331
(‘=’ ConstrExpr | [nl] ConstrBlock)
330332
331-
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
332-
| [‘case’] ‘object’ ObjectDef
333-
ClassDef ::= id [ClsTypeParamClause] ClassDef(mods, name, tparams, templ)
334-
[ConstrMods] ClsParamClauses TemplateOpt with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
333+
TmplDef ::= ([‘case’ | `enum'] ‘class’ | [`enum'] trait’) ClassDef
334+
| [‘case’ | `enum'] ‘object’ ObjectDef
335+
| `enum' EnumDef
336+
ClassDef ::= id ClassConstr TemplateOpt ClassDef(mods, name, tparams, templ)
337+
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
335338
ConstrMods ::= AccessModifier
336339
| Annotation {Annotation} (AccessModifier | ‘this’)
337340
ObjectDef ::= id TemplateOpt ModuleDef(mods, name, template) // no constructor
341+
EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumDef(mods, name, tparams, template)
342+
[nl] ‘{’ EnumCaseStat {semi EnumCaseStat ‘}’
343+
EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase
344+
EnumCase ::= `case' (EnumClassDef | ObjectDef)
345+
EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause] ClassDef(mods, name, tparams, templ)
346+
ClsParamClauses TemplateOpt
338347
TemplateOpt ::= [‘extends’ Template | [nl] TemplateBody]
339348
Template ::= ConstrApps [TemplateBody] | TemplateBody Template(constr, parents, self, stats)
340349
ConstrApps ::= ConstrApp {‘with’ ConstrApp}

0 commit comments

Comments
 (0)