Skip to content

Commit d8f4413

Browse files
committed
Parser for fixed syntax
1 parent 4874d71 commit d8f4413

File tree

4 files changed

+76
-23
lines changed

4 files changed

+76
-23
lines changed

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

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

43+
/** extend extended impl */
44+
case class Extension(name: TypeName, extended: Tree, impl: Template) extends DefTree
45+
4346
case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree
4447

4548
case class SymbolLit(str: String) extends TermTree
@@ -139,6 +142,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
139142
case class Enum() extends Mod(Flags.EmptyFlags)
140143

141144
case class EnumCase() extends Mod(Flags.EmptyFlags)
145+
146+
case class InstanceDecl() extends Mod(Flags.EmptyFlags)
142147
}
143148

144149
/** Modifiers and annotations for definitions

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

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ object Parsers {
10581058
* | PostfixExpr `match' `{' CaseClauses `}'
10591059
* Bindings ::= `(' [Binding {`,' Binding}] `)'
10601060
* Binding ::= (id | `_') [`:' Type]
1061-
* Ascription ::= `:' CompoundType
1061+
* Ascription ::= `:' InfixType
10621062
* | `:' Annotation {Annotation}
10631063
* | `:' `_' `*'
10641064
*/
@@ -1178,6 +1178,13 @@ object Parsers {
11781178
t
11791179
}
11801180

1181+
/** Ascription ::= `:' InfixType
1182+
* | `:' Annotation {Annotation}
1183+
* | `:' `_' `*'
1184+
* PatternAscription ::= `:' TypePattern
1185+
* | `:' `_' `*'
1186+
* TypePattern ::= RefinedType
1187+
*/
11811188
def ascription(t: Tree, location: Location.Value) = atPos(startOffset(t)) {
11821189
in.skipToken()
11831190
in.token match {
@@ -1539,7 +1546,7 @@ object Parsers {
15391546
if (isIdent(nme.raw.BAR)) { in.nextToken(); pattern1() :: patternAlts() }
15401547
else Nil
15411548

1542-
/** Pattern1 ::= PatVar Ascription
1549+
/** Pattern1 ::= PatVar PatternAscription
15431550
* | Pattern2
15441551
*/
15451552
def pattern1(): Tree = {
@@ -1831,8 +1838,10 @@ object Parsers {
18311838
* DefParams ::= DefParam {`,' DefParam}
18321839
* DefParam ::= {Annotation} [`inline'] Param
18331840
* Param ::= id `:' ParamType [`=' Expr]
1841+
* ImplicitParamClause ::= [nl] ‘(’ ImplicitMods ClsParams ‘)’)
1842+
* ImplicitMods ::= `implicit` [`unused`] | `unused` `implicit`
18341843
*/
1835-
def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = {
1844+
def paramClauses(owner: Name, ofCaseClass: Boolean = false, ofExtension: Boolean = false): List[List[ValDef]] = {
18361845
var imods: Modifiers = EmptyModifiers
18371846
var implicitOffset = -1 // use once
18381847
var firstClauseOfCaseClass = ofCaseClass
@@ -1878,7 +1887,7 @@ object Parsers {
18781887
}
18791888
}
18801889
def paramClause(): List[ValDef] = inParens {
1881-
if (in.token == RPAREN) Nil
1890+
if (!ofExtension && in.token == RPAREN) Nil
18821891
else {
18831892
def funArgMods(): Unit = {
18841893
if (in.token == IMPLICIT) {
@@ -1891,7 +1900,8 @@ object Parsers {
18911900
}
18921901
}
18931902
funArgMods()
1894-
1903+
if (ofExtension && !imods.is(Implicit))
1904+
syntaxError(i"parameters of extension must be implicit")
18951905
commaSeparated(() => param())
18961906
}
18971907
}
@@ -1901,7 +1911,7 @@ object Parsers {
19011911
imods = EmptyModifiers
19021912
paramClause() :: {
19031913
firstClauseOfCaseClass = false
1904-
if (imods is Implicit) Nil else clauses()
1914+
if (imods.is(Implicit) || ofExtension) Nil else clauses()
19051915
}
19061916
} else Nil
19071917
}
@@ -2159,6 +2169,7 @@ object Parsers {
21592169
/** TmplDef ::= ([`case'] ‘class’ | trait’) ClassDef
21602170
* | [`case'] `object' ObjectDef
21612171
* | `enum' EnumDef
2172+
* | `extension' ExtensionDef
21622173
*/
21632174
def tmplDef(start: Int, mods: Modifiers): Tree = {
21642175
in.token match {
@@ -2174,21 +2185,23 @@ object Parsers {
21742185
objectDef(start, posMods(start, mods | Case | Module))
21752186
case ENUM =>
21762187
enumDef(start, mods, atPos(in.skipToken()) { Mod.Enum() })
2188+
case EXTENSION =>
2189+
extensionDef(start, posMods(start, mods))
21772190
case _ =>
21782191
syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition())
21792192
EmptyTree
21802193
}
21812194
}
21822195

2183-
/** ClassDef ::= id ClassConstr TemplateOpt
2196+
/** ClassDef ::= id ClassConstr [TemplateClause]
21842197
*/
21852198
def classDef(start: Offset, mods: Modifiers): TypeDef = atPos(start, nameStart) {
21862199
classDefRest(start, mods, ident().toTypeName)
21872200
}
21882201

21892202
def classDefRest(start: Offset, mods: Modifiers, name: TypeName): TypeDef = {
21902203
val constr = classConstr(name, isCaseClass = mods is Case)
2191-
val templ = templateOpt(constr)
2204+
val templ = templateClauseOpt(constr)
21922205
TypeDef(name, templ).withMods(mods).setComment(in.getDocComment(start))
21932206
}
21942207

@@ -2197,7 +2210,7 @@ object Parsers {
21972210
def classConstr(owner: Name, isCaseClass: Boolean = false): DefDef = atPos(in.lastOffset) {
21982211
val tparams = typeParamClauseOpt(ParamOwner.Class)
21992212
val cmods = fromWithinClassConstr(constrModsOpt(owner))
2200-
val vparamss = paramClauses(owner, isCaseClass)
2213+
val vparamss = paramClauses(owner, ofCaseClass = isCaseClass)
22012214
makeConstructor(tparams, vparamss).withMods(cmods)
22022215
}
22032216

@@ -2206,14 +2219,14 @@ object Parsers {
22062219
def constrModsOpt(owner: Name): Modifiers =
22072220
modifiers(accessModifierTokens, annotsAsMods())
22082221

2209-
/** ObjectDef ::= id TemplateOpt
2222+
/** ObjectDef ::= id [TemplateClause]
22102223
*/
22112224
def objectDef(start: Offset, mods: Modifiers): ModuleDef = atPos(start, nameStart) {
22122225
objectDefRest(start, mods, ident())
22132226
}
22142227

22152228
def objectDefRest(start: Offset, mods: Modifiers, name: TermName): ModuleDef = {
2216-
val template = templateOpt(emptyConstructor)
2229+
val template = templateClauseOpt(emptyConstructor)
22172230
ModuleDef(name, template).withMods(mods).setComment(in.getDocComment(start))
22182231
}
22192232

@@ -2223,7 +2236,7 @@ object Parsers {
22232236
val modName = ident()
22242237
val clsName = modName.toTypeName
22252238
val constr = classConstr(clsName)
2226-
val impl = templateOpt(constr, isEnum = true)
2239+
val impl = templateClauseOpt(constr, isEnum = true, bodyRequired = true)
22272240
TypeDef(clsName, impl).withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start))
22282241
}
22292242

@@ -2269,6 +2282,36 @@ object Parsers {
22692282
Template(constr, parents, EmptyValDef, Nil)
22702283
}
22712284

2285+
/** ExtensionDef ::= id [ExtensionParams] 'for' AnnotType ExtensionClause
2286+
* ExtensionParams ::= [ClsTypeParamClause] [[nl] ImplicitParamClause]
2287+
* ExtensionClause ::= [`:` Template]
2288+
* | [nl] `{` `def` DefDef {semi `def` DefDef} `}`
2289+
*/
2290+
def extensionDef(start: Offset, mods: Modifiers): Extension = atPos(start, nameStart) {
2291+
val name = ident().toTypeName
2292+
val tparams = typeParamClauseOpt(ParamOwner.Class)
2293+
val vparamss = paramClauses(tpnme.EMPTY, ofExtension = true).take(1)
2294+
val constr = makeConstructor(Nil, vparamss)
2295+
accept(FOR)
2296+
val extended = annotType()
2297+
val templ =
2298+
if (in.token == COLON) {
2299+
in.nextToken()
2300+
template(constr, bodyRequired = true)._1
2301+
}
2302+
else {
2303+
val templ = templateClauseOpt(constr, bodyRequired = true)
2304+
def checkDef(tree: Tree) = tree match {
2305+
case _: DefDef | EmptyValDef => // ok
2306+
case _ => syntaxError("`def` expected", tree.pos.startPos.orElse(templ.pos.startPos))
2307+
}
2308+
checkDef(templ.self)
2309+
templ.body.foreach(checkDef)
2310+
templ
2311+
}
2312+
Extension(name, extended, templ)
2313+
}
2314+
22722315
/* -------- TEMPLATES ------------------------------------------- */
22732316

22742317
/** ConstrApp ::= SimpleType {ParArgumentExprs}
@@ -2285,26 +2328,30 @@ object Parsers {
22852328
* @return a pair consisting of the template, and a boolean which indicates
22862329
* whether the template misses a body (i.e. no {...} part).
22872330
*/
2288-
def template(constr: DefDef, isEnum: Boolean = false): (Template, Boolean) = {
2331+
def template(constr: DefDef, isEnum: Boolean = false, bodyRequired: Boolean = false): (Template, Boolean) = {
22892332
newLineOptWhenFollowedBy(LBRACE)
22902333
if (in.token == LBRACE) (templateBodyOpt(constr, Nil, isEnum), false)
22912334
else {
22922335
val parents = tokenSeparated(WITH, constrApp)
22932336
newLineOptWhenFollowedBy(LBRACE)
2294-
if (isEnum && in.token != LBRACE)
2337+
if (bodyRequired && in.token != LBRACE)
22952338
syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token))
22962339
val missingBody = in.token != LBRACE
22972340
(templateBodyOpt(constr, parents, isEnum), missingBody)
22982341
}
22992342
}
23002343

2301-
/** TemplateOpt = [`extends' Template | TemplateBody]
2344+
/** TemplateClause = `extends' Template | TemplateBody
2345+
* TemplateClauseOpt = [TemplateClause]
23022346
*/
2303-
def templateOpt(constr: DefDef, isEnum: Boolean = false): Template =
2304-
if (in.token == EXTENDS) { in.nextToken(); template(constr, isEnum)._1 }
2347+
def templateClauseOpt(constr: DefDef, isEnum: Boolean = false, bodyRequired: Boolean = false): Template =
2348+
if (in.token == EXTENDS) {
2349+
in.nextToken()
2350+
template(constr, isEnum, bodyRequired)._1
2351+
}
23052352
else {
23062353
newLineOptWhenFollowedBy(LBRACE)
2307-
if (in.token == LBRACE) template(constr, isEnum)._1
2354+
if (in.token == LBRACE || bodyRequired) template(constr, isEnum, bodyRequired)._1
23082355
else Template(constr, Nil, EmptyValDef, Nil)
23092356
}
23102357

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ object Tokens extends TokensCommon {
179179
final val ENUM = 63; enter(ENUM, "enum")
180180
final val ERASED = 64; enter(ERASED, "erased")
181181
final val OPAQUE = 65; enter(OPAQUE, "opaque")
182+
final val EXTENSION = 66; enter(EXTENSION, "extension")
182183

183184
/** special symbols */
184185
final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
@@ -199,7 +200,7 @@ object Tokens extends TokensCommon {
199200
/** XML mode */
200201
final val XMLSTART = 96; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate
201202

202-
final val alphaKeywords = tokenRange(IF, OPAQUE)
203+
final val alphaKeywords = tokenRange(IF, EXTENSION)
203204
final val symbolicKeywords = tokenRange(USCORE, VIEWBOUND)
204205
final val symbolicTokens = tokenRange(COMMA, VIEWBOUND)
205206
final val keywords = alphaKeywords | symbolicKeywords
@@ -220,7 +221,7 @@ object Tokens extends TokensCommon {
220221

221222
final val canStartBindingTokens = identifierTokens | BitSet(USCORE, LPAREN)
222223

223-
final val templateIntroTokens = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT)
224+
final val templateIntroTokens = BitSet(CLASS, TRAIT, OBJECT, ENUM, EXTENSION, CASECLASS, CASEOBJECT)
224225

225226
final val dclIntroTokens = BitSet(DEF, VAL, VAR, TYPE)
226227

docs/docs/internals/syntax.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,14 @@ DefDef ::= DefSig [‘:’ Type] ‘=’ Expr
329329
330330
TmplDef ::= ([‘case’] ‘class’ | trait’) ClassDef
331331
| [‘case’] ‘object’ ObjectDef
332-
| `enum' EnumDef
332+
| ‘enum’ EnumDef
333+
| ‘extension’ ExtensionDef
333334
ClassDef ::= id ClassConstr [TemplateClause] ClassDef(mods, name, tparams, templ)
334335
ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, <init>, Nil, vparamss, EmptyTree, EmptyTree) as first stat
335336
ConstrMods ::= {Annotation} [AccessModifier]
336337
ObjectDef ::= id [TemplateClause] ModuleDef(mods, name, template) // no constructor
337338
EnumDef ::= id ClassConstr [`extends' [ConstrApps]] EnumBody TypeDef(mods, name, template)
338-
Extension ::= 'extension' id [ExtensionParams] Extension(name, templ)
339-
'for' Type ExtensionClause
339+
ExtensionDef ::= id [ExtensionParams] 'for' AnnotType ExtensionClause Extension(name, type, templ)
340340
ExtensionParams ::= [ClsTypeParamClause] [[nl] ImplicitParamClause]
341341
ExtensionClause ::= [`:` Template]
342342
| [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’

0 commit comments

Comments
 (0)