From ee59c23e9033ed775c64583c849bd47cc3f195af Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 4 Dec 2016 14:41:28 +0100 Subject: Generalize syntax for implicit function values - allow more than one implicit binding - harmonize syntax in expressions and blocks --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 117 +++++++++++++-------- 1 file changed, 74 insertions(+), 43 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/parsing/Parsers.scala') diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5dd0df022..6fb10fd39 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -146,6 +146,7 @@ object Parsers { def isNumericLit = numericLitTokens contains in.token def isModifier = modifierTokens contains in.token def isExprIntro = canStartExpressionTokens contains in.token + def isBindingIntro = canStartBindingTokens contains in.token def isTemplateIntro = templateIntroTokens contains in.token def isDclIntro = dclIntroTokens contains in.token def isStatSeqEnd = in.token == RBRACE || in.token == EOF @@ -951,14 +952,14 @@ object Parsers { } } - /** Expr ::= FunParams `=>' Expr + /** Expr ::= [`implicit'] FunParams `=>' Expr * | Expr1 * FunParams ::= Bindings - * | [`implicit'] Id + * | Id * | `_' * ExprInParens ::= PostfixExpr `:' Type * | Expr - * BlockResult ::= (FunParams | [`implicit'] Id `:' InfixType) => Block + * BlockResult ::= [`implicit'] FunParams `=>' Block * | Expr1 * Expr1 ::= `if' `(' Expr `)' {nl} Expr [[semi] else Expr] * | `if' Expr `then' Expr [[semi] else Expr] @@ -985,22 +986,27 @@ object Parsers { def expr(): Tree = expr(Location.ElseWhere) def expr(location: Location.Value): Tree = { - val saved = placeholderParams - placeholderParams = Nil - val t = expr1(location) - if (in.token == ARROW) { - placeholderParams = saved - closureRest(startOffset(t), location, convertToParams(t)) - } - else if (isWildcard(t)) { - placeholderParams = placeholderParams ::: saved - t + val start = in.offset + if (in.token == IMPLICIT) + implicitClosure(start, location, implicitMods()) + else { + val saved = placeholderParams + placeholderParams = Nil + val t = expr1(location) + if (in.token == ARROW) { + placeholderParams = saved + closureRest(start, location, convertToParams(t)) + } + else if (isWildcard(t)) { + placeholderParams = placeholderParams ::: saved + t + } + else + try + if (placeholderParams.isEmpty) t + else new WildcardFunction(placeholderParams.reverse, t) + finally placeholderParams = saved } - else - try - if (placeholderParams.isEmpty) t - else new WildcardFunction(placeholderParams.reverse, t) - finally placeholderParams = saved } def expr1(location: Location.Value = Location.ElseWhere): Tree = in.token match { @@ -1066,8 +1072,6 @@ object Parsers { atPos(in.skipToken()) { Return(if (isExprIntro) expr() else EmptyTree, EmptyTree) } case FOR => forExpr() - case IMPLICIT => - implicitClosure(in.offset, location, atPos(in.skipToken()) { Mod.Implicit() }) case _ => expr1Rest(postfixExpr(), location) } @@ -1115,19 +1119,43 @@ object Parsers { } } + /** FunParams ::= Bindings + * | Id + * | `_' + * Bindings ::= `(' [Binding {`,' Binding}] `)' + */ + def funParams(mods: Modifiers, location: Location.Value): List[Tree] = + if (in.token == LPAREN) + inParens(if (in.token == RPAREN) Nil else commaSeparated(() => binding(mods))) + else { + val start = in.offset + val name = bindingName() + val t = + if (in.token == COLON && location == Location.InBlock) { + in.nextToken() + infixType() + } + else TypeTree() + (atPos(start) { makeParameter(name, t, mods) }) :: Nil + } + + /** Binding ::= (Id | `_') [`:' Type] + */ + def binding(mods: Modifiers): Tree = + atPos(in.offset) { makeParameter(bindingName(), typedOpt(), mods) } + + def bindingName(): TermName = + if (in.token == USCORE) { + in.nextToken() + ctx.freshName(nme.USCORE_PARAM_PREFIX).toTermName + } + else ident() + /** Expr ::= implicit Id `=>' Expr - * BlockResult ::= implicit Id [`:' InfixType] `=>' Block - */ - def implicitClosure(start: Int, location: Location.Value, implicitMod: Mod): Tree = { - val mods = Modifiers(Implicit).withAddedMod(implicitMod) - val id = termIdent() - val paramExpr = - if (location == Location.InBlock && in.token == COLON) - atPos(startOffset(id), in.skipToken()) { Typed(id, infixType()) } - else - id - closureRest(start, location, convertToParam(paramExpr, mods) :: Nil) - } + * BlockResult ::= implicit Id [`:' InfixType] `=>' Block // Scala2 only + */ + def implicitClosure(start: Int, location: Location.Value, implicitMods: Modifiers): Tree = + closureRest(start, location, funParams(implicitMods, location)) def closureRest(start: Int, location: Location.Value, params: List[Tree]): Tree = atPos(start, in.offset) { @@ -1581,6 +1609,9 @@ object Parsers { normalize(loop(start)) } + def implicitMods(): Modifiers = + addMod(EmptyModifiers, atPos(accept(IMPLICIT)) { Mod.Implicit() }) + /** Wrap annotation or constructor in New(...). */ def wrapNew(tpt: Tree) = Select(New(tpt), nme.CONSTRUCTOR) @@ -1686,9 +1717,9 @@ object Parsers { * Param ::= id `:' ParamType [`=' Expr] */ def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = { - var implicitMod: Mod = null - var firstClauseOfCaseClass = ofCaseClass + var imods: Modifiers = EmptyModifiers var implicitOffset = -1 // use once + var firstClauseOfCaseClass = ofCaseClass def param(): ValDef = { val start = in.offset var mods = annotsAsMods() @@ -1723,7 +1754,7 @@ object Parsers { if (in.token == ARROW) { if (owner.isTypeName && !(mods is Local)) syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name") - else if (implicitMod != null) + else if (imods.hasFlags) syntaxError("implicit parameters may not be call-by-name") } paramType() @@ -1735,7 +1766,7 @@ object Parsers { mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset))) implicitOffset = -1 } - if (implicitMod != null) mods = addMod(mods, implicitMod) + for (imod <- imods.mods) mods = addMod(mods, imod) ValDef(name, tpt, default).withMods(mods) } } @@ -1744,7 +1775,7 @@ object Parsers { else { if (in.token == IMPLICIT) { implicitOffset = in.offset - implicitMod = atPos(in.skipToken()) { Mod.Implicit() } + imods = implicitMods() } commaSeparated(param) } @@ -1754,7 +1785,7 @@ object Parsers { if (in.token == LPAREN) paramClause() :: { firstClauseOfCaseClass = false - if (implicitMod == null) clauses() else Nil + if (imods.hasFlags) Nil else clauses() } else Nil } @@ -2217,9 +2248,9 @@ object Parsers { stats.toList } - def localDef(start: Int, implicitMod: Option[Mod] = None): Tree = { + def localDef(start: Int, implicitMods: Modifiers = EmptyModifiers): Tree = { var mods = defAnnotsMods(localModifierTokens) - for (imod <- implicitMod) mods = (mods | ImplicitCommon).withAddedMod(imod) + for (imod <- implicitMods.mods) mods = addMod(mods, imod) defOrDcl(start, mods) } @@ -2242,9 +2273,9 @@ object Parsers { else if (isDefIntro(localModifierTokens)) if (in.token == IMPLICIT) { val start = in.offset - val mod = atPos(in.skipToken()) { Mod.Implicit() } - if (isIdent) stats += implicitClosure(start, Location.InBlock, mod) - else stats += localDef(start, Some(mod)) + val imods = implicitMods() + if (isBindingIntro) stats += implicitClosure(start, Location.InBlock, imods) + else stats += localDef(start, imods) } else { stats += localDef(in.offset) } -- cgit v1.2.3