Make the Scala interpreter invisible between interpretation calls

Is it possible to configure the Scala interpreter ( tools.nsc.IMain ) to โ€œforgetโ€ the previously executed code whenever I run the next interpret() call?

Usually, when it compiles sources, it transfers them to nested objects, so all previously defined variables, functions, and bindings are available.

It would be enough to generate nested objects (or throw them away), although I would prefer a solution that still removes the previously compiled classes from the class loader.

Is there a parameter or method, or something that I can overwrite, or an alternative to IMain that will do this? I need to have access to the resulting objects / classes from the host virtual machine.


Basically, I want to isolate subsequent interpret() calls without something more weight than creating a new IMain for each iteration.

+4
source share
1 answer

Here is one possible answer. Basically, there is a reset() method that calls the following things (mostly private, so either you buy the whole package or not):

 clearExecutionWrapper() resetClassLoader() resetAllCreators() prevRequests.clear() referencedNameMap.clear() definedNameMap.clear() virtualDirectory.clear() 

In my case, I use a custom runtime wrapper, so it needs to be tuned again, and the import is processed through a regular interpretation loop, so either add them again, or it is best to add them using the execution wrapper.

I would like to keep the bindings, they also disappeared:

 import tools.nsc._ import interpreter.IMain object Test { private final class Intp(cset: nsc.Settings) extends IMain(cset, new NewLinePrintWriter(new ConsoleWriter, autoFlush = true)) { override protected def parentClassLoader = Test.getClass.getClassLoader } object Foo { def bar() { println("BAR" )} } def run() { val cset = new nsc.Settings() cset.classpath.value += java.io.File.pathSeparator + sys.props("java.class.path") val i = new Intp(cset) i.initializeSynchronous() i.bind[Foo.type]("foo", Foo) val res0 = i.interpret("foo.bar(); val x = 33") println(s"res0: $res0") i.reset() val res1 = i.interpret("println(x)") println(s"res1: $res1") i.reset() val res2 = i.interpret("foo.bar()") println(s"res2: $res2") } } 

This will find Foo in the first iteration, correctly forget x in the second iteration, but then in the third iteration you can see that the Foo binding is also lost:

 foo: Test.Foo.type = Test$Foo$@8bf223 BAR x: Int = 33 res0: Success <console>:8: error: not found: value x println(x) ^ res1: Error <console>:8: error: not found: value foo foo.bar() ^ res2: Error 

Everything seems to be in order:

 for(j <- 0 until 3) { val user = "foo.bar()" val synth = """import Test.{Foo => foo} """.stripMargin + user val res = i.interpret(synth) println(s"res$j: $res") i.reset() } 
+2
source

Source: https://habr.com/ru/post/1481370/


All Articles