-
Notifications
You must be signed in to change notification settings - Fork 3
Update Scala to version 3 #7
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
Merged
Merged
Changes from 11 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
a02abef
Update pom-scijava to 34.0.0
jpsacha a8f2de0
Bump Scala 2.12 to latest in 2.12 line
jpsacha 01b5db4
More tests: add `testLocals()`
jpsacha 58103e3
More tests: add `testParameters()`
jpsacha 4878b18
More tests: add `testImportsRetained()` based on test in scripting-gr…
jpsacha 55147d9
Add contributor for modified files
jpsacha 1c41bc4
Upgrade Scala 2.12 to 2.13
jpsacha ad59910
Add main class for running ScriptREPL
jpsacha 2197446
Update to Scala 3
jpsacha 0054041
Add Scala AdaptedScriptEngine with support for print redirection and …
jpsacha f1318a1
Add Scala compiler options
jpsacha 124d5ae
Correct replicated comment
jpsacha 8e8231d
Adapt an empty return value from `eval` to match Script Editor expect…
jpsacha File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
src/main/scala/org/scijava/plugins/scripting/scala/ScalaAdaptedScriptEngine.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package org.scijava.plugins.scripting.scala | ||
|
||
import java.io.{OutputStream, Reader, StringWriter, Writer} | ||
import javax.script.* | ||
import scala.collection.mutable | ||
import scala.jdk.CollectionConverters.* | ||
import scala.util.Try | ||
|
||
/** | ||
* Adapted Scala ScriptEngine | ||
* | ||
* @author Jarek Sacha | ||
* @author Keith Schulze | ||
* @see ScriptEngine | ||
*/ | ||
class ScalaAdaptedScriptEngine(engine: ScriptEngine) extends AbstractScriptEngine: | ||
|
||
import ScalaAdaptedScriptEngine.* | ||
|
||
private val buffer = new Array[Char](8192) | ||
|
||
@throws[ScriptException] | ||
override def eval(reader: Reader, context: ScriptContext): AnyRef = eval(stringFromReader(reader), context) | ||
|
||
@throws[ScriptException] | ||
override def eval(script: String, context: ScriptContext): AnyRef = | ||
emulateBinding(context) | ||
evalInner(script, context) | ||
|
||
private def emulateBinding(context: ScriptContext): Unit = | ||
|
||
// Scala 3.2.2 ignores bindings, emulate binding using setup script | ||
// Create a line with variable declaration for each binding item | ||
val lines = | ||
for | ||
scope <- context.getScopes.asScala | ||
bindings <- Option(context.getBindings(scope)).map(_.asScala) // bindings in context can be null | ||
yield { | ||
for (name, value) <- bindings yield { | ||
value match | ||
case v: Double => s"val $name : Double = ${v}d" | ||
case v: Float => s"val $name : Float = ${v}f" | ||
case v: Long => s"val $name : Long = ${v}L" | ||
case v: Int => s"val $name : Int = $v" | ||
case v: Char => s"val $name : Char = '$v'" | ||
case v: Short => s"val $name : Short = $v" | ||
case v: Byte => s"val $name : Byte = $v" | ||
case v: Boolean => s"val $name : Int = $v" | ||
case o: AnyRef if isValidVariableName(name) => | ||
_transfer = o | ||
val typeName = Option(o).map(_.getClass.getCanonicalName).getOrElse("AnyRef") | ||
s""" | ||
|val $name : $typeName = { | ||
| val t = org.scijava.plugins.scripting.scala.ScalaAdaptedScriptEngine._transfer | ||
| t.asInstanceOf[$typeName] | ||
|}""".stripMargin | ||
case _: AnyRef => "" // ignore if name is not a variable | ||
case v: Unit => | ||
throw ScriptException(s"Unsupported type for bind variable $name: ${v.getClass}") | ||
} | ||
} | ||
|
||
val script = lines | ||
.flatten | ||
.filter(_.nonEmpty) | ||
.mkString("\n") | ||
|
||
if script.nonEmpty then | ||
evalInner(script, context) | ||
|
||
end emulateBinding | ||
|
||
private def evalInner(script: String, context: ScriptContext) = | ||
class WriterOutputStream(w: Writer) extends OutputStream: | ||
override def write(b: Int): Unit = w.write(b) | ||
|
||
// Redirect output to writes provided by context | ||
Console.withOut(WriterOutputStream(context.getWriter)) { | ||
Console.withErr(WriterOutputStream(context.getErrorWriter)) { | ||
engine.eval(script, context) | ||
} | ||
} | ||
|
||
private def stringFromReader(in: Reader) = | ||
val out = new StringWriter() | ||
var n = in.read(buffer) | ||
while n > -1 do | ||
out.write(buffer, 0, n) | ||
n = in.read(buffer) | ||
in.close() | ||
out.toString | ||
|
||
override def createBindings(): Bindings = engine.createBindings | ||
|
||
override def getFactory: ScriptEngineFactory = engine.getFactory | ||
|
||
override def get(key: String): AnyRef = | ||
// First try to get value from bindings | ||
var value = super.get(key) | ||
|
||
// NB: Extracting values from Scala Script Engine are a little tricky.// NB: Extracting values from Scala Script Engine are a little tricky. | ||
// Values (variables) initialised or computed in the script are// Values (variables) initialised or computed in the script are | ||
// not added to the bindings of the CompiledScript AFAICT. Therefore// not added to the bindings of the CompiledScript AFAICT. Therefore | ||
// the only way to extract them is to evaluate the variable and// the only way to extract them is to evaluate the variable and | ||
// capture the return. If it evaluates to null or throws a// capture the return. If it evaluates to null or throws a | ||
// a ScriptException, we simply return null.// a ScriptException, we simply return null. | ||
if value == null then | ||
try | ||
value = evalInner(key, getContext) | ||
catch | ||
case _: ScriptException => | ||
// HACK: Explicitly ignore ScriptException, which arises if | ||
// key is not found. This feels bad because it fails silently | ||
// for the user, but it mimics behaviour in other script langs. | ||
|
||
value | ||
end get | ||
|
||
end ScalaAdaptedScriptEngine | ||
|
||
object ScalaAdaptedScriptEngine: | ||
private lazy val variableNamePattern = """^[a-zA-Z_$][a-zA-Z_$0-9]*$""".r | ||
|
||
/** Do not use externally despite it is declared public. IT is public so it is accessible from scripts */ | ||
// noinspection ScalaWeakerAccess | ||
var _transfer: Object = _ | ||
|
||
private def isValidVariableName(name: String): Boolean = variableNamePattern.matches(name) | ||
end ScalaAdaptedScriptEngine |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.