Skip to content

Commit 4553978

Browse files
committed
Embryonic but functioning JSR223 support
1 parent fb0e3bc commit 4553978

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dotty.tools.repl.ScriptEngine$Factory

compiler/src/dotty/tools/repl/Rendering.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {
2626
private[this] var myClassLoader: ClassLoader = _
2727

2828
/** Class loader used to load compiled code */
29-
private[this] def classLoader()(implicit ctx: Context) =
29+
private[repl] def classLoader()(implicit ctx: Context) =
3030
if (myClassLoader != null) myClassLoader
3131
else {
3232
val parent = parentClassLoader.getOrElse {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package dotty.tools
2+
package repl
3+
4+
import java.io.Reader
5+
import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine => JScriptEngine, ScriptEngineFactory, ScriptException, SimpleBindings}
6+
import dotc.core.StdNames.str
7+
8+
/** A JSR 223 (Scripting API) compatible wrapper around the REPL for improved
9+
* interoperability with software that supports it.
10+
*
11+
* It works by instantiating a new script engine through the script engine manager.
12+
* The script engine provides a eval method to evaluate scripts in string form.
13+
* Example use:
14+
*
15+
* val m = new javax.script.ScriptEngineManager()
16+
* val e = m.getEngineByName("scala")
17+
* println(e.eval("42"))
18+
*/
19+
class ScriptEngine extends AbstractScriptEngine {
20+
private[this] val driver = new ReplDriver(Array("-usejavacp", "-color:never"), Console.out, None)
21+
private[this] val rendering = new Rendering
22+
private[this] var state: State = driver.initialState
23+
24+
def getFactory: ScriptEngineFactory = new ScriptEngine.Factory
25+
26+
def createBindings: Bindings = new SimpleBindings
27+
28+
/* Evaluate with the given context. */
29+
@throws[ScriptException]
30+
def eval(script: String, context: ScriptContext): Object = {
31+
val vid = state.valIndex
32+
state = driver.run(script)(state)
33+
val oid = state.objectIndex
34+
Class.forName(s"${str.REPL_SESSION_LINE}$oid", true, rendering.classLoader()(state.context))
35+
.getDeclaredMethods.find(_.getName == s"${str.REPL_RES_PREFIX}$vid")
36+
.map(_.invoke(null))
37+
.getOrElse(null)
38+
}
39+
40+
@throws[ScriptException]
41+
def eval(reader: Reader, context: ScriptContext): Object = throw new UnsupportedOperationException
42+
}
43+
44+
object ScriptEngine {
45+
import java.util.Arrays
46+
import scala.util.Properties
47+
48+
class Factory extends ScriptEngineFactory {
49+
def getEngineName = "Scala REPL"
50+
def getEngineVersion = "3.0"
51+
def getExtensions = Arrays.asList("scala")
52+
def getLanguageName = "Scala"
53+
def getLanguageVersion = Properties.versionString
54+
def getMimeTypes = Arrays.asList("application/x-scala")
55+
def getNames = Arrays.asList("scala")
56+
57+
def getMethodCallSyntax(obj: String, m: String, args: String*) = s"$obj.$m(${args.mkString(", ")})"
58+
59+
def getOutputStatement(toDisplay: String) = s"""print("$toDisplay")"""
60+
61+
def getParameter(key: String): Object = key match {
62+
case JScriptEngine.ENGINE => getEngineName
63+
case JScriptEngine.ENGINE_VERSION => getEngineVersion
64+
case JScriptEngine.LANGUAGE => getLanguageName
65+
case JScriptEngine.LANGUAGE_VERSION => getLanguageVersion
66+
case JScriptEngine.NAME => getNames.get(0)
67+
case _ => null
68+
}
69+
70+
def getProgram(statements: String*) = statements.mkString("; ")
71+
72+
def getScriptEngine: JScriptEngine = new ScriptEngine
73+
}
74+
}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
val res0: Int = 42
2+
3+
42
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
val m = new javax.script.ScriptEngineManager(getClass().getClassLoader())
4+
val e = m.getEngineByName("scala")
5+
println(e.eval("42"))
6+
}
7+
}
8+

0 commit comments

Comments
 (0)