Refactor repl and JSR 223 support code, add separate example jars for each type of JSR 223 repl (with tests)

This commit is contained in:
Ilya Chernikov
2016-09-26 17:56:26 +02:00
parent 079fece9b4
commit 10d259771c
22 changed files with 925 additions and 152 deletions
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cli.common.repl
import java.io.Reader
import javax.script.*
abstract class KotlinJsr223JvmScriptEngineBase(protected val myFactory: ScriptEngineFactory) : AbstractScriptEngine(), ScriptEngine {
protected var lineCount = 0
protected val history = arrayListOf<ReplCodeLine>()
abstract fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult
override fun eval(script: String, context: ScriptContext?): Any? {
lineCount += 1
// TODO bind to context
val codeLine = ReplCodeLine(lineCount, script)
val evalResult = eval(codeLine, history)
val ret = when (evalResult) {
is ReplEvalResult.ValueResult -> evalResult.value
is ReplEvalResult.UnitResult -> null
is ReplEvalResult.Error -> throw ScriptException(evalResult.message)
is ReplEvalResult.Incomplete -> throw ScriptException("error: incomplete code")
is ReplEvalResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${evalResult.lineNo}")
}
history.add(codeLine)
// TODO update context
return ret
}
override fun eval(script: Reader, context: ScriptContext?): Any? = eval(script.readText(), context)
override fun createBindings(): Bindings = SimpleBindings()
override fun getFactory(): ScriptEngineFactory = myFactory
}
@@ -14,18 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.jsr223 package org.jetbrains.kotlin.cli.common.repl
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.KotlinVersion import org.jetbrains.kotlin.cli.common.KotlinVersion
import org.jetbrains.kotlin.utils.PathUtil
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngine import javax.script.ScriptEngine
import javax.script.ScriptEngineFactory import javax.script.ScriptEngineFactory
@Suppress("unused") // used in javax.script.ScriptEngineFactory META-INF file abstract class KotlinJsr223JvmScriptEngineFactoryBase : ScriptEngineFactory {
class KotlinJvmJsr223StandardScriptEngineFactory4Idea : ScriptEngineFactory {
override fun getLanguageName(): String = "kotlin" override fun getLanguageName(): String = "kotlin"
override fun getLanguageVersion(): String = KotlinVersion.VERSION override fun getLanguageVersion(): String = KotlinVersion.VERSION
@@ -35,20 +30,6 @@ class KotlinJvmJsr223StandardScriptEngineFactory4Idea : ScriptEngineFactory {
override fun getMimeTypes(): List<String> = listOf("text/x-kotlin") override fun getMimeTypes(): List<String> = listOf("text/x-kotlin")
override fun getNames(): List<String> = listOf("kotlin") override fun getNames(): List<String> = listOf("kotlin")
override fun getScriptEngine(): ScriptEngine =
KotlinJvmJsr223ScriptEngine4Idea(
Disposer.newDisposable(),
this,
listOf(PathUtil.getKotlinPathsForIdeaPlugin().runtimePath),
"kotlin.script.ScriptTemplateWithArgsAndBindings",
{ ctx ->
val bindings = ctx.getBindings(ScriptContext.ENGINE_SCOPE)
arrayOf(
(bindings[ScriptEngine.ARGV] as? Array<*>) ?: emptyArray<String>(),
bindings) },
arrayOf(Array<String>::class.java, java.util.Map::class.java)
)
override fun getOutputStatement(toDisplay: String?): String = "print(\"$toDisplay\")" override fun getOutputStatement(toDisplay: String?): String = "print(\"$toDisplay\")"
override fun getMethodCallSyntax(obj: String, m: String, vararg args: String): String = "$obj.$m(${args.joinToString()})" override fun getMethodCallSyntax(obj: String, m: String, vararg args: String): String = "$obj.$m(${args.joinToString()})"
@@ -181,10 +181,12 @@ open class GenericRepl(
scriptDefinition: KotlinScriptDefinition, scriptDefinition: KotlinScriptDefinition,
compilerConfiguration: CompilerConfiguration, compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector, messageCollector: MessageCollector,
baseClassloader: ClassLoader? baseClassloader: ClassLoader?,
scriptArgs: Array<Any?>? = null,
scriptArgsTypes: Array<Class<*>>? = null
) : ReplEvaluator, GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) { ) : ReplEvaluator, GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) {
private val compiledEvaluator = GenericReplCompiledEvaluator(compilerConfiguration.jvmClasspathRoots, baseClassloader) private val compiledEvaluator = GenericReplCompiledEvaluator(compilerConfiguration.jvmClasspathRoots, baseClassloader, scriptArgs, scriptArgsTypes)
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult = synchronized(this) { override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult = synchronized(this) {
return compileAndEval(this, compiledEvaluator, codeLine, history) return compileAndEval(this, compiledEvaluator, codeLine, history)
@@ -1 +1 @@
org.jetbrains.kotlin.jsr223.KotlinJvmJsr223StandardScriptEngineFactory4Idea org.jetbrains.kotlin.jsr223.KotlinJsr223StandardScriptEngineFactory4Idea
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.jsr223
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.daemon.client.DaemonReportMessage
import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.KotlinCompilerClient
import org.jetbrains.kotlin.daemon.client.KotlinRemoteReplCompiler
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import javax.script.ScriptContext
import javax.script.ScriptEngineFactory
import javax.script.ScriptException
class KotlinJsr223JvmScriptEngine4Idea(
disposable: Disposable,
factory: ScriptEngineFactory,
templateClasspath: List<File>,
templateClassName: String,
getScriptArgs: (ScriptContext) -> Array<Any?>?,
scriptArgsTypes: Array<Class<*>>?
) : KotlinJsr223JvmScriptEngineBase(factory) {
private val daemon by lazy {
val path = PathUtil.getKotlinPathsForIdeaPlugin().compilerPath
assert(path.exists())
val compilerId = CompilerId.makeCompilerId(path)
val daemonOptions = configureDaemonOptions()
val daemonJVMOptions = DaemonJVMOptions()
val daemonReportMessages = arrayListOf<DaemonReportMessage>()
KotlinCompilerClient.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, DaemonReportingTargets(null, daemonReportMessages), true, true)
?: throw ScriptException("Unable to connect to repl server:" + daemonReportMessages.joinToString("\n ", prefix = "\n ") { "${it.category.name} ${it.message}" })
}
private val replCompiler by lazy {
daemon.let {
KotlinRemoteReplCompiler(disposable,
it,
makeAutodeletingFlagFile("idea-jsr223-repl-session"),
CompileService.TargetPlatform.JVM,
templateClasspath,
templateClassName,
System.out)
}
}
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
val localEvaluator by lazy { GenericReplCompiledEvaluator(templateClasspath, Thread.currentThread().contextClassLoader, getScriptArgs(getContext()), scriptArgsTypes) }
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult {
fun ReplCompileResult.Error.locationString() = if (location == CompilerMessageLocation.NO_LOCATION) ""
else " at ${location.line}:${location.column}:"
val compileResult = replCompiler.compile(codeLine, history)
val compiled = when (compileResult) {
is ReplCompileResult.Error -> throw ScriptException("Error${compileResult.locationString()}: ${compileResult.message}")
is ReplCompileResult.Incomplete -> throw ScriptException("error: incomplete code")
is ReplCompileResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${compileResult.lineNo}")
is ReplCompileResult.CompiledClasses -> compileResult
}
return localEvaluator.eval(codeLine, history, compiled.classes, compiled.hasResult, compiled.newClasspath)
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.jsr223
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.utils.PathUtil
import javax.script.ScriptContext
import javax.script.ScriptEngine
@Suppress("unused") // used in javax.script.ScriptEngineFactory META-INF file
class KotlinJsr223StandardScriptEngineFactory4Idea : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmScriptEngine4Idea(
Disposer.newDisposable(),
this,
listOf(PathUtil.getKotlinPathsForIdeaPlugin().runtimePath),
"kotlin.script.ScriptTemplateWithArgsAndBindings",
{ ctx ->
val bindings = ctx.getBindings(ScriptContext.ENGINE_SCOPE)
arrayOf(
(bindings[ScriptEngine.ARGV] as? Array<*>) ?: emptyArray<String>(),
bindings) },
arrayOf(Array<String>::class.java, java.util.Map::class.java)
)
}
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<properties>
<maven-plugin-anno.version>1.4.1</maven-plugin-anno.version>
<maven.version>3.0.4</maven.version>
</properties>
<parent>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-project</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>kotlin-jsr223-daemon-local-eval-example</artifactId>
<packaging>jar</packaging>
<description>Sample Kotlin JSR 223 scripting jar with daemon (out-of-process) compilation and local (in-process) evaluation</description>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-runtime</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-script-util</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${project.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.6</version>
<configuration>
<systemPropertyVariables>
<KOTLIN_COMPILER_JAR>${org.jetbrains.kotlin:kotlin-compiler:jar}</KOTLIN_COMPILER_JAR>
<KOTLIN_JAVA_RUNTIME_JAR>${org.jetbrains.kotlin:kotlin-runtime:jar}</KOTLIN_JAVA_RUNTIME_JAR>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1 @@
org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory
@@ -16,33 +16,18 @@
package org.jetbrains.kotlin.script.jsr223 package org.jetbrains.kotlin.script.jsr223
import junit.framework.TestCase
import org.jetbrains.kotlin.cli.common.KotlinVersion import org.jetbrains.kotlin.cli.common.KotlinVersion
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import javax.script.ScriptEngine import javax.script.ScriptEngine
import javax.script.ScriptEngineFactory
import javax.script.ScriptEngineManager import javax.script.ScriptEngineManager
import javax.script.SimpleBindings import javax.script.SimpleBindings
class KotlinJsr223ScriptEngineTest : TestCase() { class KotlinJsr223ScriptEngineIT {
private var factory: ScriptEngineFactory? = null
private var engine: ScriptEngine? = null
override fun setUp() {
super.setUp()
factory = ScriptEngineManager().getEngineByExtension("kts").factory
engine = factory?.scriptEngine
}
override fun tearDown() {
factory = null
super.tearDown()
}
@Test @Test
fun testEngineFactory() { fun testEngineFactory() {
val factory = ScriptEngineManager().getEngineByExtension("kts").factory
Assert.assertNotNull(factory) Assert.assertNotNull(factory)
factory!!.apply { factory!!.apply {
Assert.assertEquals("kotlin", languageName) Assert.assertEquals("kotlin", languageName)
@@ -63,17 +48,21 @@ class KotlinJsr223ScriptEngineTest : TestCase() {
@Test @Test
fun testEngine() { fun testEngine() {
Assert.assertNotNull(engine as? KotlinJsr232ScriptEngine) val factory = ScriptEngineManager().getEngineByExtension("kts").factory
Assert.assertNotNull(factory)
val engine = factory!!.scriptEngine
Assert.assertNotNull(engine as? KotlinJsr223JvmDaemonLocalEvalScriptEngine)
Assert.assertSame(factory, engine!!.factory) Assert.assertSame(factory, engine!!.factory)
val bindings = engine!!.createBindings() val bindings = engine.createBindings()
Assert.assertTrue(bindings is SimpleBindings) Assert.assertTrue(bindings is SimpleBindings)
} }
@Test @Test
fun testSimpleEval() { fun testSimpleEval() {
val res1 = engine!!.eval("val x = 3") val engine = ScriptEngineManager().getEngineByExtension("kts")!!
val res1 = engine.eval("val x = 3")
Assert.assertNull(res1) Assert.assertNull(res1)
val res2 = engine!!.eval("x + 2") val res2 = engine.eval("x + 2")
Assert.assertEquals(5, res2) Assert.assertEquals(5, res2)
} }
} }
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<properties>
<maven-plugin-anno.version>1.4.1</maven-plugin-anno.version>
<maven.version>3.0.4</maven.version>
</properties>
<parent>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-project</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>kotlin-jsr223-daemon-remote-eval-example</artifactId>
<packaging>jar</packaging>
<description>Sample Kotlin JSR 223 scripting jar with daemon (out-of-process) compilation and evaluation</description>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-runtime</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-script-util</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${project.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.6</version>
<configuration>
<systemPropertyVariables>
<KOTLIN_COMPILER_JAR>${org.jetbrains.kotlin:kotlin-compiler:jar}</KOTLIN_COMPILER_JAR>
<KOTLIN_JAVA_RUNTIME_JAR>${org.jetbrains.kotlin:kotlin-runtime:jar}</KOTLIN_JAVA_RUNTIME_JAR>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1 @@
org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmDaemonRemoteEvalScriptEngineFactory
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.script.jsr223
import org.jetbrains.kotlin.cli.common.KotlinVersion
import org.junit.Assert
import org.junit.Test
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import javax.script.SimpleBindings
class KotlinJsr223ScriptEngineIT {
@Test
fun testEngineFactory() {
val factory = ScriptEngineManager().getEngineByExtension("kts").factory
Assert.assertNotNull(factory)
factory!!.apply {
Assert.assertEquals("kotlin", languageName)
Assert.assertEquals(KotlinVersion.VERSION, languageVersion)
Assert.assertEquals("kotlin", engineName)
Assert.assertEquals(KotlinVersion.VERSION, engineVersion)
Assert.assertEquals(listOf("kts"), extensions)
Assert.assertEquals(listOf("text/x-kotlin"), mimeTypes)
Assert.assertEquals(listOf("kotlin"), names)
Assert.assertEquals("obj.method(arg1, arg2, arg3)", getMethodCallSyntax("obj", "method", "arg1", "arg2", "arg3"))
Assert.assertEquals("print(\"Hello, world!\")", getOutputStatement("Hello, world!"))
Assert.assertEquals(KotlinVersion.VERSION, getParameter(ScriptEngine.LANGUAGE_VERSION))
val sep = System.getProperty("line.separator")
val prog = arrayOf("val x: Int = 3", "var y = x + 2")
Assert.assertEquals(prog.joinToString(sep) + sep, getProgram(*prog))
}
}
@Test
fun testEngine() {
val factory = ScriptEngineManager().getEngineByExtension("kts").factory
Assert.assertNotNull(factory)
val engine = factory!!.scriptEngine
Assert.assertNotNull(engine as? KotlinJsr223JvmDaemonRemoteEvalScriptEngine)
Assert.assertSame(factory, engine!!.factory)
val bindings = engine.createBindings()
Assert.assertTrue(bindings is SimpleBindings)
}
@Test
fun testSimpleEval() {
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
val res1 = engine.eval("val x = 3")
Assert.assertNull(res1)
val res2 = engine.eval("x + 2")
Assert.assertEquals(5, res2)
}
}
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<properties>
<maven-plugin-anno.version>1.4.1</maven-plugin-anno.version>
<maven.version>3.0.4</maven.version>
</properties>
<parent>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-project</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>kotlin-jsr223-local-example</artifactId>
<packaging>jar</packaging>
<description>Sample Kotlin JSR 223 scripting jar with local (in-process) compilation and evaluation</description>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-runtime</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-script-util</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${project.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.6</version>
<configuration>
<systemPropertyVariables>
<KOTLIN_COMPILER_JAR>${org.jetbrains.kotlin:kotlin-compiler:jar}</KOTLIN_COMPILER_JAR>
<KOTLIN_JAVA_RUNTIME_JAR>${org.jetbrains.kotlin:kotlin-runtime:jar}</KOTLIN_JAVA_RUNTIME_JAR>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1 @@
org.jetbrains.kotlin.script.jsr223.KotlinJsr232JvmLocalScriptEngineFactory
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.script.jsr223
import org.jetbrains.kotlin.cli.common.KotlinVersion
import org.junit.Assert
import org.junit.Test
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import javax.script.SimpleBindings
class KotlinJsr223ScriptEngineIT {
@Test
fun testEngineFactory() {
val factory = ScriptEngineManager().getEngineByExtension("kts").factory
Assert.assertNotNull(factory)
factory!!.apply {
Assert.assertEquals("kotlin", languageName)
Assert.assertEquals(KotlinVersion.VERSION, languageVersion)
Assert.assertEquals("kotlin", engineName)
Assert.assertEquals(KotlinVersion.VERSION, engineVersion)
Assert.assertEquals(listOf("kts"), extensions)
Assert.assertEquals(listOf("text/x-kotlin"), mimeTypes)
Assert.assertEquals(listOf("kotlin"), names)
Assert.assertEquals("obj.method(arg1, arg2, arg3)", getMethodCallSyntax("obj", "method", "arg1", "arg2", "arg3"))
Assert.assertEquals("print(\"Hello, world!\")", getOutputStatement("Hello, world!"))
Assert.assertEquals(KotlinVersion.VERSION, getParameter(ScriptEngine.LANGUAGE_VERSION))
val sep = System.getProperty("line.separator")
val prog = arrayOf("val x: Int = 3", "var y = x + 2")
Assert.assertEquals(prog.joinToString(sep) + sep, getProgram(*prog))
}
}
@Test
fun testEngine() {
val factory = ScriptEngineManager().getEngineByExtension("kts").factory
Assert.assertNotNull(factory)
val engine = factory!!.scriptEngine
Assert.assertNotNull(engine as? KotlinJsr232JvmLocalScriptEngine)
Assert.assertSame(factory, engine!!.factory)
val bindings = engine.createBindings()
Assert.assertTrue(bindings is SimpleBindings)
}
@Test
fun testSimpleEval() {
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
val res1 = engine.eval("val x = 3")
Assert.assertNull(res1)
val res2 = engine.eval("x + 2")
Assert.assertEquals(5, res2)
}
}
+4
View File
@@ -74,6 +74,7 @@
<modules> <modules>
<module>tools/kotlin-compiler</module> <module>tools/kotlin-compiler</module>
<module>tools/kotlin-compiler-embeddable</module> <module>tools/kotlin-compiler-embeddable</module>
<module>tools/kotlin-daemon-client</module>
<module>tools/kotlin-build-common</module> <module>tools/kotlin-build-common</module>
<module>tools/kotlin-build-common-test</module> <module>tools/kotlin-build-common-test</module>
<module>tools/kotlin-maven-plugin</module> <module>tools/kotlin-maven-plugin</module>
@@ -112,6 +113,9 @@
<module>examples/kotlin-gradle-subplugin-example</module> <module>examples/kotlin-gradle-subplugin-example</module>
<module>examples/browser-example</module> <module>examples/browser-example</module>
<module>examples/browser-example-with-library</module> <module>examples/browser-example-with-library</module>
<module>examples/kotlin-jsr223-local-example</module>
<module>examples/kotlin-jsr223-daemon-local-eval-example</module>
<module>examples/kotlin-jsr223-daemon-remote-eval-example</module>
</modules> </modules>
<dependencies> <dependencies>
+7 -1
View File
@@ -39,6 +39,11 @@
<artifactId>kotlin-compiler</artifactId> <artifactId>kotlin-compiler</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-daemon-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.jcabi</groupId> <groupId>com.jcabi</groupId>
<artifactId>jcabi-aether</artifactId> <artifactId>jcabi-aether</artifactId>
@@ -97,7 +102,8 @@
<version>2.6</version> <version>2.6</version>
<configuration> <configuration>
<systemPropertyVariables> <systemPropertyVariables>
<runtimeJar>${org.jetbrains.kotlin:kotlin-stdlib:jar}</runtimeJar> <jvm>${env.JDK_17}/bin/java</jvm>
<KOTLIN_JAVA_RUNTIME_JAR>${org.jetbrains.kotlin:kotlin-stdlib:jar}</KOTLIN_JAVA_RUNTIME_JAR>
</systemPropertyVariables> </systemPropertyVariables>
</configuration> </configuration>
<executions> <executions>
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.script.jsr223
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.daemon.client.*
import org.jetbrains.kotlin.daemon.common.*
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import javax.script.ScriptContext
import javax.script.ScriptEngineFactory
import javax.script.ScriptException
class KotlinJsr223JvmDaemonLocalEvalScriptEngine(
disposable: Disposable,
factory: ScriptEngineFactory,
compilerJar: File,
templateClasspath: List<File>,
templateClassName: String,
getScriptArgs: (ScriptContext) -> Array<Any?>?,
scriptArgsTypes: Array<Class<*>>?,
compilerOut: OutputStream = System.err
) : KotlinJsr223JvmScriptEngineBase(factory) {
private val daemon by lazy { connectToCompileService(compilerJar) }
private val replCompiler by lazy {
daemon.let {
KotlinRemoteReplCompiler(
disposable,
it,
makeAutodeletingFlagFile("jsr223-repl-session"),
CompileService.TargetPlatform.JVM,
templateClasspath,
templateClassName,
compilerOut)
}
}
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
val localEvaluator by lazy { GenericReplCompiledEvaluator(templateClasspath, Thread.currentThread().contextClassLoader, getScriptArgs(getContext()), scriptArgsTypes) }
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult {
fun ReplCompileResult.Error.locationString() = if (location == CompilerMessageLocation.NO_LOCATION) ""
else " at ${location.line}:${location.column}:"
val compileResult = replCompiler.compile(codeLine, history)
val compiled = when (compileResult) {
is ReplCompileResult.Error -> throw ScriptException("Error${compileResult.locationString()}: ${compileResult.message}")
is ReplCompileResult.Incomplete -> throw ScriptException("error: incomplete code")
is ReplCompileResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${compileResult.lineNo}")
is ReplCompileResult.CompiledClasses -> compileResult
}
return localEvaluator.eval(codeLine, history, compiled.classes, compiled.hasResult, compiled.newClasspath)
}
}
class KotlinJsr223JvmDaemonRemoteEvalScriptEngine(
disposable: Disposable,
factory: ScriptEngineFactory,
compilerJar: File,
templateClasspath: List<File>,
templateClassName: String,
getScriptArgs: (ScriptContext) -> Array<Any?>?,
scriptArgsTypes: Array<Class<*>>?,
compilerOutputStream: OutputStream = System.err,
evallOutputStream: OutputStream = System.out,
evalErrrorStream: OutputStream = System.err,
evalInputStream: InputStream = System.`in`
) : KotlinJsr223JvmScriptEngineBase(factory) {
private val daemon by lazy { connectToCompileService(compilerJar) }
// TODO: bindings passing works only once on the first eval, subsequent setContext/setBindings call have no effect. Consider making it dynamic, but take history into account
private val repl by lazy {
daemon.let {
KotlinRemoteReplEvaluator(
disposable,
it,
makeAutodeletingFlagFile("jsr223-repl-session"),
CompileService.TargetPlatform.JVM,
templateClasspath,
templateClassName,
getScriptArgs(getContext()),
scriptArgsTypes,
compilerOutputStream,
evallOutputStream,
evalErrrorStream,
evalInputStream)
}
}
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult = repl.eval(codeLine, history)
}
private fun connectToCompileService(compilerJar: File): CompileService {
val compilerId = CompilerId.makeCompilerId(compilerJar)
val daemonOptions = configureDaemonOptions()
val daemonJVMOptions = DaemonJVMOptions()
val daemonReportMessages = arrayListOf<DaemonReportMessage>()
return KotlinCompilerClient.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, DaemonReportingTargets(null, daemonReportMessages), true, true)
?: throw ScriptException("Unable to connect to repl server:" + daemonReportMessages.joinToString("\n ", prefix = "\n ") { "${it.category.name} ${it.message}" })
}
@@ -21,21 +21,30 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.repl.GenericRepl import org.jetbrains.kotlin.cli.jvm.repl.GenericRepl
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.script.KotlinScriptDefinition import org.jetbrains.kotlin.script.KotlinScriptDefinition
import java.io.Reader import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import javax.script.* import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.net.URLClassLoader
import javax.script.ScriptContext
import javax.script.ScriptEngineFactory
import javax.script.ScriptException
class KotlinJsr232ScriptEngine( class KotlinJsr232JvmLocalScriptEngine(
disposable: Disposable, disposable: Disposable,
private val factory: ScriptEngineFactory, factory: ScriptEngineFactory,
private val scriptDefinition: KotlinScriptDefinition, val templateClasspath: List<File>,
private val compilerConfiguration: CompilerConfiguration, templateClassName: String,
baseClassLoader: ClassLoader getScriptArgs: (ScriptContext) -> Array<Any?>?,
) : AbstractScriptEngine(), ScriptEngine { scriptArgsTypes: Array<Class<*>>?
) : KotlinJsr223JvmScriptEngineBase(factory) {
data class MessageCollectorReport(val severity: CompilerMessageSeverity, val message: String, val location: CompilerMessageLocation) data class MessageCollectorReport(val severity: CompilerMessageSeverity, val message: String, val location: CompilerMessageLocation)
@@ -74,33 +83,32 @@ class KotlinJsr232ScriptEngine(
} }
} }
private val repl = object : GenericRepl(disposable, scriptDefinition, compilerConfiguration, messageCollector, baseClassLoader) {} private val repl by lazy {
GenericRepl(
private var lineCount = 0 disposable,
makeScriptDefinition(templateClasspath, templateClassName),
private val history = arrayListOf<ReplCodeLine>() makeCompilerConfiguration(),
messageCollector,
override fun eval(script: String, context: ScriptContext?): Any? { Thread.currentThread().contextClassLoader,
lineCount += 1 getScriptArgs(getContext()),
// TODO bind to context scriptArgsTypes)
val codeLine = ReplCodeLine(lineCount, script)
val evalResult = repl.eval(codeLine, history)
messageCollector.resetAndThrowOnErrors()
val ret = when (evalResult) {
is ReplEvalResult.ValueResult -> evalResult.value
is ReplEvalResult.UnitResult -> null
is ReplEvalResult.Error -> throw ScriptException(evalResult.message)
is ReplEvalResult.Incomplete -> throw ScriptException("error: incomplete code")
is ReplEvalResult.HistoryMismatch -> throw ScriptException("Repl history mismatch at line: ${evalResult.lineNo}")
}
history.add(codeLine)
// TODO update context
return ret
} }
override fun eval(script: Reader, context: ScriptContext?): Any? = eval(script.readText(), context) private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), this.javaClass.classLoader)
val cls = classloader.loadClass(templateClassName)
return KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, null, null, emptyMap())
}
override fun createBindings(): Bindings = SimpleBindings() private fun makeCompilerConfiguration() = CompilerConfiguration().apply {
addJvmClasspathRoots(PathUtil.getJdkClassesRoots())
addJvmClasspathRoots(templateClasspath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
}
override fun getFactory(): ScriptEngineFactory = factory override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult {
val evalResult = repl.eval(codeLine, history)
messageCollector.resetAndThrowOnErrors()
return evalResult
}
} }
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("unused") // could be used externally in javax.script.ScriptEngineFactory META-INF file
package org.jetbrains.kotlin.script.jsr223
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.utils.PathUtil.*
import java.io.File
import java.io.FileNotFoundException
import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.StandardScriptTemplate
class KotlinJsr232JvmLocalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine =
KotlinJsr232JvmLocalScriptEngine(
Disposer.newDisposable(),
this,
listOf(kotlinRuntimeJar),
"kotlin.script.ScriptTemplateWithArgsAndBindings",
::makeArgumentsForTemplateWithArgsAndBindings,
arrayOf(Array<String>::class.java, java.util.Map::class.java)
)
}
class KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmDaemonLocalEvalScriptEngine(
Disposer.newDisposable(),
this,
kotlinCompilerJar,
listOf(kotlinRuntimeJar),
"kotlin.script.ScriptTemplateWithArgsAndBindings",
::makeArgumentsForTemplateWithArgsAndBindings,
arrayOf(Array<String>::class.java, java.util.Map::class.java)
)
}
class KotlinJsr223JvmDaemonRemoteEvalScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmDaemonRemoteEvalScriptEngine(
Disposer.newDisposable(),
this,
kotlinCompilerJar,
listOf(kotlinRuntimeJar),
"kotlin.script.ScriptTemplateWithArgsAndBindings",
::makeSerializableArgumentsForTemplateWithArgsAndBindings,
arrayOf(Array<String>::class.java, java.util.Map::class.java)
)
}
private fun makeArgumentsForTemplateWithArgsAndBindings(ctx: ScriptContext): Array<Any?> {
val bindings = ctx.getBindings(ScriptContext.ENGINE_SCOPE)
return arrayOf(
(bindings[ScriptEngine.ARGV] as? Array<*>) ?: emptyArray<String>(),
bindings)
}
private fun makeSerializableArgumentsForTemplateWithArgsAndBindings(ctx: ScriptContext): Array<Any?> {
val bindings = ctx.getBindings(ScriptContext.ENGINE_SCOPE)
val serializableBindings = linkedMapOf<String, Any>()
// TODO: consider deeper analysis and copying to serializable data if possible
serializableBindings.putAll(bindings)
return arrayOf(
(bindings[ScriptEngine.ARGV] as? Array<*>) ?: emptyArray<String>(),
serializableBindings)
}
private fun File.existsOrNull(): File? = existsAndCheckOrNull { true }
private inline fun File.existsAndCheckOrNull(check: (File.() -> Boolean)): File? = if (exists() && check()) this else null
private val kotlinCompilerJar = System.getProperty("KOTLIN_COMPILER_JAR")?.let(::File)?.existsOrNull()
?: getPathUtilJar().existsAndCheckOrNull { name == KOTLIN_COMPILER_JAR }
?: throw FileNotFoundException("Cannot find kotlin compiler jar, set KOTLIN_COMPILER_JAR property to proper location")
private val kotlinRuntimeJar = System.getProperty("KOTLIN_JAVA_RUNTIME_JAR")?.let(::File)?.existsOrNull()
?: kotlinCompilerJar.let { File(it.parentFile, KOTLIN_JAVA_RUNTIME_JAR) }.existsOrNull()
?: getResourcePathForClass(StandardScriptTemplate::class.java).existsOrNull()
?: throw FileNotFoundException("Cannot find kotlin runtime jar, set KOTLIN_JAVA_RUNTIME_JAR property to proper location")
@@ -1,72 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.script.jsr223
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.KotlinVersion
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.script.StandardScriptDefinition
import org.jetbrains.kotlin.utils.PathUtil
import javax.script.ScriptEngine
import javax.script.ScriptEngineFactory
@Suppress("unused") // used in javax.script.ScriptEngineFactory META-INF file
class KotlinJsr232StandardScriptEngineFactory: ScriptEngineFactory {
override fun getLanguageName(): String = "kotlin"
override fun getLanguageVersion(): String = KotlinVersion.VERSION
override fun getEngineName(): String = "kotlin"
override fun getEngineVersion(): String = KotlinVersion.VERSION
override fun getExtensions(): List<String> = listOf("kts")
override fun getMimeTypes(): List<String> = listOf("text/x-kotlin")
override fun getNames(): List<String> = listOf("kotlin")
override fun getScriptEngine(): ScriptEngine =
KotlinJsr232ScriptEngine(
Disposer.newDisposable(),
this,
StandardScriptDefinition,
CompilerConfiguration().apply {
addJvmClasspathRoots(PathUtil.getJdkClassesRoots())
addJvmClasspathRoots(PathUtil.getKotlinPathsForCompiler().let { listOf(it.runtimePath, it.reflectPath) })
// TODO: addJvmClasspathRoots(config.classpath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
put(JVMConfigurationKeys.INCLUDE_RUNTIME, true)
},
Thread.currentThread().contextClassLoader)
override fun getOutputStatement(toDisplay: String?): String = "print(\"$toDisplay\")"
override fun getMethodCallSyntax(obj: String, m: String, vararg args: String): String = "$obj.$m(${args.joinToString()})"
override fun getProgram(vararg statements: String): String {
val sep = System.getProperty("line.separator")
return statements.joinToString(sep) + sep
}
override fun getParameter(key: String?): Any? =
when (key) {
ScriptEngine.NAME -> engineName
ScriptEngine.LANGUAGE -> languageName
ScriptEngine.LANGUAGE_VERSION -> languageVersion
ScriptEngine.ENGINE -> engineName
ScriptEngine.ENGINE_VERSION -> engineVersion
else -> null
}
}
@@ -116,7 +116,7 @@ done
try { try {
val configuration = CompilerConfiguration().apply { val configuration = CompilerConfiguration().apply {
addJvmClasspathRoots(PathUtil.getJdkClassesRoots()) addJvmClasspathRoots(PathUtil.getJdkClassesRoots())
val rtJar = System.getProperty("runtimeJar") val rtJar = System.getProperty("KOTLIN_JAVA_RUNTIME_JAR")
Assert.assertNotNull(rtJar) Assert.assertNotNull(rtJar)
addJvmClasspathRoot(File(rtJar)) addJvmClasspathRoot(File(rtJar))
put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)