@@ -188,7 +188,7 @@ object Parsers {
188188/* -------------- TOKEN CLASSES ------------------------------------------- */
189189
190190 def isIdent = in.isIdent
191- def isIdent (name : Name ) = in.token == IDENTIFIER && in. name == name
191+ def isIdent (name : Name ) = in.isIdent( name)
192192 def isSimpleLiteral = simpleLiteralTokens contains in.token
193193 def isLiteral = literalTokens contains in.token
194194 def isNumericLit = numericLitTokens contains in.token
@@ -216,10 +216,11 @@ object Parsers {
216216 in.canStartExprTokens.contains(in.token) && ! in.isSoftModifierInModifierPosition
217217
218218 def isDefIntro (allowedMods : BitSet , excludedSoftModifiers : Set [TermName ] = Set .empty): Boolean =
219- in.token == AT ||
220- (defIntroTokens `contains` in.token) ||
221- (allowedMods `contains` in.token) ||
222- in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
219+ in.token == AT
220+ || defIntroTokens.contains(in.token)
221+ || allowedMods.contains(in.token)
222+ || in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
223+ || isIdent(nme.extension) && followingIsExtension()
223224
224225 def isStatSep : Boolean = in.isNewLine || in.token == SEMI
225226
@@ -944,6 +945,13 @@ object Parsers {
944945 lookahead.skipParens()
945946 lookahead.token == COLON || lookahead.token == SUBTYPE
946947
948+ def followingIsExtension () =
949+ val lookahead = in.LookaheadScanner ()
950+ lookahead.nextToken()
951+ if lookahead.isIdent && ! lookahead.isIdent(nme.of) then
952+ lookahead.nextToken()
953+ lookahead.isIdent(nme.of)
954+
947955/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
948956
949957 var opStack : List [OpInfo ] = Nil
@@ -3275,6 +3283,7 @@ object Parsers {
32753283 * | [‘case’] ‘object’ ObjectDef
32763284 * | ‘enum’ EnumDef
32773285 * | ‘given’ GivenDef
3286+ * | ‘extension’ ExtensionDef
32783287 */
32793288 def tmplDef (start : Int , mods : Modifiers ): Tree =
32803289 in.token match {
@@ -3293,8 +3302,11 @@ object Parsers {
32933302 case GIVEN =>
32943303 givenDef(start, mods, atSpan(in.skipToken()) { Mod .Given () })
32953304 case _ =>
3296- syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition ())
3297- EmptyTree
3305+ if isIdent(nme.extension) && followingIsExtension() then
3306+ extensionDef(start, mods)
3307+ else
3308+ syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition ())
3309+ EmptyTree
32983310 }
32993311
33003312 /** ClassDef ::= id ClassConstr TemplateOpt
@@ -3522,6 +3534,23 @@ object Parsers {
35223534 finalizeDef(gdef, mods1, start)
35233535 }
35243536
3537+ /** ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ‘with’ ExtMethods
3538+ */
3539+ def extensionDef (start : Offset , mods : Modifiers ): ModuleDef =
3540+ in.nextToken()
3541+ val name = if isIdent && ! isIdent(nme.of) then ident() else EmptyTermName
3542+ if ! isIdent(nme.of) then syntaxErrorOrIncomplete(" `of` expected" )
3543+ if isIdent(nme.of) then in.nextToken()
3544+ val tparams = typeParamClauseOpt(ParamOwner .Def )
3545+ val extParams = paramClause(0 , prefix = true )
3546+ val givenParamss = paramClauses(givenOnly = true )
3547+ accept(WITH )
3548+ if ! in.isNestedStart then syntaxError(" Extension without extension methods" )
3549+ val templ = templateBodyOpt(makeConstructor(tparams, extParams :: givenParamss), Nil , Nil )
3550+ templ.body.foreach(checkExtensionMethod(tparams, _))
3551+ val edef = ModuleDef (name, templ)
3552+ finalizeDef(edef, addFlag(mods, Given ), start)
3553+
35253554/* -------- TEMPLATES ------------------------------------------- */
35263555
35273556 /** SimpleConstrApp ::= AnnotType {ParArgumentExprs}
@@ -3681,7 +3710,7 @@ object Parsers {
36813710 def templateStatSeq (): (ValDef , List [Tree ]) = checkNoEscapingPlaceholders {
36823711 var self : ValDef = EmptyValDef
36833712 val stats = new ListBuffer [Tree ]
3684- if (isExprIntro) {
3713+ if (isExprIntro && ! isDefIntro(modifierTokens) ) {
36853714 val first = expr1()
36863715 if (in.token == ARROW ) {
36873716 first match {
@@ -3707,10 +3736,10 @@ object Parsers {
37073736 stats ++= importClause(IMPORT , Import )
37083737 else if (in.token == EXPORT )
37093738 stats ++= importClause(EXPORT , Export .apply)
3710- else if (isExprIntro)
3711- stats += expr1()
37123739 else if (isDefIntro(modifierTokensOrCase))
37133740 stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens))
3741+ else if (isExprIntro)
3742+ stats += expr1()
37143743 else if (! isStatSep) {
37153744 exitOnError = mustStartStat
37163745 syntaxErrorOrIncomplete(" illegal start of definition" )
0 commit comments