diff options
author | odersky <odersky@gmail.com> | 2016-10-25 15:42:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-25 15:42:31 +0200 |
commit | 40da850dfb5218131d0a8a0cdfd87bbe54569832 (patch) | |
tree | 96c65f2b0997e5bd1c4c951ca62b62d35cce335d /src | |
parent | 133fbb352b5acafb9e1ea5ab53e8678dca03afd9 (diff) | |
parent | 24a725db99786eaf5f37903429bfefcf8db12aaf (diff) | |
download | dotty-40da850dfb5218131d0a8a0cdfd87bbe54569832.tar.gz dotty-40da850dfb5218131d0a8a0cdfd87bbe54569832.tar.bz2 dotty-40da850dfb5218131d0a8a0cdfd87bbe54569832.zip |
Merge pull request #1608 from dotty-staging/modifiers
Record syntactic information about modifiers
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/untpd.scala | 50 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 89 |
2 files changed, 98 insertions, 41 deletions
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 852c3a346..6513dfdc3 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -94,9 +94,42 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { class InfixOpBlock(leftOperand: Tree, rightOp: Tree) extends Block(leftOperand :: Nil, rightOp) // ----- Modifiers ----------------------------------------------------- + /** Mod is intended to record syntactic information about modifiers, it's + * NOT a replacement of FlagSet. + * + * For any query about semantic information, check `flags` instead. + */ + sealed abstract class Mod(val flags: FlagSet) extends Positioned - /** Modifiers and annotations for definitions - * @param flags The set flags + object Mod { + case class Private() extends Mod(Flags.Private) + + case class Protected() extends Mod(Flags.Protected) + + case class Val() extends Mod(Flags.EmptyFlags) + + case class Var() extends Mod(Flags.Mutable) + + case class Implicit(flag: FlagSet = Flags.ImplicitCommon) extends Mod(flag) + + case class Final() extends Mod(Flags.Final) + + case class Sealed() extends Mod(Flags.Sealed) + + case class Override() extends Mod(Flags.Override) + + case class Abstract() extends Mod(Flags.Abstract) + + case class Lazy() extends Mod(Flags.Lazy) + + case class Inline() extends Mod(Flags.Inline) + + case class Type() extends Mod(Flags.EmptyFlags) + } + + /** Modifiers and annotations for definitions + * + * @param flags The set flags * @param privateWithin If a private or protected has is followed by a * qualifier [q], the name q, "" as a typename otherwise. * @param annotations The annotations preceding the modifiers @@ -104,7 +137,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Modifiers ( flags: FlagSet = EmptyFlags, privateWithin: TypeName = tpnme.EMPTY, - annotations: List[Tree] = Nil) extends Positioned with Cloneable { + annotations: List[Tree] = Nil, + mods: List[Mod] = Nil) extends Positioned with Cloneable { def is(fs: FlagSet): Boolean = flags is fs def is(fc: FlagConjunction): Boolean = flags is fc @@ -120,7 +154,15 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { if (this.flags == flags) this else copy(flags = flags) - def withAddedAnnotation(annot: Tree): Modifiers = + def withAddedMod(mod: Mod): Modifiers = + if (mods.exists(_ eq mod)) this + else withMods(mods :+ mod) + + def withMods(ms: List[Mod]): Modifiers = + if (mods eq ms) this + else copy(mods = ms) + + def withAddedAnnotation(annot: Tree): Modifiers = if (annotations.exists(_ eq annot)) this else withAnnotations(annotations :+ annot) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 17e894144..6adb7f010 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1097,8 +1097,9 @@ object Parsers { /** Expr ::= implicit Id `=>' Expr * BlockResult ::= implicit Id [`:' InfixType] `=>' Block */ - def implicitClosure(start: Int, location: Location.Value): Tree = { - val mods = atPos(start) { Modifiers(Implicit) } + def implicitClosure(start: Int, location: Location.Value, implicitMod: Option[Mod] = None): Tree = { + var mods = atPos(start) { Modifiers(Implicit) } + if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get) val id = termIdent() val paramExpr = if (location == Location.InBlock && in.token == COLON) @@ -1464,19 +1465,19 @@ object Parsers { /* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */ - private def flagOfToken(tok: Int): FlagSet = tok match { - case ABSTRACT => Abstract - case FINAL => Final - case IMPLICIT => ImplicitCommon - case INLINE => Inline - case LAZY => Lazy - case OVERRIDE => Override - case PRIVATE => Private - case PROTECTED => Protected - case SEALED => Sealed + private def modOfToken(tok: Int): Mod = tok match { + case ABSTRACT => Mod.Abstract() + case FINAL => Mod.Final() + case IMPLICIT => Mod.Implicit(ImplicitCommon) + case INLINE => Mod.Inline() + case LAZY => Mod.Lazy() + case OVERRIDE => Mod.Override() + case PRIVATE => Mod.Private() + case PROTECTED => Mod.Protected() + case SEALED => Mod.Sealed() } - /** Drop `private' modifier when followed by a qualifier. + /** Drop `private' modifier when followed by a qualifier. * Contract `abstract' and `override' to ABSOVERRIDE */ private def normalize(mods: Modifiers): Modifiers = @@ -1488,11 +1489,11 @@ object Parsers { mods private def addModifier(mods: Modifiers): Modifiers = { - val flag = flagOfToken(in.token) - if (mods is flag) syntaxError(RepeatedModifier(flag.toString)) - val res = addFlag(mods, flag) - in.nextToken() - res + val tok = in.token + val mod = atPos(in.skipToken()) { modOfToken(tok) } + + if (mods is mod.flags) syntaxError(RepeatedModifier(mod.flags.toString)) + addMod(mods, mod) } private def compatible(flags1: FlagSet, flags2: FlagSet): Boolean = ( @@ -1518,6 +1519,11 @@ object Parsers { } } + /** Always add the syntactic `mod`, but check and conditionally add semantic `mod.flags` + */ + def addMod(mods: Modifiers, mod: Mod): Modifiers = + addFlag(mods, mod.flags).withAddedMod(mod) + /** AccessQualifier ::= "[" (Id | this) "]" */ def accessQualifierOpt(mods: Modifiers): Modifiers = @@ -1614,8 +1620,8 @@ object Parsers { mods = atPos(start, in.offset) { if (in.token == TYPE) { - in.nextToken() - mods | Param | ParamAccessor + val mod = atPos(in.skipToken()) { Mod.Type() } + (mods | Param | ParamAccessor).withAddedMod(mod) } else { if (mods.hasFlags) syntaxError("`type' expected") mods | Param | PrivateLocal @@ -1659,7 +1665,7 @@ object Parsers { * Param ::= id `:' ParamType [`=' Expr] */ def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = { - var implicitFlag = EmptyFlags + var implicitMod: Mod = null var firstClauseOfCaseClass = ofCaseClass var implicitOffset = -1 // use once def param(): ValDef = { @@ -1670,11 +1676,11 @@ object Parsers { mods = atPos(start, in.offset) { if (in.token == VAL) { - in.nextToken() - mods + val mod = atPos(in.skipToken()) { Mod.Val() } + mods.withAddedMod(mod) } else if (in.token == VAR) { - in.nextToken() - addFlag(mods, Mutable) + val mod = atPos(in.skipToken()) { Mod.Var() } + addMod(mods, mod) } else { if (!(mods.flags &~ (ParamAccessor | Inline)).isEmpty) syntaxError("`val' or `var' expected") @@ -1696,7 +1702,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 (!implicitFlag.isEmpty) + else if (implicitMod != null) syntaxError("implicit parameters may not be call-by-name") } paramType() @@ -1708,15 +1714,16 @@ object Parsers { mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset))) implicitOffset = -1 } - ValDef(name, tpt, default).withMods(addFlag(mods, implicitFlag)) + if (implicitMod != null) mods = addMod(mods, implicitMod) + ValDef(name, tpt, default).withMods(mods) } } def paramClause(): List[ValDef] = inParens { if (in.token == RPAREN) Nil else { if (in.token == IMPLICIT) { - implicitOffset = in.skipToken() - implicitFlag = Implicit + implicitOffset = in.offset + implicitMod = atPos(in.skipToken()) { Mod.Implicit(Implicit) } } commaSeparated(param) } @@ -1726,7 +1733,7 @@ object Parsers { if (in.token == LPAREN) paramClause() :: { firstClauseOfCaseClass = false - if (implicitFlag.isEmpty) clauses() else Nil + if (implicitMod == null) clauses() else Nil } else Nil } @@ -1819,9 +1826,13 @@ object Parsers { */ def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match { case VAL => - patDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) + val mod = atPos(in.skipToken()) { Mod.Val() } + val mods1 = mods.withAddedMod(mod) + patDefOrDcl(start, mods1, in.getDocComment(start)) case VAR => - patDefOrDcl(start, posMods(start, addFlag(mods, Mutable)), in.getDocComment(start)) + val mod = atPos(in.skipToken()) { Mod.Var() } + val mod1 = addMod(mods, mod) + patDefOrDcl(start, mod1, in.getDocComment(start)) case DEF => defDefOrDcl(start, posMods(start, mods), in.getDocComment(start)) case TYPE => @@ -2184,8 +2195,11 @@ object Parsers { stats.toList } - def localDef(start: Int, implicitFlag: FlagSet): Tree = - defOrDcl(start, addFlag(defAnnotsMods(localModifierTokens), implicitFlag)) + def localDef(start: Int, implicitFlag: FlagSet, implicitMod: Option[Mod] = None): Tree = { + var mods = addFlag(defAnnotsMods(localModifierTokens), implicitFlag) + if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get) + defOrDcl(start, mods) + } /** BlockStatSeq ::= { BlockStat semi } [ResultExpr] * BlockStat ::= Import @@ -2205,9 +2219,10 @@ object Parsers { stats += expr(Location.InBlock) else if (isDefIntro(localModifierTokens)) if (in.token == IMPLICIT) { - val start = in.skipToken() - if (isIdent) stats += implicitClosure(start, Location.InBlock) - else stats += localDef(start, ImplicitCommon) + val start = in.offset + val mod = atPos(in.skipToken()) { Mod.Implicit(ImplicitCommon) } + if (isIdent) stats += implicitClosure(start, Location.InBlock, Some(mod)) + else stats += localDef(start, ImplicitCommon, Some(mod)) } else { stats += localDef(in.offset, EmptyFlags) } |