Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSR 223 Scala ScriptContext does not support setWriter #8422

Closed
scabug opened this issue Mar 17, 2014 · 10 comments
Closed

JSR 223 Scala ScriptContext does not support setWriter #8422

scabug opened this issue Mar 17, 2014 · 10 comments

Comments

@scabug
Copy link

scabug commented Mar 17, 2014

This code should print first the stars and after that the number three. However, it seems that setting the context does not have any effect.

{code} val w = new StringWriter()

val engine = new ScriptEngineManager().getEngineByName("scala")
val c = new SimpleScriptContext()
c.setWriter(w)
engine.setContext(c)

engine.eval("println(3)")

println("***")
println(w.toString()){code}

@scabug
Copy link
Author

scabug commented Mar 17, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8422?orig=1
Reporter: Teemu Sirkiä (ttsirkia)
Affected Versions: 2.11.0-M8, 2.11.5, 2.11.6

@scabug
Copy link
Author

scabug commented Mar 8, 2015

Margaret Leber (MaggieL) said (edited on Mar 8, 2015 11:23:02 PM UTC):
I just bumped into this myself...and it's crippling my project.

Is it possibly a result of scala/scala@6c48941 ?
(No, that didn't land until 2.11.6)

@scabug
Copy link
Author

scabug commented Mar 15, 2015

Margaret Leber (MaggieL) said:
Just to show it's not just setWriter that's borked; setAttribute doesn't work either. #7916 asserts get/setBndings is toast too :

in sbt console

import javax.script._
val engine = new ScriptEngineManager().getEngineByName("scala")
val iMain = engine.asInstanceOf[scala.tools.nsc.interpreter.IMain]
// now we play settings/classpath games so this works in sbt console
class MyClass
iMain.settings.embeddedDefaults[MyClass]
iMain.settings.usemanifestcp.value = true
def getPath(className: String) = java.lang.Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath()
def compilerClass = "scala.tools.nsc.Interpreter"
def langClass = "scala.Some"
val compilerPath = s"${getPath(compilerClass)};${getPath(langClass)}"
iMain.settings.bootclasspath.append(compilerPath)
iMain.settings.classpath.append(compilerPath)
// OK, game on:
val c = new SimpleScriptContext()
c.setAttribute("foo", new Integer(5), ScriptContext.ENGINE_SCOPE)
c.setAttribute("foo", new Integer(6), ScriptContext.GLOBAL_SCOPE)
import java.io.StringWriter
val w = new StringWriter()
c.setWriter(w)
engine.setContext(c)
engine.eval("println(foo)")
w

gets

<console>:8: error: not found: value foo
              println(foo)
                      ^
javax.script.ScriptException: compile-time error
  at scala.tools.nsc.interpreter.IMain.compiled(IMain.scala:591)
  at scala.tools.nsc.interpreter.IMain.eval(IMain.scala:1047)
  at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
  ... 43 elided

@scabug
Copy link
Author

scabug commented Sep 8, 2015

@SethTisue said:
[~MaggieL] Scala's JSR 223 support is "minimal"; it came in as a community contribution. further improvements submitted by the community would be very welcome, but it's "out of scope for the Scala team". quotes are from #874. I've put the "community" tag on this and #7916. if there's somewhere in the documentation or the Scala website that you think inappropriately oversells our level of support for JSR 223, please point them out and I'll make sure the wording gets changed.

@scabug
Copy link
Author

scabug commented Sep 8, 2015

Margaret Leber (MaggieL) said:
I may have misunderstood http://docs.scala-lang.org/scala/2.11/ when it and the 2.11 release notes showed "JSR-223 Scripting Engine support" as a feature in 2014, thinking that the "out of scope" comment from 2011 no longer obtained. Not knowing the players or being familiar with the processes in the project, I didn't twig that @rjolly (whose PR it was) isn't part of "the Scala team".

I spent a lot of time going though gyrations trying to get the classpath right in our sbt-based Play app so we could actually get a Scala ScriptEngine started in the Java library we were calling from Scala, only to find that once I did, it wasn't possible to read or write variables into the script environment from Java.

This was a huge disappointment. Certainly javax.script.ScriptEngine says "ScriptEngine is the fundamental interface whose methods must be fully functional in every implementation of this specification."; there's no notion there of a "minimal support" level, so when it doesn't work, it's just a bug. I haven't researched deeply into back releases of 2.11 (we were on 2.8 until I led an effort to get us to 2.11 that was substantially motivated by wanting to use JSR-223) but based on the example in the "Overview" it looks to me like this part of it actually worked at some time in the past.

@scabug
Copy link
Author

scabug commented Sep 9, 2015

@SethTisue said:
I looked into this a bit. scala.Console is a singleton, so overriding the behavior of println only in code running in a particular IMain instance would not be straightforward — especially in the presence of multiple threads.

the following workaround bypasses the official JSR 223 API but may be useful, regardless:

scala> import javax.script._
import javax.script._

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

scala> val baos = new java.io.ByteArrayOutputStream
baos: java.io.ByteArrayOutputStream =

scala> val ps = new java.io.PrintStream(baos)
ps: java.io.PrintStream = java.io.PrintStream@36224f93

scala> Console.withOut(ps)(e.eval("List(1,2,3).foreach(println)"))
res1: Object = null

scala> baos.toString
res2: String =
"1
2
3
"

@scabug
Copy link
Author

scabug commented Sep 9, 2015

@SethTisue said:
As for the claim in the 2.11 overview, unfortunately I don't have access to a time machine, but I agree it would have been better if the original notes had included this change: scala/scala#4733

@scabug
Copy link
Author

scabug commented Sep 9, 2015

Margaret Leber (MaggieL) said:
Sorry, I've been busy babysitting grandkids this evening and an commenting from my tablet. But frankly, in the current state of the code, given the stated interface contract of ScriptEngine and its explicit injunction that all implementations must implement all methods, I think it's a mistake to claim any JSR-223 support at all. Which is a shame.

@scabug
Copy link
Author

scabug commented Oct 19, 2015

@som-snytt said:
JSR 223 is vague on various points, but what it says is: "Implementations whose scripting languages have well-defined constructs to display character output, must use the Writer returned by the getWriter method for this purpose."

So a snippet that uses println can have an appropriate method injected or imported. (Similarly print and printf.) That avoids Console.out.

It's too bad the Predef.read methods are deprecated because they would serve the same purpose.

Otherwise, the solution is for the script engine to Console.withOut etc before evaluation. That also takes care of invoking components that use Console.

@scabug
Copy link
Author

scabug commented Feb 2, 2016

@som-snytt said:
This uses Console.withOut.

scala/scala#4819

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants