Skip to content

Commit af43b61

Browse files
committed
add tests for modifiers
1 parent efec81f commit af43b61

File tree

2 files changed

+182
-10
lines changed

2 files changed

+182
-10
lines changed

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

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,8 +1097,9 @@ object Parsers {
10971097
/** Expr ::= implicit Id `=>' Expr
10981098
* BlockResult ::= implicit Id [`:' InfixType] `=>' Block
10991099
*/
1100-
def implicitClosure(start: Int, location: Location.Value): Tree = {
1101-
val mods = atPos(start) { Modifiers(Implicit) }
1100+
def implicitClosure(start: Int, location: Location.Value, implicitMod: Option[Mod] = None): Tree = {
1101+
var mods = atPos(start) { Modifiers(Implicit) }
1102+
if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get)
11021103
val id = termIdent()
11031104
val paramExpr =
11041105
if (location == Location.InBlock && in.token == COLON)
@@ -1674,6 +1675,7 @@ object Parsers {
16741675
*/
16751676
def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = {
16761677
var implicitFlag = EmptyFlags
1678+
var implicitMod: Mod = null
16771679
var firstClauseOfCaseClass = ofCaseClass
16781680
var implicitOffset = -1 // use once
16791681
def param(): ValDef = {
@@ -1722,14 +1724,16 @@ object Parsers {
17221724
mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset)))
17231725
implicitOffset = -1
17241726
}
1727+
if (implicitMod != null) mods = mods.withAddedMod(implicitMod)
17251728
ValDef(name, tpt, default).withMods(addFlag(mods, implicitFlag))
17261729
}
17271730
}
17281731
def paramClause(): List[ValDef] = inParens {
17291732
if (in.token == RPAREN) Nil
17301733
else {
17311734
if (in.token == IMPLICIT) {
1732-
implicitOffset = in.skipToken()
1735+
implicitOffset = in.offset
1736+
implicitMod = atPos(in.offset) { in.nextToken(); Mod.Implicit() }
17331737
implicitFlag = Implicit
17341738
}
17351739
commaSeparated(param)
@@ -1833,9 +1837,13 @@ object Parsers {
18331837
*/
18341838
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
18351839
case VAL =>
1836-
patDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
1840+
val mod = atPos(in.offset) { in.nextToken(); Mod.Val() }
1841+
val modPos = atPos(start) { mods.withAddedMod(mod) }
1842+
patDefOrDcl(start, modPos, in.getDocComment(start))
18371843
case VAR =>
1838-
patDefOrDcl(start, posMods(start, addFlag(mods, Mutable)), in.getDocComment(start))
1844+
val mod = atPos(in.offset) { in.nextToken(); Mod.Var() }
1845+
val modPos = atPos(start) { addFlag(mods, Mutable).withAddedMod(mod) }
1846+
patDefOrDcl(start, modPos, in.getDocComment(start))
18391847
case DEF =>
18401848
defDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
18411849
case TYPE =>
@@ -2198,8 +2206,11 @@ object Parsers {
21982206
stats.toList
21992207
}
22002208

2201-
def localDef(start: Int, implicitFlag: FlagSet): Tree =
2202-
defOrDcl(start, addFlag(defAnnotsMods(localModifierTokens), implicitFlag))
2209+
def localDef(start: Int, implicitFlag: FlagSet, implicitMod: Option[Mod] = None): Tree = {
2210+
var mods = addFlag(defAnnotsMods(localModifierTokens), implicitFlag)
2211+
if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get)
2212+
defOrDcl(start, mods)
2213+
}
22032214

22042215
/** BlockStatSeq ::= { BlockStat semi } [ResultExpr]
22052216
* BlockStat ::= Import
@@ -2219,9 +2230,10 @@ object Parsers {
22192230
stats += expr(Location.InBlock)
22202231
else if (isDefIntro(localModifierTokens))
22212232
if (in.token == IMPLICIT) {
2222-
val start = in.skipToken()
2223-
if (isIdent) stats += implicitClosure(start, Location.InBlock)
2224-
else stats += localDef(start, ImplicitCommon)
2233+
val start = in.offset
2234+
val mod = atPos(in.offset) { in.nextToken(); Mod.Implicit() }
2235+
if (isIdent) stats += implicitClosure(start, Location.InBlock, Some(mod))
2236+
else stats += localDef(start, ImplicitCommon, Some(mod))
22252237
} else {
22262238
stats += localDef(in.offset, EmptyFlags)
22272239
}

test/test/ModifiersParsingTest.scala

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package test
2+
3+
import org.junit.Test
4+
import org.junit.Assert._
5+
6+
import dotty.tools.dotc.ast.untpd.modsDeco
7+
import dotty.tools.dotc.ast.untpd._
8+
import dotty.tools.dotc.ast.{ Trees => d }
9+
import dotty.tools.dotc.parsing.Parsers.Parser
10+
import dotty.tools.dotc.util.SourceFile
11+
import dotty.tools.dotc.core.Contexts.ContextBase
12+
13+
object ModifiersParsingTest {
14+
implicit val ctx = (new ContextBase).initialCtx
15+
16+
implicit def parse(code: String): Tree = {
17+
val (_, stats) = new Parser(new SourceFile("<meta>", code.toCharArray)).templateStatSeq()
18+
stats match { case List(stat) => stat; case stats => Thicket(stats) }
19+
}
20+
21+
implicit class TreeDeco(val code: Tree) extends AnyVal {
22+
def firstConstrValDef: ValDef = code match {
23+
case d.TypeDef(_, d.Template(constr, _, _, _)) =>
24+
constr.vparamss.head.head
25+
}
26+
27+
def firstTypeParam: TypeDef = code match {
28+
case d.TypeDef(_, d.Template(constr, _, _, _)) =>
29+
constr.tparams.head
30+
}
31+
32+
def defParam(i: Int): ValDef = code match {
33+
case d.DefDef(_, _, vparamss, _, _) =>
34+
vparamss.head.toArray.apply(i)
35+
}
36+
37+
def defParam(i: Int, j: Int): ValDef = code match {
38+
case d.DefDef(_, _, vparamss, _, _) =>
39+
vparamss.toArray.apply(i).toArray.apply(j)
40+
}
41+
42+
def funParam(i: Int): Tree = code match {
43+
case Function(params, _) =>
44+
params.toArray.apply(i)
45+
}
46+
47+
def field(i: Int): Tree = code match {
48+
case d.TypeDef(_, t: Template) =>
49+
t.body.toArray.apply(i)
50+
}
51+
52+
def field(name: String): Tree = code match {
53+
case d.TypeDef(_, t: Template) =>
54+
t.body.find({
55+
case m: MemberDef => m.name.show == name
56+
case _ => false
57+
}).get
58+
}
59+
60+
def stat(i: Int): Tree = code match {
61+
case d.Block(stats, expr) =>
62+
if (i < stats.length) stats.toArray.apply(i)
63+
else expr
64+
}
65+
66+
def modifiers: List[Mod] = code match {
67+
case t: MemberDef => t.mods.mods
68+
}
69+
}
70+
}
71+
72+
73+
class ModifiersParsingTest {
74+
import ModifiersParsingTest._
75+
76+
77+
@Test def valDef = {
78+
var source: Tree = "class A(var a: Int)"
79+
assert(source.firstConstrValDef.modifiers == List(Mod.Var()))
80+
81+
source = "class A(val a: Int)"
82+
assert(source.firstConstrValDef.modifiers == List(Mod.Val()))
83+
84+
source = "class A(private val a: Int)"
85+
assert(source.firstConstrValDef.modifiers == List(Mod.Private(), Mod.Val()))
86+
87+
source = "class A(protected var a: Int)"
88+
assert(source.firstConstrValDef.modifiers == List(Mod.Protected(), Mod.Var()))
89+
90+
source = "class A(protected implicit val a: Int)"
91+
assert(source.firstConstrValDef.modifiers == List(Mod.Protected(), Mod.Implicit(), Mod.Val()))
92+
93+
source = "class A[T]"
94+
assert(source.firstTypeParam.modifiers == List())
95+
96+
source = "class A[type T]"
97+
assert(source.firstTypeParam.modifiers == List(Mod.Type()))
98+
}
99+
100+
@Test def typeDef = {
101+
var source: Tree = "class A"
102+
assert(source.modifiers == List())
103+
104+
source = "sealed class A"
105+
assert(source.modifiers == List(Mod.Sealed()))
106+
107+
source = "implicit class A"
108+
assert(source.modifiers == List(Mod.Implicit()))
109+
110+
source = "abstract sealed class A"
111+
assert(source.modifiers == List(Mod.Abstract(), Mod.Sealed()))
112+
}
113+
114+
@Test def fieldDef = {
115+
val source: Tree =
116+
"""
117+
| class A {
118+
| lazy var a = ???
119+
| lazy private val b = ???
120+
| final val c = ???
121+
|
122+
| abstract override def f: Boolean
123+
| inline def g(n: Int) = ???
124+
| }
125+
""".stripMargin
126+
127+
assert(source.field("a").modifiers == List(Mod.Lazy(), Mod.Var()))
128+
assert(source.field("b").modifiers == List(Mod.Lazy(), Mod.Private(), Mod.Val()))
129+
assert(source.field("c").modifiers == List(Mod.Final(), Mod.Val()))
130+
assert(source.field("f").modifiers == List(Mod.Abstract(), Mod.Override()))
131+
assert(source.field("g").modifiers == List(Mod.Inline()))
132+
}
133+
134+
@Test def paramDef = {
135+
var source: Tree = "def f(inline a: Int) = ???"
136+
assert(source.defParam(0).modifiers == List(Mod.Inline()))
137+
138+
source = "def f(implicit a: Int, b: Int) = ???"
139+
assert(source.defParam(0).modifiers == List(Mod.Implicit()))
140+
assert(source.defParam(1).modifiers == List(Mod.Implicit()))
141+
142+
source = "def f(x: Int, y: Int)(implicit a: Int, b: Int) = ???"
143+
assert(source.defParam(0, 0).modifiers == List())
144+
assert(source.defParam(1, 0).modifiers == List(Mod.Implicit()))
145+
}
146+
147+
@Test def blockDef = {
148+
var source: Tree = "implicit val x : A = ???"
149+
assert(source.modifiers == List(Mod.Implicit(), Mod.Val()))
150+
151+
source = "implicit var x : A = ???"
152+
assert(source.modifiers == List(Mod.Implicit(), Mod.Var()))
153+
154+
source = "{ implicit var x : A = ??? }"
155+
assert(source.stat(0).modifiers == List(Mod.Implicit(), Mod.Var()))
156+
157+
source = "{ implicit x => x * x }"
158+
assert(source.stat(0).funParam(0).modifiers == List(Mod.Implicit()))
159+
}
160+
}

0 commit comments

Comments
 (0)