aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2016-10-25 15:42:31 +0200
committerGitHub <noreply@github.com>2016-10-25 15:42:31 +0200
commit40da850dfb5218131d0a8a0cdfd87bbe54569832 (patch)
tree96c65f2b0997e5bd1c4c951ca62b62d35cce335d /src
parent133fbb352b5acafb9e1ea5ab53e8678dca03afd9 (diff)
parent24a725db99786eaf5f37903429bfefcf8db12aaf (diff)
downloaddotty-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.scala50
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala89
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)
}