I mentioned the REPL because the first thing ScriptEngine does is create an instance of ReplDriver. I haven’t seen scala.tools.nsc.interpreter.shell.Scripted before. Documentation is somewhat succinct (not a single line of it for the entire class). Anyway, that’s Scala 2, right? I’m in Scala 3.
And there is some stuff named setContext and setBindings that might be useful for what you are trying to achieve? (I have no idea what they do but their name sounds promissing…)
Yes, I meant to apply up to the string, not to println.
My impression is that contexts and bindings let me add names that refer to existing values, but what I need is to load code from outside the REPL, which means using a suitable class loader.
I’m also interested in this. I managed to once for Scala 2.11 integrate with the REPL but I have no idea on how to do it for Scala 3…
This was how I did it after trial and error in Scala 2.11 (be ware of hacky old code), and I had to fiddle with settings so that the Java class path was used etc: Init and logic
I started to try to find out ho to use the new ReplDriver in Scala 3 but never found a way to use the same class path as the invoking app and do the bindings you want. Here is my abandoned trial: main and other stuff but I have forgotten now what made me give up. I guess I was not able to tell from the code without doc-comments how to use it.
I assume we want this for the same purpose, i.e., for teaching. I face scenarios where I don’t want to give students a function signature, but I still want to be able to compile a test suite if they messed it up.
Yes I wanted this for teaching, but with another goal: to provide a REPL with a DSL already invoked and a simple swing GUI that can integrate with the custom repl state.
I think it would be really useful with a simple api for those who just want to use the REPL for:
binding stuff in the surronding environment
run code from a String
get the result back with ability to cast it to known types in the surronding environment that created the repl instance
get a customized jline-based loop similar to the actual scala repl
Currently, given the code here, I finally managed to setup my own ReplDriver but I found the api difficult to grasp with a lot of imports etc that i did not understand.
I actually just got this hack to build and run like this (with a big fat assembly will all the compiler dependencies - I have published the fat jar here under assets called reqt4.jar ):
$ java -jar reqt4.jar
*** Hello reqt4 ***
Welcome to Scala 3.1.1-RC1 (17.0.4, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
reqt4> val s1 = reqt.replDriver.run("val x = 42")(using reqt.replDriver.exposeMyState.get)
val x: Int = 42
reqt4> s1 == reqt.replDriver.exposeMyState.get
val res0: Boolean = true
reqt4> val s2 = reqt.replDriver.run("x")(using reqt.replDriver.exposeMyState.get)
val res0: Int = 42
Unfortunately this did not work:
reqt4> x
-- [E006] Not Found Error: -----------------------------------------------------
1 |x
|^
|Not found: x
reqt4> val y = 42
val y: Int = 42
reqt4> val s3 = reqt.replDriver.run("y")(using reqt.replDriver.exposeMyState.get)
-- [E006] Not Found Error: -----------------------------------------------------
1 |y
|^
|Not found: y
So I guess we need a new kind of ReplDriver with mutable state… But I dont know yet how to make the meta-circular session above work…
The state shouldn’t be an issue: You feed a state to run, which returns an updated state, to feed to the next call to run. It’s incorporating code defined elsewhere that is the challenge.
Well, as you see above, the code in my Main is accessible inside the repl that my Main runs… For instance the reqt.replDriver itself is accessible inside the running repl instance… If that is what you mean?
But if you evaluate the string "val y = 42" it should be added to the same state and it should work. Definitions outside of eval go to a different state.
You can see my hacked ReplDriver here with the exposed state hack, but I didn’t get it to work with new definitions of the same running session outside the run method, so my exposed state is somehow not really updated and I don’t get why (but I’m starting to get tired and need to eat very soon )