Increment repl line generation on compilation error

fixes #KT-17921 and #KT-21141
Tests added to the JSR223 local eval example
This commit is contained in:
Ilya Chernikov
2017-12-22 12:57:36 +01:00
parent 2d8e73f3f6
commit 953a485fe7
3 changed files with 61 additions and 10 deletions
@@ -53,6 +53,7 @@ open class BasicReplStageHistory<T>(override val lock: ReentrantReadWriteLock =
lock.write {
val removed = map { it.id }
clear()
currentGeneration.incrementAndGet()
return removed
}
}
@@ -67,7 +68,10 @@ open class BasicReplStageHistory<T>(override val lock: ReentrantReadWriteLock =
currentGeneration.incrementAndGet()
removed
}
else emptyList()
else {
currentGeneration.incrementAndGet()
emptyList()
}
}
}
}
@@ -35,7 +35,15 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler,
val aggregatedState = state.asState(AggregatedReplStageState::class.java)
val compiled = compiler.compile(state, codeLine)
when (compiled) {
is ReplCompileResult.Error -> ReplEvalResult.Error.CompileTime(compiled.message, compiled.location)
is ReplCompileResult.Error -> {
aggregatedState.apply {
lock.write {
assert(state1.history.size == state2.history.size)
adjustHistories() // needed due to statefulness of AnalyzerEngine - in case of compilation errors the line name reuse leads to #KT-17921
}
}
ReplEvalResult.Error.CompileTime(compiled.message, compiled.location)
}
is ReplCompileResult.Incomplete -> ReplEvalResult.Incomplete()
is ReplCompileResult.CompiledClasses -> {
val result = eval(state, compiled, scriptArgs, invokeWrapper)
@@ -46,14 +54,7 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler,
aggregatedState.apply {
lock.write {
if (state1.history.size > state2.history.size) {
if (state2.history.size == 0) {
state1.history.reset()
}
else {
state2.history.peek()?.let {
state1.history.resetTo(it.id)
}
}
adjustHistories()
assert(state1.history.size == state2.history.size)
}
}
@@ -91,3 +92,9 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler,
evaluator.eval(state, compiledCode, scriptArgs ?: defaultScriptArgs, invokeWrapper)
}
}
private fun AggregatedReplStageState<*, *>.adjustHistories(): Iterable<ILineId>? =
state2.history.peek()?.let {
state1.history.resetTo(it.id)
}
?: state1.history.reset()
@@ -72,6 +72,46 @@ class KotlinJsr223LocalScriptEngineIT {
Assert.assertEquals(5, res2)
}
@Test
fun testEvalWithError() {
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
try {
engine.eval("java.lang.fish")
Assert.fail("Script error expected")
}
catch (e: ScriptException) {}
val res1 = engine.eval("val x = 3")
Assert.assertNull(res1)
try {
engine.eval("y")
Assert.fail("Script error expected")
}
catch (e: ScriptException) {
Assert.assertTrue("Expected message to contain \"unresolved reference: y\", actual: \"${e.message}\"",
e.message?.contains("unresolved reference: y") ?: false)
}
val res3 = engine.eval("x + 2")
Assert.assertEquals(5, res3)
}
@Test
fun testEngineRepeatWithReset() {
val code = "open class A {}\n" +
"class B : A() {}"
val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine
val res1 = engine.eval(code)
Assert.assertNull(res1)
engine.state.history.reset()
engine.eval(code)
}
@Test
fun testInvocable() {
val engine = ScriptEngineManager().getEngineByExtension("kts")!!