diff --git a/pom.xml b/pom.xml index 49f29bd..461a0b4 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,11 @@ Wisconsin-Madison. org/jetbrains/kotlin/daemon/common/*,kotlinx/coroutines/** + 1.4.30 + + + + false @@ -111,20 +116,13 @@ Wisconsin-Madison. org.jetbrains.kotlin - kotlin-script-util + kotlin-stdlib ${kotlin.version} org.jetbrains.kotlin - kotlin-script-runtime + kotlin-scripting-jsr223 ${kotlin.version} - runtime - - - org.jetbrains.kotlin - kotlin-scripting-compiler-embeddable - ${kotlin.version} - runtime diff --git a/src/main/java/org/scijava/plugins/scripting/kotlin/KotlinScriptLanguage.java b/src/main/java/org/scijava/plugins/scripting/kotlin/KotlinScriptLanguage.java deleted file mode 100644 index d2ab486..0000000 --- a/src/main/java/org/scijava/plugins/scripting/kotlin/KotlinScriptLanguage.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * #%L - * JSR-223-compliant Kotlin scripting language plugin. - * %% - * Copyright (C) 2016 - 2019 Board of Regents of the University of - * Wisconsin-Madison. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ - -package org.scijava.plugins.scripting.kotlin; - -import java.util.Arrays; -import java.util.List; - -import javax.script.ScriptEngine; - -import org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory; -import org.scijava.plugin.Plugin; -import org.scijava.script.AdaptedScriptLanguage; -import org.scijava.script.ScriptLanguage; - -/** - * A SciJava {@link ScriptLanguage} for Kotlin. - * - * @author Curtis Rueden - * @see ScriptEngine - */ -@Plugin(type = ScriptLanguage.class, name = "Kotlin") -public class KotlinScriptLanguage extends AdaptedScriptLanguage { - - public KotlinScriptLanguage() { - super(new KotlinJsr223JvmLocalScriptEngineFactory()); - } - - @Override - public List getNames() { - // NB: The wrapped ScriptEngineFactory does not include Kotlin in its list. - return Arrays.asList("kotlin", "Kotlin"); - } - - @Override - public List getExtensions() { - // NB: The wrapped ScriptEngineFactory does not include .kt in its list. - return Arrays.asList("kt", "kts"); - } -} diff --git a/src/main/kotlin/org/scijava/plugins/scripting/kotlin/KotlinScriptLanguage.kt b/src/main/kotlin/org/scijava/plugins/scripting/kotlin/KotlinScriptLanguage.kt new file mode 100644 index 0000000..e777e68 --- /dev/null +++ b/src/main/kotlin/org/scijava/plugins/scripting/kotlin/KotlinScriptLanguage.kt @@ -0,0 +1,111 @@ +/* + * #%L + * JSR-223-compliant Kotlin scripting language plugin. + * %% + * Copyright (C) 2016 - 2019 Board of Regents of the University of + * Wisconsin-Madison. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package org.scijava.plugins.scripting.kotlin + +import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase +import org.scijava.plugin.Plugin +import org.scijava.script.AdaptedScriptLanguage +import org.scijava.script.ScriptLanguage +import java.io.Reader +import javax.script.* + +/** + * A SciJava [ScriptLanguage] for Kotlin. + * + * @author Curtis Rueden + * @author Philipp Hanslovsky + * @see ScriptEngine + */ +@Plugin(type = ScriptLanguage::class, name = "Kotlin") +class KotlinScriptLanguage : AdaptedScriptLanguage(Factory()) { + // NB: The wrapped ScriptEngineFactory does not include Kotlin in its list. + override fun getNames() = listOf("kotlin", "Kotlin") + + // NB: The wrapped ScriptEngineFactory does not include .kt in its list. + override fun getExtensions() = listOf("kt", "kts") + + class Factory : KotlinJsr223JvmScriptEngineFactoryBase() { + override fun getScriptEngine(): ScriptEngine { + return SynchronizedScriptEngine(ScriptEngineManager().getEngineByExtension("kts")) + } + } + + class SynchronizedScriptEngine(private val delegate: ScriptEngine) : ScriptEngine { + @Synchronized + @Throws(ScriptException::class) + override fun eval(s: String, scriptContext: ScriptContext): Any? = delegate.eval(s, scriptContext) + + @Synchronized + @Throws(ScriptException::class) + override fun eval(reader: Reader, scriptContext: ScriptContext): Any? = delegate.eval(reader, scriptContext) + + @Synchronized + @Throws(ScriptException::class) + override fun eval(s: String): Any? = delegate.eval(s) + + @Synchronized + @Throws(ScriptException::class) + override fun eval(reader: Reader): Any? = delegate.eval(reader) + + @Synchronized + @Throws(ScriptException::class) + override fun eval(s: String, bindings: Bindings): Any? = delegate.eval(s, bindings) + + @Synchronized + @Throws(ScriptException::class) + override fun eval(reader: Reader, bindings: Bindings): Any? = delegate.eval(reader, bindings) + + @Synchronized + override fun put(s: String, o: Any) = delegate.put(s, o) + + @Synchronized + override fun get(s: String): Any? = delegate[s] + + @Synchronized + override fun getBindings(i: Int): Bindings? = delegate.getBindings(i) + + @Synchronized + override fun setBindings(bindings: Bindings, i: Int) = delegate.setBindings(bindings, i) + + @Synchronized + override fun createBindings(): Bindings = delegate.createBindings() + + @Synchronized + override fun getContext(): ScriptContext = delegate.context + + @Synchronized + override fun setContext(scriptContext: ScriptContext) { + delegate.context = scriptContext + } + + @Synchronized + override fun getFactory(): ScriptEngineFactory = delegate.factory + } +} \ No newline at end of file diff --git a/src/test/java/org/scijava/plugins/scripting/kotlin/KotlinTest.java b/src/test/java/org/scijava/plugins/scripting/kotlin/KotlinTest.java deleted file mode 100644 index c99da98..0000000 --- a/src/test/java/org/scijava/plugins/scripting/kotlin/KotlinTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * #%L - * JSR-223-compliant Kotlin scripting language plugin. - * %% - * Copyright (C) 2016 - 2019 Board of Regents of the University of - * Wisconsin-Madison. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ - -package org.scijava.plugins.scripting.kotlin; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.concurrent.ExecutionException; - -import javax.script.Bindings; -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptException; - -import org.junit.Test; -import org.scijava.Context; -import org.scijava.script.AbstractScriptLanguageTest; -import org.scijava.script.ScriptLanguage; -import org.scijava.script.ScriptModule; -import org.scijava.script.ScriptService; - -/** - * Kotlin unit tests. - * - * @author Curtis Rueden - */ -public class KotlinTest extends AbstractScriptLanguageTest { - - @Test - public void testDiscovery() { - assertDiscovered(KotlinScriptLanguage.class); - } - - @Test - public void testBasic() throws InterruptedException, ExecutionException, - IOException, ScriptException - { - final Context context = new Context(ScriptService.class); - final ScriptService scriptService = context.getService(ScriptService.class); - final String script = "1 + 2"; - final ScriptModule m = scriptService.run("add.kt", script, true).get(); - final Object result = m.getReturnValue(); - assertEquals("3", result.toString()); - } - - @Test - public void testLocals() throws ScriptException { - final Context context = new Context(ScriptService.class); - final ScriptService scriptService = context.getService(ScriptService.class); - - final ScriptLanguage language = scriptService.getLanguageByExtension("kt"); - final ScriptEngine engine = language.getScriptEngine(); - assertTrue(engine.getFactory().getNames().contains("kotlin")); - - engine.put("hello", 17); - assertEquals("17", engine.eval("bindings[\"hello\"]").toString()); - assertEquals("17", engine.get("hello").toString()); - - engine.put("foo", "bar"); - assertEquals("bar", engine.eval("bindings[\"foo\"]").toString()); - assertEquals("bar", engine.get("foo").toString()); - // FIXME: You cannot modify or insert a variable in the bindings! -// engine.eval("bindings[\"foo\"] = \"great\""); -// assertEquals("great", engine.eval("bindings[\"foo\"]").toString()); -// assertEquals("great", engine.get("foo").toString()); - - final Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); - bindings.clear(); - assertNull(engine.get("hello")); - } - - // FIXME: Calling methods on injected instance vars fails with - // "unresolved reference". Nor can we store values into the bindings map! -// @Test -// public void testParameters() throws InterruptedException, ExecutionException, -// IOException, ScriptException -// { -// final Context context = new Context(ScriptService.class); -// final ScriptService scriptService = context.getService(ScriptService.class); -// -// final String script = "" + // -// "// @ScriptService ss\n" + // -// "// @OUTPUT String language\n" + // -// "// @OUTPUT ScriptService ssOut\n" + // -// "println(\"==> \" + bindings[\"ss\"])\n" + // -// "bindings[\"ssOut\"] = bindings[\"ss\"]\n"; -//// "println(\"==> \" + ss.canHandleFile(\"/Users/curtis\"))\n"; -//// "val language = " + // -//// "bindings[\"ss\"].getLanguageByName(\"kotlin\").getLanguageName()\n"; -// final ScriptModule m = scriptService.run("hello.kt", script, true).get(); -// -// final Object actual = m.getOutput("ssOut"); -// final Object expected = -// scriptService.getLanguageByName("kotlin"); -// assertEquals(expected, actual); -// } - -} diff --git a/src/test/kotlin/org/scijava/plugins/scripting/kotlin/KotlinTest.kt b/src/test/kotlin/org/scijava/plugins/scripting/kotlin/KotlinTest.kt new file mode 100644 index 0000000..08b6c5c --- /dev/null +++ b/src/test/kotlin/org/scijava/plugins/scripting/kotlin/KotlinTest.kt @@ -0,0 +1,93 @@ +/* + * #%L + * JSR-223-compliant Kotlin scripting language plugin. + * %% + * Copyright (C) 2016 - 2019 Board of Regents of the University of + * Wisconsin-Madison. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package org.scijava.plugins.scripting.kotlin + +import org.junit.Assert +import org.junit.BeforeClass +import org.junit.Test +import org.scijava.Context +import org.scijava.script.AbstractScriptLanguageTest +import org.scijava.script.ScriptLanguage +import org.scijava.script.ScriptService +import java.io.IOException +import java.util.concurrent.ExecutionException +import javax.script.ScriptContext +import javax.script.ScriptEngine +import javax.script.ScriptException +import kotlin.math.E + +/** + * Kotlin unit tests. + * + * @author Curtis Rueden + * @author Philipp Hanslovsky + */ +class KotlinTest : AbstractScriptLanguageTest() { + + @Test + fun testDiscovery() = assertDiscovered(KotlinScriptLanguage::class.java) + + @Test + @Throws(InterruptedException::class, ExecutionException::class, IOException::class, ScriptException::class) + fun `test basic script engine eval`() = Assert.assertEquals(3, engine.eval("1 + 2")) + + @Test + @Throws(ScriptException::class) + fun `test basic engine eval with bindings`() { + engine.put("Hello", ", SciJava!") + Assert.assertEquals(", SciJava!", engine.eval("Hello")) + Assert.assertEquals(", SciJava!", engine["Hello"]) + + val bindings = engine.createBindings() + bindings["base"] = E + val script = "import kotlin.math.*; base.pow(0)" + Assert.assertThrows(ScriptException::class.java) { engine.eval(script) } + Assert.assertEquals(1.0, engine.eval(script, bindings) as Double, 0.0) + + // clear bindings and access variable Hello to cause ScriptException + engine.getBindings(ScriptContext.ENGINE_SCOPE)?.clear() + Assert.assertNull(engine["Hello"]) + } + + + companion object { + @BeforeClass + @JvmStatic + fun initKotlinLang() { + val context = Context(ScriptService::class.java) + val scriptService: ScriptService = context.getService(ScriptService::class.java) + _kotlinLang = scriptService.getLanguageByName("Kotlin") + _engine = _kotlinLang.scriptEngine + } + private lateinit var _kotlinLang: ScriptLanguage + private lateinit var _engine: ScriptEngine + val engine get() = _engine + } +} \ No newline at end of file