@@ -20,7 +20,6 @@ import scala.tools.nsc.typechecker.{StructuredTypeStrings, TypeStrings}
2020import scala .tools .nsc .util ._
2121import ScalaClassLoader .URLClassLoader
2222import scala .tools .nsc .util .Exceptional .unwrap
23- import javax .script .{AbstractScriptEngine , Bindings , Compilable , CompiledScript , ScriptContext , ScriptEngine , ScriptEngineFactory , ScriptException }
2423import java .net .URL
2524import scala .tools .util .PathResolver
2625
@@ -56,10 +55,11 @@ import scala.tools.util.PathResolver
5655 * @author Moez A. Abdel-Gawad
5756 * @author Lex Spoon
5857 */
59- class IMain (@ BeanProperty val factory : ScriptEngineFactory , initialSettings : Settings , protected val out : JPrintWriter ) extends AbstractScriptEngine with Compilable with Imports with PresentationCompilation {
58+ class IMain (initialSettings : Settings , protected val out : JPrintWriter ) extends Imports with PresentationCompilation {
6059 imain =>
6160
62- setBindings(createBindings, ScriptContext .ENGINE_SCOPE )
61+ def this (initialSettings : Settings ) = this (initialSettings, IMain .defaultOut)
62+
6363 object replOutput extends ReplOutput (settings.Yreploutdir ) { }
6464
6565 @ deprecated(" Use replOutput.dir instead" , " 2.11.0" )
@@ -104,13 +104,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
104104 finally if (! saved) settings.nowarn.value = false
105105 }
106106
107- /** construct an interpreter that reports to Console */
108- def this (settings : Settings , out : JPrintWriter ) = this (null , settings, out)
109- def this (factory : ScriptEngineFactory , settings : Settings ) = this (factory, settings, new NewLinePrintWriter (new ConsoleWriter , true ))
110- def this (settings : Settings ) = this (settings, new NewLinePrintWriter (new ConsoleWriter , true ))
111- def this (factory : ScriptEngineFactory ) = this (factory, new Settings ())
112- def this () = this (new Settings ())
113-
114107 // the expanded prompt but without color escapes and without leading newline, for purposes of indenting
115108 lazy val formatting = Formatting .forPrompt(replProps.promptText)
116109 lazy val reporter : ReplReporter = new ReplReporter (this )
@@ -464,7 +457,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
464457 pos
465458 }
466459
467- private [interpreter] def requestFromLine (line : String , synthetic : Boolean ): Either [IR .Result , Request ] = {
460+ private [interpreter] def requestFromLine (line : String , synthetic : Boolean = false ): Either [IR .Result , Request ] = {
468461 val content = line
469462
470463 val trees : List [global.Tree ] = parse(content) match {
@@ -559,77 +552,8 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
559552 */
560553 def interpret (line : String ): IR .Result = interpret(line, synthetic = false )
561554 def interpretSynthetic (line : String ): IR .Result = interpret(line, synthetic = true )
562- def interpret (line : String , synthetic : Boolean ): IR .Result = compile(line, synthetic) match {
563- case Left (result) => result
564- case Right (req) => new WrappedRequest (req).loadAndRunReq
565- }
566-
567- private def compile (line : String , synthetic : Boolean ): Either [IR .Result , Request ] = {
568- if (global == null ) Left (IR .Error )
569- else requestFromLine(line, synthetic) match {
570- case Left (result) => Left (result)
571- case Right (req) =>
572- // null indicates a disallowed statement type; otherwise compile and
573- // fail if false (implying e.g. a type error)
574- if (req == null || ! req.compile) Left (IR .Error ) else Right (req)
575- }
576- }
577-
578- var code = " "
579- var bound = false
580- def compiled (script : String ): CompiledScript = {
581- if (! bound) {
582- quietBind(" engine" -> this .asInstanceOf [ScriptEngine ])
583- bound = true
584- }
585- val cat = code + script
586- compile(cat, false ) match {
587- case Left (result) => result match {
588- case IR .Incomplete => {
589- code = cat + " \n "
590- new CompiledScript {
591- def eval (context : ScriptContext ): Object = null
592- def getEngine : ScriptEngine = IMain .this
593- }
594- }
595- case _ => {
596- code = " "
597- throw new ScriptException (" compile-time error" )
598- }
599- }
600- case Right (req) => {
601- code = " "
602- new WrappedRequest (req)
603- }
604- }
605- }
606-
607- private class WrappedRequest (val req : Request ) extends CompiledScript {
608- var recorded = false
609-
610- /** In Java we would have to wrap any checked exception in the declared
611- * ScriptException. Runtime exceptions and errors would be ok and would
612- * not need to be caught. So let us do the same in Scala : catch and
613- * wrap any checked exception, and let runtime exceptions and errors
614- * escape. We could have wrapped runtime exceptions just like other
615- * exceptions in ScriptException, this is a choice.
616- */
617- @ throws[ScriptException ]
618- def eval (context : ScriptContext ): Object = {
619- val result = req.lineRep.evalEither match {
620- case Left (e : RuntimeException ) => throw e
621- case Left (e : Exception ) => throw new ScriptException (e)
622- case Left (e) => throw e
623- case Right (result) => result.asInstanceOf [Object ]
624- }
625- if (! recorded) {
626- recordRequest(req)
627- recorded = true
628- }
629- result
630- }
631-
632- def loadAndRunReq = classLoader.asContext {
555+ def interpret (line : String , synthetic : Boolean ): IR .Result = {
556+ def loadAndRunReq (req : Request ) = classLoader.asContext {
633557 val (result, succeeded) = req.loadAndRun
634558
635559 /** To our displeasure, ConsoleReporter offers only printMessage,
@@ -654,35 +578,55 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
654578 }
655579 }
656580
657- def getEngine : ScriptEngine = IMain .this
581+ compile(line, synthetic) match {
582+ case Left (result) => result
583+ case Right (req) => loadAndRunReq(req)
584+ }
585+ }
586+
587+ // create a Request and compile it
588+ private [interpreter] def compile (line : String , synthetic : Boolean ): Either [IR .Result , Request ] = {
589+ if (global == null ) Left (IR .Error )
590+ else requestFromLine(line, synthetic) match {
591+ case Right (null ) => Left (IR .Error ) // disallowed statement type
592+ case Right (req) if ! req.compile => Left (IR .Error ) // compile error
593+ case ok @ Right (req) => ok
594+ case err @ Left (result) => err
595+ }
658596 }
659597
660598 /** Bind a specified name to a specified value. The name may
661599 * later be used by expressions passed to interpret.
662600 *
601+ * A fresh `ReadEvalPrint`, which defines a `line` package, is used to compile
602+ * a custom `eval` object that wraps the bound value.
603+ *
604+ * If the bound value is successfully installed, then bind the name
605+ * by interpreting `val name = $line42.$eval.value`.
606+ *
663607 * @param name the variable name to bind
664608 * @param boundType the type of the variable, as a string
665609 * @param value the object value to bind to it
666610 * @return an indication of whether the binding succeeded
667611 */
668612 def bind (name : String , boundType : String , value : Any , modifiers : List [String ] = Nil ): IR .Result = {
669613 val bindRep = new ReadEvalPrint ()
670- bindRep.compile("""
671- |object %s {
672- | var value: %s = _
673- | def set(x: Any) = value = x.asInstanceOf[%s ]
614+ bindRep.compile(s """
615+ |object ${bindRep.evalName} {
616+ | var value: $boundType = _
617+ | def set(x: Any) = value = x.asInstanceOf[ $boundType ]
674618 |}
675- """ .stripMargin.format(bindRep.evalName, boundType, boundType)
676- )
619+ """ .stripMargin
620+ )
677621 bindRep.callEither(" set" , value) match {
678622 case Left (ex) =>
679623 repldbg(" Set failed in bind(%s, %s, %s)" .format(name, boundType, value))
680624 repldbg(util.stackTraceString(ex))
681625 IR .Error
682-
683626 case Right (_) =>
684- val line = " %sval %s = %s.value" .format(modifiers map (_ + " " ) mkString, name, bindRep.evalPath)
685- repldbg(" Interpreting: " + line)
627+ val mods = if (modifiers.isEmpty) " " else modifiers.mkString(" " , " " , " " )
628+ val line = s " ${mods}val $name = ${ bindRep.evalPath }.value "
629+ repldbg(s " Interpreting: $line" )
686630 interpret(line)
687631 }
688632 }
@@ -1046,31 +990,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
1046990 override def toString = " Request(line=%s, %s trees)" .format(line, trees.size)
1047991 }
1048992
1049- def createBindings : Bindings = new IBindings {
1050- override def put (name : String , value : Object ): Object = {
1051- val n = name.indexOf(" :" )
1052- val p : NamedParam = if (n < 0 ) (name, value) else {
1053- val nme = name.substring(0 , n).trim
1054- val tpe = name.substring(n + 1 ).trim
1055- NamedParamClass (nme, tpe, value)
1056- }
1057- if (! p.name.startsWith(" javax.script" )) bind(p)
1058- null
1059- }
1060- }
1061-
1062- @ throws[ScriptException ]
1063- def compile (script : String ): CompiledScript = eval(" new javax.script.CompiledScript { def eval(context: javax.script.ScriptContext): Object = { " + script + " }.asInstanceOf[Object]; def getEngine: javax.script.ScriptEngine = engine }" ).asInstanceOf [CompiledScript ]
1064-
1065- @ throws[ScriptException ]
1066- def compile (reader : java.io.Reader ): CompiledScript = compile(stringFromReader(reader))
1067-
1068- @ throws[ScriptException ]
1069- def eval (script : String , context : ScriptContext ): Object = compiled(script).eval(context)
1070-
1071- @ throws[ScriptException ]
1072- def eval (reader : java.io.Reader , context : ScriptContext ): Object = eval(stringFromReader(reader), context)
1073-
1074993 override def finalize = close
1075994
1076995 /** Returns the name of the most recent interpreter result.
@@ -1267,54 +1186,9 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
12671186
12681187/** Utility methods for the Interpreter. */
12691188object IMain {
1270- import java .util .Arrays .{ asList => asJavaList }
12711189 /** Dummy identifier fragement inserted at the cursor before presentation compilation. Needed to support completion of `global.def<TAB>` */
12721190 val DummyCursorFragment = " _CURSOR_"
12731191
1274- class Factory extends ScriptEngineFactory {
1275- @ BeanProperty
1276- val engineName = " Scala Interpreter"
1277-
1278- @ BeanProperty
1279- val engineVersion = " 1.0"
1280-
1281- @ BeanProperty
1282- val extensions : JList [String ] = asJavaList(" scala" )
1283-
1284- @ BeanProperty
1285- val languageName = " Scala"
1286-
1287- @ BeanProperty
1288- val languageVersion = scala.util.Properties .versionString
1289-
1290- def getMethodCallSyntax (obj : String , m : String , args : String * ): String = null
1291-
1292- @ BeanProperty
1293- val mimeTypes : JList [String ] = asJavaList(" application/x-scala" )
1294-
1295- @ BeanProperty
1296- val names : JList [String ] = asJavaList(" scala" )
1297-
1298- def getOutputStatement (toDisplay : String ): String = null
1299-
1300- def getParameter (key : String ): Object = key match {
1301- case ScriptEngine .ENGINE => engineName
1302- case ScriptEngine .ENGINE_VERSION => engineVersion
1303- case ScriptEngine .LANGUAGE => languageName
1304- case ScriptEngine .LANGUAGE_VERSION => languageVersion
1305- case ScriptEngine .NAME => names.get(0 )
1306- case _ => null
1307- }
1308-
1309- def getProgram (statements : String * ): String = null
1310-
1311- def getScriptEngine : ScriptEngine = {
1312- val settings = new Settings ()
1313- settings.usemanifestcp.value = true
1314- new IMain (this , settings)
1315- }
1316- }
1317-
13181192 // The two name forms this is catching are the two sides of this assignment:
13191193 //
13201194 // $line3.$read.$iw.$iw.Bippy =
@@ -1366,5 +1240,10 @@ object IMain {
13661240
13671241 def stripImpl (str : String ): String = naming.unmangle(str)
13681242 }
1243+ private [interpreter] def defaultSettings = new Settings ()
1244+ private [scala] def defaultOut = new NewLinePrintWriter (new ConsoleWriter , true )
1245+
1246+ /** construct an interpreter that reports to Console */
1247+ def apply (initialSettings : Settings = defaultSettings, out : JPrintWriter = defaultOut) = new IMain (initialSettings, out)
13691248}
13701249
0 commit comments