summaryrefslogtreecommitdiff
path: root/src/repl
diff options
context:
space:
mode:
authorRaphael Jolly <rjolly@users.sourceforge.net>2013-03-09 22:02:02 +0100
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-03-11 22:36:17 -0700
commit3a30af154e62f5b8a569486b09788c42db2103a6 (patch)
tree4f43fbca95a1f9d59e7307826497b36039328006 /src/repl
parent3e8f8ddb2ac057ad82e1a7e37f59baff1c0e15ac (diff)
downloadscala-3a30af154e62f5b8a569486b09788c42db2103a6.tar.gz
scala-3a30af154e62f5b8a569486b09788c42db2103a6.tar.bz2
scala-3a30af154e62f5b8a569486b09788c42db2103a6.zip
SI-874 actual JSR-223 implementation
Diffstat (limited to 'src/repl')
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala174
1 files changed, 149 insertions, 25 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index cb2e3c32b8..c92777c13e 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -19,6 +19,11 @@ import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings }
import ScalaClassLoader.URLClassLoader
import scala.tools.nsc.util.Exceptional.unwrap
import scala.collection.{ mutable, immutable }
+import scala.reflect.BeanProperty
+import scala.util.Properties.versionString
+import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, SimpleBindings, CompiledScript, Compilable}
+import java.io.{ StringWriter, Reader }
+import java.util.Arrays
import IMain._
import java.util.concurrent.Future
import scala.reflect.runtime.{ universe => ru }
@@ -57,7 +62,7 @@ import StdReplTags._
* @author Moez A. Abdel-Gawad
* @author Lex Spoon
*/
-class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends Imports {
+class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Settings, protected val out: JPrintWriter) extends AbstractScriptEngine(new SimpleBindings) with Compilable with Imports {
imain =>
object replOutput extends ReplOutput(settings.Yreploutdir) { }
@@ -100,7 +105,10 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
}
/** construct an interpreter that reports to Console */
+ def this(settings: Settings, out: JPrintWriter) = this(null, settings, out)
+ def this(factory: ScriptEngineFactory, settings: Settings) = this(factory, settings, new NewLinePrintWriter(new ConsoleWriter, true))
def this(settings: Settings) = this(settings, new NewLinePrintWriter(new ConsoleWriter, true))
+ def this(factory: ScriptEngineFactory) = this(factory, new Settings())
def this() = this(new Settings())
lazy val formatting: Formatting = new Formatting {
@@ -146,19 +154,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
}
def isInitializeComplete = _initializeComplete
- /** the public, go through the future compiler */
lazy val global: Global = {
- if (isInitializeComplete) _compiler
- else {
- // If init hasn't been called yet you're on your own.
- if (_isInitialized == null) {
- repldbg("Warning: compiler accessed before init set up. Assuming no postInit code.")
- initialize(())
- }
- // blocks until it is ; false means catastrophic failure
- if (_isInitialized.get()) _compiler
- else null
- }
+ if (!isInitializeComplete) _initialize()
+ _compiler
}
import global._
@@ -535,9 +533,82 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
*/
def interpret(line: String): IR.Result = interpret(line, synthetic = false)
def interpretSynthetic(line: String): IR.Result = interpret(line, synthetic = true)
- def interpret(line: String, synthetic: Boolean): IR.Result = {
- def loadAndRunReq(req: Request) = {
- classLoader.setAsContext()
+ def interpret(line: String, synthetic: Boolean): IR.Result = compile(line, synthetic) match {
+ case Left(result) => result
+ case Right(req) => new WrappedRequest(req).loadAndRunReq
+ }
+
+ private def compile(line: String, synthetic: Boolean): Either[IR.Result, Request] = {
+ if (global == null) Left(IR.Error)
+ else requestFromLine(line, synthetic) match {
+ case Left(result) => Left(result)
+ case Right(req) =>
+ // null indicates a disallowed statement type; otherwise compile and
+ // fail if false (implying e.g. a type error)
+ if (req == null || !req.compile) Left(IR.Error) else Right(req)
+ }
+ }
+
+ var code = ""
+ var bound = false
+ @throws(classOf[ScriptException])
+ def compile(script: String): CompiledScript = {
+ if (!bound) {
+ quietBind("bindings", getBindings(ScriptContext.ENGINE_SCOPE))
+ bound = true
+ }
+ val cat = code + script
+ compile(cat, false) match {
+ case Left(result) => result match {
+ case IR.Incomplete => {
+ code = cat + "\n"
+ new CompiledScript {
+ def eval(context: ScriptContext): Object = null
+ def getEngine: ScriptEngine = IMain.this
+ }
+ }
+ case _ => {
+ code = ""
+ throw new ScriptException("compile-time error")
+ }
+ }
+ case Right(req) => {
+ code = ""
+ new WrappedRequest(req)
+ }
+ }
+ }
+
+ @throws(classOf[ScriptException])
+ def compile(reader: Reader): CompiledScript = {
+ val writer = new StringWriter()
+ var c = reader.read()
+ while(c != -1) {
+ writer.write(c)
+ c = reader.read()
+ }
+ reader.close()
+ compile(writer.toString())
+ }
+
+ private class WrappedRequest(val req: Request) extends CompiledScript {
+ var recorded = false
+
+ @throws(classOf[ScriptException])
+ def eval(context: ScriptContext): Object = {
+ val result = req.lineRep.evalEither match {
+ case Left(e: Exception) => throw new ScriptException(e)
+ case Left(_) => throw new ScriptException("run-time error")
+ case Right(result) => result.asInstanceOf[Object]
+ }
+ if (!recorded) {
+ recordRequest(req)
+ recorded = true
+ }
+ result
+ }
+
+ def loadAndRunReq = classLoader.asContext {
val (result, succeeded) = req.loadAndRun
/** To our displeasure, ConsoleReporter offers only printMessage,
@@ -562,15 +633,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
}
}
- if (global == null) IR.Error
- else requestFromLine(line, synthetic) match {
- case Left(result) => result
- case Right(req) =>
- // null indicates a disallowed statement type; otherwise compile and
- // fail if false (implying e.g. a type error)
- if (req == null || !req.compile) IR.Error
- else loadAndRunReq(req)
- }
+ def getEngine: ScriptEngine = IMain.this
}
/** Bind a specified name to a specified value. The name may
@@ -703,6 +766,14 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
lazy val evalClass = load(evalPath)
+ def evalEither = callEither(resultName) match {
+ case Left(ex) => ex match {
+ case ex: NullPointerException => Right(null)
+ case ex => Left(unwrap(ex))
+ }
+ case Right(result) => Right(result)
+ }
+
def compile(source: String): Boolean = compileAndSaveRun("<console>", source)
/** The innermost object inside the wrapper, found by
@@ -738,6 +809,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
mostRecentWarnings = warnings
}
private def evalMethod(name: String) = evalClass.getMethods filter (_.getName == name) match {
+ case Array() => null
case Array(method) => method
case xs => sys.error("Internal error: eval object " + evalClass + ", " + xs.mkString("\n", "\n", ""))
}
@@ -897,6 +969,16 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
override def toString = "Request(line=%s, %s trees)".format(line, trees.size)
}
+ def createBindings: Bindings = new SimpleBindings
+
+ @throws(classOf[ScriptException])
+ def eval(script: String, context: ScriptContext): Object = compile(script).eval(context)
+
+ @throws(classOf[ScriptException])
+ def eval(reader: Reader, context: ScriptContext): Object = compile(reader).eval(context)
+
+ override def finalize = close
+
/** Returns the name of the most recent interpreter result.
* Mostly this exists so you can conveniently invoke methods on
* the previous result.
@@ -1068,6 +1150,48 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
/** Utility methods for the Interpreter. */
object IMain {
+ class Factory extends ScriptEngineFactory {
+ @BeanProperty
+ val engineName = "Scala Interpreter"
+
+ @BeanProperty
+ val engineVersion = "1.0"
+
+ @BeanProperty
+ val extensions: JList[String] = Arrays.asList("scala")
+
+ @BeanProperty
+ val languageName = "Scala"
+
+ @BeanProperty
+ val languageVersion = versionString
+
+ def getMethodCallSyntax(obj: String, m: String, args: String*): String = null
+
+ @BeanProperty
+ val mimeTypes: JList[String] = Arrays.asList("application/x-scala")
+
+ @BeanProperty
+ val names: JList[String] = Arrays.asList("scala")
+
+ def getOutputStatement(toDisplay: String): String = null
+
+ def getParameter(key: String): Object = key match {
+ case ScriptEngine.ENGINE => engineName
+ case ScriptEngine.ENGINE_VERSION => engineVersion
+ case ScriptEngine.LANGUAGE => languageName
+ case ScriptEngine.LANGUAGE_VERSION => languageVersion
+ case ScriptEngine.NAME => names.get(0)
+ case _ => null
+ }
+
+ def getProgram(statements: String*): String = null
+
+ def getScriptEngine: ScriptEngine = new IMain(this, new Settings() {
+ usemanifestcp.value = true
+ })
+ }
+
// The two name forms this is catching are the two sides of this assignment:
//
// $line3.$read.$iw.$iw.Bippy =