Skip to content

Commit 2d012a3

Browse files
authored
Visibility Modifiers (#1094)
This PR reorganizes parsing of modifiers on declaraionts, which are now grouped in `Info`. It also adds one new modifier `private`, which is parsed, but then ignored.
1 parent 28925ce commit 2d012a3

File tree

8 files changed

+424
-294
lines changed

8 files changed

+424
-294
lines changed

effekt/jvm/src/main/scala/effekt/Repl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
315315
val fullSpan = Span(source, 0, source.content.length, origin = Origin.Synthesized)
316316
ModuleDecl("interactive", includes,
317317
definitions :+ FunDef(IdDef("main", fakeSpan), Many.empty(fakeSpan), Many.empty(fakeSpan), Many.empty(fakeSpan), Maybe.None(fakeSpan),
318-
body, None, fullSpan), None, fullSpan)
318+
body, Info.empty(fakeSpan), fullSpan), None, fullSpan)
319319
}
320320

321321
def makeEval(source: Source, expr: Term): ModuleDecl = {

effekt/jvm/src/test/scala/effekt/LSPTests.scala

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ class LSPTests extends FunSuite {
4848
def withClientAndServer(testBlock: (MockLanguageClient, Server) => Unit): Unit = {
4949
withClientAndServer(true)(testBlock)
5050
}
51-
51+
5252
/** Normalize the output of the IR by replacing the generated identifiers and stripping all whitespace
5353
*/
5454
def normalizeIRString(ir: String): String = {
5555
ir.replaceAll("_\\d+", "_whatever")
5656
.replaceAll("\\s+", "")
5757
}
58-
58+
5959
def assertIREquals(ir: String, expected: String): Unit = {
6060
val normalizedIR = normalizeIRString(ir)
6161
val normalizedExpected = normalizeIRString(expected)
@@ -1222,7 +1222,18 @@ class LSPTests extends FunSuite {
12221222
| ),
12231223
| Span(StringSource(def main() = <>, file://test.effekt), 13, 15, Real())
12241224
| ),
1225-
| None(),
1225+
| Info(
1226+
| None(),
1227+
| Maybe(
1228+
| None(),
1229+
| Span(StringSource(def main() = <>, file://test.effekt), 0, 0, Real())
1230+
| ),
1231+
| Maybe(
1232+
| None(),
1233+
| Span(StringSource(def main() = <>, file://test.effekt), 0, 0, Real())
1234+
| ),
1235+
| None()
1236+
| ),
12261237
| Span(StringSource(def main() = <>, file://test.effekt), 0, 15, Real())
12271238
| )
12281239
| ),
@@ -1410,7 +1421,7 @@ class LSPTests extends FunSuite {
14101421
assertEquals(receivedHoles.head.holes.length, 1)
14111422
}
14121423
}
1413-
1424+
14141425
test("Server publishes hole id for nested defs") {
14151426
withClientAndServer { (client, server) =>
14161427
val source =

effekt/jvm/src/test/scala/effekt/ParserTests.scala

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class ParserTests extends munit.FunSuite {
144144
def parseExternDef(input: String, positions: Positions = new Positions())(using munit.Location): Def =
145145
parse(input, _.externDef())
146146

147+
def parseInfo(input: String, positions: Positions = new Positions())(using munit.Location): Info =
148+
parse(input, _.info(parseCaptures = true))
149+
147150
// Custom asserts
148151
//
149152
//
@@ -997,7 +1000,8 @@ class ParserTests extends munit.FunSuite {
9971000
IdDef("foo", Span(source, pos(0), pos(1))),
9981001
None,
9991002
Var(IdRef(Nil, "f", Span(source, pos(2), pos(3))), Span(source, pos(2), pos(3))),
1000-
None, Span(source, 0, pos.last)))
1003+
Info.empty(Span(source, 0, 0)),
1004+
Span(source, 0, pos.last)))
10011005
}
10021006

10031007
parseDefinition(
@@ -1079,6 +1083,17 @@ class ParserTests extends munit.FunSuite {
10791083
assertEquals(funDef.ret.span, Span(source, pos(1), pos(1)))
10801084
}
10811085

1086+
test("Function definition with comment") {
1087+
val (source, pos) =
1088+
raw"""/// Calculate the answer to the ultimate question of life, the universe, and everything
1089+
|def calculate() = 42
1090+
|""".sourceAndPositions
1091+
1092+
val definition = parseDefinition(source.content)
1093+
1094+
assertEquals(definition.doc, Some(" Calculate the answer to the ultimate question of life, the universe, and everything"))
1095+
}
1096+
10821097
test("Function definition with whitespaces instead of return type") {
10831098
val (source, pos) =
10841099
raw"""def foo{b: => Unit / bar} = <>
@@ -1132,6 +1147,62 @@ class ParserTests extends munit.FunSuite {
11321147
assertEquals(valDef.span, span)
11331148
}
11341149

1150+
test("Declaration info with capture set") {
1151+
val (source, pos) =
1152+
raw"""/// Some doc comment
1153+
|private extern {a, b, c}
1154+
|↑ ↑↑ ↑↑ ↑
1155+
|""".sourceAndPositions
1156+
1157+
parseInfo(source.content) match {
1158+
case Info(
1159+
Some(doc),
1160+
isPrivate,
1161+
isExtern,
1162+
Some(CaptureSet(captures, Span(_, captFrom, captTo, _)))) =>
1163+
1164+
assertEquals(doc, " Some doc comment")
1165+
assertEquals(isPrivate, Maybe(Some(()), Span(source, pos(0), pos(1))))
1166+
assertEquals(isExtern, Maybe(Some(()), Span(source, pos(2), pos(3))))
1167+
assertEquals(captures.map(_.name), List("a", "b", "c"))
1168+
assertEquals(captFrom, pos(4))
1169+
assertEquals(captTo, pos(5))
1170+
1171+
case info => fail(s"Wrong info: ${info}")
1172+
}
1173+
}
1174+
1175+
test("Only private") {
1176+
val (source, pos) =
1177+
raw"""/// Some doc comment
1178+
|private
1179+
|↑ ↑
1180+
|""".sourceAndPositions
1181+
1182+
parseInfo(source.content) match {
1183+
case Info(doc, isPrivate, isExtern, externCapture) =>
1184+
1185+
assertEquals(doc, Some(" Some doc comment"))
1186+
assertEquals(isPrivate, Maybe(Some(()), Span(source, pos(0), pos(1))))
1187+
assertEquals(isExtern, Maybe(None, Span(source, pos(1), pos(1))))
1188+
assertEquals(externCapture, None)
1189+
}
1190+
}
1191+
1192+
test("Only doc comment") {
1193+
val (source, pos) =
1194+
raw"""/// Some doc comment
1195+
| ↑
1196+
|""".sourceAndPositions
1197+
1198+
parseInfo(source.content) match {
1199+
case Info(doc, isPrivate, isExtern, externCapture) =>
1200+
assertEquals(doc, Some(" Some doc comment"))
1201+
assertEquals(isPrivate, Maybe(None, Span(source, pos(0), pos(0))))
1202+
assertEquals(isExtern, Maybe(None, Span(source, pos(0), pos(0))))
1203+
assertEquals(externCapture, None)
1204+
}
1205+
}
11351206

11361207
test("Region definition parses with correct span") {
11371208
val (source, span) =

effekt/shared/src/main/scala/effekt/Intelligence.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ trait Intelligence {
125125
p.productElementNames.zip(p.productIterator)
126126
.collectFirst {
127127
case ("doc", Some(s: String)) => s
128+
case ("info", source.Info(Some(s: String), _, _, _)) => s
128129
}
129130
case _ => None
130131
}

effekt/shared/src/main/scala/effekt/Lexer.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,7 @@ enum TokenKind {
130130
case `fun`
131131
case `match`
132132
case `def`
133-
case `module`
134-
case `import`
135-
case `export`
136133
case `extern`
137-
case `include`
138134
case `record`
139135
case `box`
140136
case `unbox`
@@ -146,6 +142,12 @@ enum TokenKind {
146142
case `is`
147143
case `namespace`
148144
case `pure`
145+
146+
case `module`
147+
case `import`
148+
case `export`
149+
case `include`
150+
case `private`
149151
}
150152

151153
object TokenKind {
@@ -178,7 +180,7 @@ object TokenKind {
178180
`let`, `true`, `false`, `val`, `var`, `if`, `else`, `while`, `type`, `effect`, `interface`,
179181
`try`, `with`, `case`, `do`, `fun`, `match`, `def`, `module`, `import`, `export`, `extern`,
180182
`include`, `record`, `box`, `unbox`, `return`, `region`, `resource`, `new`, `and`, `is`,
181-
`namespace`, `pure`
183+
`namespace`, `pure`, `private`
182184
)
183185

184186
val keywordMap: immutable.HashMap[String, TokenKind] =

0 commit comments

Comments
 (0)