How to use JSR-223 to get Scala interpreter in sbt console?
Asked Answered
G

1

5

In the sbt console, sbt version 0.13.5, Scala version 2.11.1, I can get javax.script.ScriptEngine for Scala:

scala> val engine = new javax.script.ScriptEngineManager().getEngineByName("scala")
engine: javax.script.ScriptEngine = scala.tools.nsc.interpreter.IMain@bf78a9

However, I can't use it:

scala> engine.eval("3")
[init] error: error while loading Object, Missing dependency 'object scala in compiler mirror', required by /usr/lib/jvm/java-7-openjdk-i386/jre/lib/rt.jar(java/lang/Object.class)

Failed to initialize compiler: object scala in compiler mirror not found.
** Note that as of 2.8 scala does not assume use of the java classpath.
** For the old behavior pass -usejavacp to scala, or if using a Settings
** object programatically, settings.usejavacp.value = true.
scala.reflect.internal.MissingRequirementError: object scala in compiler mirror not found.
  at ...

According to the SBT FAQ, I am supposed to do some magic with a Settings, and then pass it into my Interpreter's constructor. However, I'm not directly creating an Interpreter (and it's not even clear if I'm indirectly creating it, as the engine object is an IMain).

Is there some way for the Scala ScriptEngine to work on the SBT console?

Goody answered 30/5, 2014 at 18:23 Comment(0)
C
5

You can cast your engine to scala.tools.nsc.interpreter.IMain, which will give you an access to the settings. Then you can use embeddedDefaults to set a classpath as it was mentioned in the FAQ. Just do it before call to the eval method.

val engine = new javax.script.ScriptEngineManager().getEngineByName("scala")
val settings = engine.asInstanceOf[scala.tools.nsc.interpreter.IMain].settings
// MyScalaClass is just any class in your project
settings.embeddedDefaults[MyScalaClass]

Given that you should be able to run eval, e.g.

scala> engine.eval("10")
res3: Object = 10

The reason is more or less explained in the gist linked from the FAQ. Basically, when creating an interpreter using getEngineByName("scala"), the java.class.path is used and it contains only sbt-launch.jar. Using the trick with embeddedDefaults sets the class path to the correct value (you can check the settings before and after a call to the embeddedDefaults).

Carolinian answered 22/6, 2014 at 13:21 Comment(1)
For completeness, sbt -Dscala.usejavacp=true console makes getEngine fail. I think the change for jsr223 made classpath tweaks that deserve review. Thx for the gist link, I hadn't seen the history.Mountaineer

© 2022 - 2024 — McMap. All rights reserved.