Skip to content

Commit f85c153

Browse files
committed
Flatten top level block in REPL
This makes multi-line editing more convenient
1 parent 63bdce5 commit f85c153

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

compiler/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,36 @@ class ReplCompiler extends Compiler {
7575

7676
implicit val ctx: Context = state.context
7777

78+
// If trees is of the form `{ def1; def2; def3 }` then `List(def1, def2, def3)`
79+
val flattened = trees match {
80+
case List(Block(stats, expr)) =>
81+
if (expr eq EmptyTree) stats // happens when expr is not an expression
82+
else stats :+ expr
83+
case _ =>
84+
trees
85+
}
86+
7887
var valIdx = state.valIndex
88+
val defs = new mutable.ListBuffer[Tree]
7989

80-
val defs = trees.flatMap {
90+
flattened.foreach {
8191
case expr @ Assign(id: Ident, _) =>
8292
// special case simple reassignment (e.g. x = 3)
8393
// in order to print the new value in the REPL
8494
val assignName = (id.name ++ str.REPL_ASSIGN_SUFFIX).toTermName
8595
val assign = ValDef(assignName, TypeTree(), id).withPos(expr.pos)
86-
List(expr, assign)
96+
defs += expr += assign
8797
case expr if expr.isTerm =>
8898
val resName = (str.REPL_RES_PREFIX + valIdx).toTermName
8999
valIdx += 1
90100
val vd = ValDef(resName, TypeTree(), expr).withPos(expr.pos)
91-
vd :: Nil
101+
defs += vd
92102
case other =>
93-
other :: Nil
103+
defs += other
94104
}
95105

96106
Definitions(
97-
defs,
107+
defs.toList,
98108
state.copy(
99109
objectIndex = state.objectIndex + (if (defs.isEmpty) 0 else 1),
100110
valIndex = valIdx

compiler/test/dotty/tools/repl/ReplCompilerTests.scala

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import org.junit.{Ignore, Test}
77

88
class ReplCompilerTests extends ReplTest {
99

10+
private def lines() = storedOutput().split(EOL).toList
11+
1012
@Test def compileSingle = fromInitialState { implicit state =>
1113
run("def foo: 1 = 1")
1214
assertEquals("def foo: Int(1)", storedOutput().trim)
@@ -53,7 +55,7 @@ class ReplCompilerTests extends ReplTest {
5355
"val res1: Int = 20"
5456
)
5557

56-
assertEquals(expected, storedOutput().split(EOL).toList)
58+
assertEquals(expected, lines())
5759
}
5860

5961
@Test def testImportMutable =
@@ -124,6 +126,32 @@ class ReplCompilerTests extends ReplTest {
124126
)
125127

126128
run(source)
127-
assertEquals(expected, storedOutput().split(EOL).toList)
129+
assertEquals(expected, lines())
128130
}
131+
132+
@Test def topLevelBlock =
133+
fromInitialState { implicit state =>
134+
val source =
135+
"""{
136+
| def foo = 1
137+
| case class A(x: Int)
138+
| foo
139+
| def bar = 2
140+
|}""".stripMargin
141+
142+
val expected = List(
143+
"// defined case class A",
144+
"def foo: Int",
145+
"def bar: Int",
146+
"val res0: Int = 1"
147+
)
148+
149+
val ns = run(source)
150+
assertEquals(expected, lines())
151+
ns
152+
}
153+
.andThen { implicit state =>
154+
run("val a = A(foo + bar)")
155+
assertEquals("val a: A = A(3)", storedOutput().trim)
156+
}
129157
}

0 commit comments

Comments
 (0)