@@ -34,6 +34,7 @@ import javax.script.*
3434import scala .collection .mutable
3535import scala .jdk .CollectionConverters .*
3636import scala .util .Try
37+ import scala .util .control .NonFatal
3738import scala .util .matching .Regex
3839
3940/**
@@ -67,12 +68,12 @@ class ScalaAdaptedScriptEngine(engine: ScriptEngine) extends AbstractScriptEngin
6768
6869 // Scala 3.2.2 ignores bindings, emulate binding using setup script
6970 // Create a line with variable declaration for each binding item
70- val lines =
71+ val transfers : mutable. Seq [ Seq [ String ]] =
7172 for
7273 scope <- context.getScopes.asScala
7374 bindings <- Option (context.getBindings(scope)).map(_.asScala) // bindings in context can be null
7475 yield {
75- for (name, value) <- bindings yield {
76+ for (name, value) <- bindings.toSeq yield {
7677 if isValidVariableName(name) then
7778 val validName = addBackticksIfNeeded(name)
7879 value match
@@ -85,12 +86,22 @@ class ScalaAdaptedScriptEngine(engine: ScriptEngine) extends AbstractScriptEngin
8586 case v : Byte => s " val $validName : Byte = $v"
8687 case v : Boolean => s " val $validName : Int = $v"
8788 case v : AnyRef =>
88- _transfer = v
89- val typeName = Option (v).map(_.getClass.getCanonicalName).getOrElse(" AnyRef" )
89+ val transferIndex = BindingSupport .nextTransferIndex
90+ BindingSupport .__transfer(transferIndex) = v
91+ val typeName = Option (v)
92+ .map { oo =>
93+ val tt : Array [_] = oo.getClass.getTypeParameters
94+ tt.foreach(t => log(s " ${oo.getClass.getCanonicalName} TYPE PARAM: ${t.getClass.getName}" ))
95+ val p = tt.map(_ => " _" ).mkString(" [" , " ," , " ]" )
96+ val n = oo.getClass.getCanonicalName
97+ if tt.nonEmpty then n + p else n
98+ }
99+ .getOrElse(" AnyRef" )
90100 val validTypeName = addBackticksIfNeeded(typeName)
91101 s """
92102 |val $validName : $validTypeName = {
93- | val t = org.scijava.plugins.scripting.scala.ScalaAdaptedScriptEngine._transfer
103+ | val t = org.scijava.plugins.scripting.scala.ScalaAdaptedScriptEngine.BindingSupport
104+ | ._transfer( $transferIndex)
94105 | t.asInstanceOf[ $validTypeName]
95106 |} """ .stripMargin
96107 case v : Unit =>
@@ -100,26 +111,45 @@ class ScalaAdaptedScriptEngine(engine: ScriptEngine) extends AbstractScriptEngin
100111 }
101112 }
102113
103- val script = lines
114+ val script = transfers
104115 .flatten
105116 .filter(_.nonEmpty)
106117 .mkString(" \n " )
107118
108- if script.nonEmpty then
109- evalInner(script, context)
119+ evalInner(script, context)
110120
111121 end emulateBinding
112122
113- private def evalInner (script : String , context : ScriptContext ) =
114- class WriterOutputStream (w : Writer ) extends OutputStream :
115- override def write (b : Int ): Unit = w.write(b)
123+ private def evalInner (script : String , context : ScriptContext ): AnyRef =
124+ log(
125+ s """
126+ |LOG[evalInner] script
127+ |BEGIN
128+ |---------------------------
129+ | $script
130+ |---------------------------
131+ |END
132+ | """ .stripMargin
133+ )
134+ if script.trim.isEmpty then
135+ log(" LOG[evalInner] script is empty, skipping evaluation" )
136+ null
137+ else
138+ class WriterOutputStream (w : Writer ) extends OutputStream :
139+ override def write (b : Int ): Unit = w.write(b)
116140
117- // Redirect output to writes provided by context
118- Console .withOut(WriterOutputStream (context.getWriter)) {
119- Console .withErr(WriterOutputStream (context.getErrorWriter)) {
120- engine.eval(script, context)
121- }
122- }
141+ try
142+ // Redirect output to writes provided by context
143+ Console .withOut(WriterOutputStream (context.getWriter)) {
144+ Console .withErr(WriterOutputStream (context.getErrorWriter)) {
145+ engine.eval(script, context)
146+ }
147+ }
148+ catch
149+ case NonFatal (t) =>
150+ log(s " LOG[evalInner] in eval: $t" )
151+ t.printStackTrace()
152+ throw t
123153
124154 private def stringFromReader (in : Reader ) =
125155 val out = new StringWriter ()
@@ -156,9 +186,15 @@ class ScalaAdaptedScriptEngine(engine: ScriptEngine) extends AbstractScriptEngin
156186 value
157187 end get
158188
189+ private def log (msg : String ): Unit = {
190+ if ScalaAdaptedScriptEngine .DEBUG then
191+ Console .out.println(msg)
192+ }
193+
159194end ScalaAdaptedScriptEngine
160195
161196object ScalaAdaptedScriptEngine :
197+ private val DEBUG : Boolean = false
162198 private lazy val variableNamePattern = """ ^[a-zA-Z_$][a-zA-Z_$0-9]*$""" .r
163199 private val scala3Keywords = Seq (
164200 " abstract" ,
@@ -204,10 +240,6 @@ object ScalaAdaptedScriptEngine:
204240 " yield"
205241 )
206242
207- /** Do not use externally despite it is declared public. IT is public so it is accessible from scripts */
208- // noinspection ScalaWeakerAccess
209- var _transfer : Object = _
210-
211243 private def isValidVariableName (name : String ): Boolean = variableNamePattern.matches(name)
212244
213245 private [scala] def addBackticksIfNeeded (referenceName : String ): String =
@@ -216,4 +248,32 @@ object ScalaAdaptedScriptEngine:
216248 .map(n => if scala3Keywords.contains(n) then s " ` $n` " else n)
217249 .mkString(" ." )
218250
251+ /**
252+ * Temporary support for implementing binding in the script engine.
253+ * It has limited capacity and does not free memory.
254+ * Access to storage is public, so it is visible from scripts.
255+ */
256+ // noinspection ScalaWeakerAccess
257+ object BindingSupport :
258+ private val MaxTransfers : Int = 1024 * 1024
259+
260+ /**
261+ * Do not use externally despite it is declared public.
262+ * It is public so it is accessible from scripts that are used to emulate variable binding
263+ */
264+ // noinspection ScalaWeakerAccess,ScalaUnusedSymbol
265+ def _transfer : Seq [AnyRef ] = __transfer.toSeq
266+
267+ private [scala] val __transfer : mutable.ListBuffer [AnyRef ] = mutable.ListBuffer .empty[AnyRef ]
268+
269+ private var lastTransferIndex = - 1
270+
271+ private [scala] def nextTransferIndex : Int =
272+ if lastTransferIndex + 1 >= MaxTransfers then
273+ throw new IllegalStateException (" ScalaAdaptedScriptEngine: maximum transfer limit reached" )
274+
275+ lastTransferIndex += 1
276+ __transfer.append(null )
277+ lastTransferIndex
278+
219279end ScalaAdaptedScriptEngine
0 commit comments