|
| 1 | +/* |
| 2 | + * #%L |
| 3 | + * JSR-223-compliant Scala scripting language plugin. |
| 4 | + * %% |
| 5 | + * Copyright (C) 2013 - 2023 SciJava developers. |
| 6 | + * %% |
| 7 | + * Redistribution and use in source and binary forms, with or without |
| 8 | + * modification, are permitted provided that the following conditions are met: |
| 9 | + * |
| 10 | + * 1. Redistributions of source code must retain the above copyright notice, |
| 11 | + * this list of conditions and the following disclaimer. |
| 12 | + * 2. Redistributions in binary form must reproduce the above copyright notice, |
| 13 | + * this list of conditions and the following disclaimer in the documentation |
| 14 | + * and/or other materials provided with the distribution. |
| 15 | + * |
| 16 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 17 | + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 18 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 19 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE |
| 20 | + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 21 | + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 22 | + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 23 | + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 24 | + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 25 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 26 | + * POSSIBILITY OF SUCH DAMAGE. |
| 27 | + * #L% |
| 28 | + */ |
| 29 | + |
1 | 30 | package org.scijava.plugins.scripting.scala
|
2 | 31 |
|
3 | 32 | import java.io.{OutputStream, Reader, StringWriter, Writer}
|
4 | 33 | import javax.script.*
|
5 | 34 | import scala.collection.mutable
|
6 | 35 | import scala.jdk.CollectionConverters.*
|
7 | 36 | import scala.util.Try
|
| 37 | +import scala.util.matching.Regex |
8 | 38 |
|
9 | 39 | /**
|
10 | 40 | * Adapted Scala ScriptEngine
|
@@ -43,26 +73,30 @@ class ScalaAdaptedScriptEngine(engine: ScriptEngine) extends AbstractScriptEngin
|
43 | 73 | bindings <- Option(context.getBindings(scope)).map(_.asScala) // bindings in context can be null
|
44 | 74 | yield {
|
45 | 75 | for (name, value) <- bindings yield {
|
46 |
| - value match |
47 |
| - case v: Double => s"val $name : Double = ${v}d" |
48 |
| - case v: Float => s"val $name : Float = ${v}f" |
49 |
| - case v: Long => s"val $name : Long = ${v}L" |
50 |
| - case v: Int => s"val $name : Int = $v" |
51 |
| - case v: Char => s"val $name : Char = '$v'" |
52 |
| - case v: Short => s"val $name : Short = $v" |
53 |
| - case v: Byte => s"val $name : Byte = $v" |
54 |
| - case v: Boolean => s"val $name : Int = $v" |
55 |
| - case o: AnyRef if isValidVariableName(name) => |
56 |
| - _transfer = o |
57 |
| - val typeName = Option(o).map(_.getClass.getCanonicalName).getOrElse("AnyRef") |
58 |
| - s""" |
59 |
| - |val $name : $typeName = { |
60 |
| - | val t = org.scijava.plugins.scripting.scala.ScalaAdaptedScriptEngine._transfer |
61 |
| - | t.asInstanceOf[$typeName] |
62 |
| - |}""".stripMargin |
63 |
| - case _: AnyRef => "" // ignore if name is not a variable |
64 |
| - case v: Unit => |
65 |
| - throw ScriptException(s"Unsupported type for bind variable $name: ${v.getClass}") |
| 76 | + if isValidVariableName(name) then |
| 77 | + val validName = addBackticksIfNeeded(name) |
| 78 | + value match |
| 79 | + case v: Double => s"val $validName : Double = ${v}d" |
| 80 | + case v: Float => s"val $validName : Float = ${v}f" |
| 81 | + case v: Long => s"val $validName : Long = ${v}L" |
| 82 | + case v: Int => s"val $validName : Int = $v" |
| 83 | + case v: Char => s"val $validName : Char = '$v'" |
| 84 | + case v: Short => s"val $validName : Short = $v" |
| 85 | + case v: Byte => s"val $validName : Byte = $v" |
| 86 | + case v: Boolean => s"val $validName : Int = $v" |
| 87 | + case v: AnyRef => |
| 88 | + _transfer = v |
| 89 | + val typeName = Option(v).map(_.getClass.getCanonicalName).getOrElse("AnyRef") |
| 90 | + val validTypeName = addBackticksIfNeeded(typeName) |
| 91 | + s""" |
| 92 | + |val $validName : $validTypeName = { |
| 93 | + | val t = org.scijava.plugins.scripting.scala.ScalaAdaptedScriptEngine._transfer |
| 94 | + | t.asInstanceOf[$validTypeName] |
| 95 | + |}""".stripMargin |
| 96 | + case v: Unit => |
| 97 | + throw ScriptException(s"Unsupported type for bind variable $name: ${v.getClass}") |
| 98 | + else |
| 99 | + "" // ignore if name is not a variable |
66 | 100 | }
|
67 | 101 | }
|
68 | 102 |
|
@@ -126,10 +160,60 @@ end ScalaAdaptedScriptEngine
|
126 | 160 |
|
127 | 161 | object ScalaAdaptedScriptEngine:
|
128 | 162 | private lazy val variableNamePattern = """^[a-zA-Z_$][a-zA-Z_$0-9]*$""".r
|
| 163 | + private val scala3Keywords = Seq( |
| 164 | + "abstract", |
| 165 | + "case", |
| 166 | + "catch", |
| 167 | + "class", |
| 168 | + "def", |
| 169 | + "do", |
| 170 | + "else", |
| 171 | + "enum", |
| 172 | + "export", |
| 173 | + "extends", |
| 174 | + "false", |
| 175 | + "final", |
| 176 | + "finally", |
| 177 | + "for", |
| 178 | + "given", |
| 179 | + "if", |
| 180 | + "implicit", |
| 181 | + "import", |
| 182 | + "lazy", |
| 183 | + "match", |
| 184 | + "new", |
| 185 | + "null", |
| 186 | + "object", |
| 187 | + "override", |
| 188 | + "package", |
| 189 | + "private", |
| 190 | + "protected", |
| 191 | + "return", |
| 192 | + "sealed", |
| 193 | + "super", |
| 194 | + "then", |
| 195 | + "throw", |
| 196 | + "trait", |
| 197 | + "true", |
| 198 | + "try", |
| 199 | + "type", |
| 200 | + "val", |
| 201 | + "var", |
| 202 | + "while", |
| 203 | + "with", |
| 204 | + "yield" |
| 205 | + ) |
129 | 206 |
|
130 | 207 | /** Do not use externally despite it is declared public. IT is public so it is accessible from scripts */
|
131 | 208 | // noinspection ScalaWeakerAccess
|
132 | 209 | var _transfer: Object = _
|
133 | 210 |
|
134 | 211 | private def isValidVariableName(name: String): Boolean = variableNamePattern.matches(name)
|
| 212 | + |
| 213 | + private[scala] def addBackticksIfNeeded(referenceName: String): String = |
| 214 | + referenceName |
| 215 | + .split("\\.") |
| 216 | + .map(n => if scala3Keywords.contains(n) then s"`$n`" else n) |
| 217 | + .mkString(".") |
| 218 | + |
135 | 219 | end ScalaAdaptedScriptEngine
|
0 commit comments