Compare commits

...

5 Commits

Author SHA1 Message Date
Ilya Chernikov
c063c04b4a ~ idea jsr223 new 2020-02-14 10:44:36 +01:00
Ilya Chernikov
929f386f1c Add a new facade to the daemon for refinement callbacks 2020-02-14 10:44:36 +01:00
Ilya Chernikov
f2596ae975 Implement new scripting repl compiler in the daemon
without refinement yet
2020-02-14 10:44:35 +01:00
Ilya Chernikov
f52920360f Extract refinement interface in the scripting API
preparing for the script/repl compilation in the daemon
2020-02-14 10:44:34 +01:00
Ilya Chernikov
0630d08c39 Move jsr223 definitions to scripting-jvm...
for easier sharing with IDE modules that cannot tolerate cli compiler
dependencies
2020-02-14 10:44:34 +01:00
50 changed files with 1080 additions and 238 deletions

View File

@@ -54,6 +54,7 @@ dependencies {
testCompile(project(":compiler:ir.ir2cfg"))
testCompile(project(":compiler:ir.tree")) // used for deepCopyWithSymbols call that is removed by proguard from the compiler TODO: make it more straightforward
testCompile(project(":kotlin-scripting-compiler"))
testCompile(project(":kotlin-scripting-jvm-host"))
testCompile(project(":kotlin-script-util"))
testCompileOnly(projectRuntimeJar(":kotlin-daemon-client-new"))
testCompileOnly(project(":kotlin-reflect-api"))

View File

@@ -25,6 +25,8 @@ dependencies {
compileOnly(project(":compiler:incremental-compilation-impl"))
compileOnly(project(":daemon-common-new"))
compileOnly(project(":kotlin-scripting-jvm-host"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeJars("trove4j") }
@@ -32,6 +34,9 @@ dependencies {
embedded(project(":daemon-common")) { isTransitive = false }
embedded(project(":daemon-common-new")) { isTransitive = false }
embedded(project(":kotlin-scripting-common")) { isTransitive = false }
embedded(project(":kotlin-scripting-jvm")) { isTransitive = false }
embedded(project(":kotlin-scripting-jvm-host")) { isTransitive = false }
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) {
isTransitive = false
}

View File

@@ -21,11 +21,18 @@ import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.daemon.common.*
import java.io.File
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
// TODO: reduce number of ports used then SOCKET_ANY_FREE_PORT is passed (same problem with other calls)
open class KotlinRemoteReplCompilerClient(
protected val compileService: CompileService,
val sessionId: Int
) : ReplCompiler {
constructor(
compileService: CompileService,
clientAliveFlagFile: File?,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
@@ -33,22 +40,44 @@ open class KotlinRemoteReplCompilerClient(
templateClasspath: List<File>,
templateClassName: String,
port: Int = SOCKET_ANY_FREE_PORT
) : ReplCompiler {
val services = BasicCompilerServicesWithResultsFacadeServer(messageCollector, null, port)
val sessionId = compileService.leaseReplSession(
) : this(
compileService,
compileService.leaseReplSession(
clientAliveFlagFile?.absolutePath,
args,
CompilationOptions(
CompilerMode.NON_INCREMENTAL_COMPILER,
targetPlatform,
arrayOf(ReportCategory.COMPILER_MESSAGE.code, ReportCategory.DAEMON_MESSAGE.code, ReportCategory.EXCEPTION.code, ReportCategory.OUTPUT_MESSAGE.code),
ReportSeverity.INFO.code,
emptyArray()),
services,
makeCompilationOptions(targetPlatform),
BasicCompilerServicesWithResultsFacadeServer(messageCollector, null, port),
templateClasspath,
templateClassName
).get()
).get()
)
constructor(
compileService: CompileService,
clientAliveFlagFile: File?,
targetPlatform: CompileService.TargetPlatform,
args: Array<out String>,
messageCollector: MessageCollector,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade? = null,
port: Int = SOCKET_ANY_FREE_PORT
) : this(
compileService,
null.let {
val sess = compileService.leaseReplSession(
clientAliveFlagFile?.absolutePath,
args,
makeCompilationOptions(targetPlatform),
BasicCompilerServicesWithResultsFacadeServer(messageCollector, null, port),
scriptCompilationConfiguration,
scriptingHostConfiguration,
scriptCompilationConfigurationFacade ?: ScriptCompilationConfigurationFacadeServer(port = port)
)
val res = sess.get()
res
}
)
// dispose should be called at the end of the repl lifetime to free daemon repl session and appropriate resources
open fun dispose() {
@@ -69,3 +98,18 @@ open class KotlinRemoteReplCompilerClient(
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult =
compileService.replCompile(sessionId, state.asState(RemoteReplCompilerState::class.java).replStateFacade.getId(), codeLine).get()
}
private fun makeCompilationOptions(targetPlatform: CompileService.TargetPlatform): CompilationOptions {
return CompilationOptions(
CompilerMode.NON_INCREMENTAL_COMPILER,
targetPlatform,
arrayOf(
ReportCategory.COMPILER_MESSAGE.code,
ReportCategory.DAEMON_MESSAGE.code,
ReportCategory.EXCEPTION.code,
ReportCategory.OUTPUT_MESSAGE.code,
),
ReportSeverity.INFO.code,
emptyArray(),
)
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.client
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface
import org.jetbrains.kotlin.daemon.common.SOCKET_ANY_FREE_PORT
import org.jetbrains.kotlin.daemon.common.ScriptCompilationConfigurationFacade
import java.rmi.server.UnicastRemoteObject
import kotlin.script.experimental.api.*
import kotlin.script.experimental.util.PropertiesCollection
class ScriptCompilationConfigurationFacadeServer(
val refineImpl: ScriptCompilationConfigurationRefine = DirectScriptCompilationConfigurationRefine(),
port: Int = SOCKET_ANY_FREE_PORT
) :
ScriptCompilationConfigurationFacade,
UnicastRemoteObject(port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory) {
override fun refineConfiguration(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration> = runBlocking {
refineImpl(refiningKey, context)
}
}

View File

@@ -5,16 +5,19 @@
package org.jetbrains.kotlin.daemon.common.experimental
import kotlinx.coroutines.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.newSingleThreadContext
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.*
import org.jetbrains.kotlin.daemon.common.CompileService
import org.jetbrains.kotlin.daemon.common.CompilerServicesFacadeBase
import java.io.File
import java.util.logging.Logger
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
class CompileServiceClientSideImpl(
override val serverPort: Int,
@@ -112,6 +115,29 @@ class CompileServiceClientSideImpl(
return readMessage(id)
}
override suspend fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBaseAsync,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacadeAsync
): CompileService.CallResult<Int> {
val id = sendMessage(
LeaseReplSessionWithScriptingApiMessage(
aliveFlagPath,
compilerArguments,
compilationOptions,
servicesFacade,
scriptCompilationConfiguration,
scriptingHostConfiguration,
scriptCompilationConfigurationFacade
)
)
return readMessage(id)
}
// CompileService methods:
override suspend fun checkCompilerId(expectedCompilerId: CompilerId): Boolean {
@@ -341,6 +367,29 @@ class CompileServiceClientSideImpl(
)
}
class LeaseReplSessionWithScriptingApiMessage(
val aliveFlagPath: String?,
val compilerArguments: Array<out String>,
val compilationOptions: CompilationOptions,
val servicesFacade: CompilerServicesFacadeBaseAsync,
val scriptCompilationConfiguration: ScriptCompilationConfiguration,
val scriptingHostConfiguration: ScriptingHostConfiguration,
val scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacadeAsync
) : Server.Message<CompileServiceServerSide>() {
override suspend fun processImpl(server: CompileServiceServerSide, sendReply: (Any?) -> Unit) =
sendReply(
server.leaseReplSession(
aliveFlagPath,
compilerArguments,
compilationOptions,
servicesFacade,
scriptCompilationConfiguration,
scriptingHostConfiguration,
scriptCompilationConfigurationFacade
)
)
}
class ReleaseReplSessionMessage(val sessionId: Int) : Server.Message<CompileServiceServerSide>() {
override suspend fun processImpl(server: CompileServiceServerSide, sendReply: (Any?) -> Unit) =
sendReply(server.releaseReplSession(sessionId))

View File

@@ -8,16 +8,16 @@ package org.jetbrains.kotlin.daemon.common.experimental
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Client
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.DefaultClientRMIWrapper
import org.jetbrains.kotlin.daemon.common.*
import java.io.File
import java.io.Serializable
import java.rmi.NoSuchObjectException
import java.rmi.server.UnicastRemoteObject
import java.util.*
import java.util.logging.Logger
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
class CompileServiceRMIWrapper(val server: CompileServiceServerSide, daemonOptions: DaemonOptions, compilerId: CompilerId) :
CompileService {
@@ -174,6 +174,26 @@ class CompileServiceRMIWrapper(val server: CompileServiceServerSide, daemonOptio
)
}
override fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade
) = runBlocking {
server.leaseReplSession(
aliveFlagPath,
compilerArguments,
compilationOptions,
servicesFacade.toClient(),
scriptCompilationConfiguration,
scriptingHostConfiguration,
scriptCompilationConfigurationFacade.toClient()
)
}
override fun replCreateState(sessionId: Int) = runBlocking {
server.replCreateState(sessionId).toRMI()
}

View File

@@ -9,6 +9,7 @@ dependencies {
compile(project(":compiler:util"))
compile(project(":compiler:cli-common"))
compile(project(":kotlin-build-common"))
compile(project(":kotlin-scripting-common"))
compile(kotlinStdlib())
compileOnly(project(":js:js.frontend"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }

View File

@@ -16,11 +16,16 @@
package org.jetbrains.kotlin.daemon.common
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import java.io.File
import java.io.Serializable
import java.rmi.Remote
import java.rmi.RemoteException
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
interface CompileService : Remote {
@@ -202,6 +207,17 @@ interface CompileService : Remote {
templateClassName: String
): CallResult<Int>
@Throws(RemoteException::class)
fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade
): CallResult<Int>
@Throws(RemoteException::class)
fun replCreateState(sessionId: Int): CallResult<ReplStateFacade>

View File

@@ -8,6 +8,8 @@ import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import java.io.File
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
interface CompileServiceAsync {
@@ -57,6 +59,16 @@ interface CompileServiceAsync {
templateClassName: String
): CompileService.CallResult<Int>
suspend fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBaseAsync,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacadeAsync
): CompileService.CallResult<Int>
suspend fun replCreateState(sessionId: Int): CompileService.CallResult<ReplStateFacadeAsync>
suspend fun replCheck(

View File

@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.daemon.common
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import java.io.File
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
class CompileServiceAsyncWrapper(
val rmiCompileService: CompileService
@@ -45,6 +47,24 @@ class CompileServiceAsyncWrapper(
templateClassName
)
override suspend fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBaseAsync,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacadeAsync
) = rmiCompileService.leaseReplSession(
aliveFlagPath,
compilerArguments,
compilationOptions,
servicesFacade.toRMI(),
scriptCompilationConfiguration,
scriptingHostConfiguration,
scriptCompilationConfigurationFacade.toRMI()
)
override suspend fun replCreateState(sessionId: Int) =
rmiCompileService.replCreateState(sessionId).toClient()

View File

@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import java.io.File
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.ScriptingHostConfiguration
class CompileServiceClientRMIWrapper(
val asyncCompileService: CompileServiceAsync
@@ -103,7 +105,6 @@ class CompileServiceClientRMIWrapper(
)
}
override fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
@@ -122,6 +123,26 @@ class CompileServiceClientRMIWrapper(
)
}
override fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade
) = runBlocking {
asyncCompileService.leaseReplSession(
aliveFlagPath,
compilerArguments,
compilationOptions,
servicesFacade.toClient(),
scriptCompilationConfiguration,
scriptingHostConfiguration,
scriptCompilationConfigurationFacade.toClient()
)
}
override fun replCreateState(sessionId: Int) = runBlocking {
asyncCompileService.replCreateState(sessionId)
}.toRMI()

View File

@@ -0,0 +1,22 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.common
import java.rmi.Remote
import java.rmi.RemoteException
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.util.PropertiesCollection
interface ScriptCompilationConfigurationFacade : Remote {
@Throws(RemoteException::class)
fun refineConfiguration(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration>
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.common
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.util.PropertiesCollection
interface ScriptCompilationConfigurationFacadeAsync {
suspend fun refineConfiguration(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration>
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.common
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.util.PropertiesCollection
class ScriptCompilationConfigurationFacadeAsyncWrapper(val rmiScriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade) :
ScriptCompilationConfigurationFacadeAsync {
override suspend fun refineConfiguration(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
rmiScriptCompilationConfigurationFacade.refineConfiguration(refiningKey, context)
}
fun ScriptCompilationConfigurationFacade.toClient() = ScriptCompilationConfigurationFacadeAsyncWrapper(this)
fun CompileService.CallResult<ScriptCompilationConfigurationFacade>.toClient() = when (this) {
is CompileService.CallResult.Good -> CompileService.CallResult.Good(this.result.toClient())
is CompileService.CallResult.Dying -> this
is CompileService.CallResult.Error -> this
is CompileService.CallResult.Ok -> this
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.common
import kotlinx.coroutines.runBlocking
import java.io.Serializable
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.util.PropertiesCollection
class ScriptCompilationConfigurationFacadeRMIWrapper(val clientSide: ScriptCompilationConfigurationFacadeAsync) :
ScriptCompilationConfigurationFacade, Serializable {
override fun refineConfiguration(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
runBlocking { clientSide.refineConfiguration(refiningKey, context) }
}
fun ScriptCompilationConfigurationFacadeAsync.toRMI() = ScriptCompilationConfigurationFacadeRMIWrapper(this)
fun CompileService.CallResult<ScriptCompilationConfigurationFacadeAsync>.toRMI() = when (this) {
is CompileService.CallResult.Good -> CompileService.CallResult.Good(this.result.toRMI())
is CompileService.CallResult.Dying -> this
is CompileService.CallResult.Error -> this
is CompileService.CallResult.Ok -> this
}

View File

@@ -21,16 +21,12 @@ import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.JvmSourceRoot
import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
@@ -52,10 +48,8 @@ import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJs
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.rmi.NoSuchObjectException
@@ -71,6 +65,14 @@ import java.util.logging.Logger
import kotlin.concurrent.read
import kotlin.concurrent.schedule
import kotlin.concurrent.write
import kotlin.script.experimental.api.DirectScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler
import kotlin.script.experimental.util.PropertiesCollection
const val REMOTE_STREAM_BUFFER_SIZE = 4096
@@ -812,8 +814,9 @@ class CompileServiceImpl(
)
val messageCollector = KeepFirstErrorMessageCollector(compilerMessagesStream)
val repl = KotlinJvmReplService(
disposable, port, compilerId, templateClasspath, templateClassName,
messageCollector, operationsTracer
port,
makeLegacyReplCompiler(disposable, compilerId, templateClasspath, templateClassName, messageCollector),
operationsTracer
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
@@ -896,8 +899,48 @@ class CompileServiceImpl(
val disposable = Disposer.newDisposable()
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
val repl = KotlinJvmReplService(
disposable, port, compilerId, templateClasspath, templateClassName,
messageCollector, null
port,
makeLegacyReplCompiler(disposable, compilerId, templateClasspath, templateClassName, messageCollector),
null
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
CompileService.CallResult.Good(sessionId)
}
}
private class RemoteScriptConfigurationRefine(
val scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade
) : ScriptCompilationConfigurationRefine {
override suspend fun invoke(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
scriptCompilationConfigurationFacade.refineConfiguration(refiningKey, context)
}
override fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBase,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacade
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
if (compilationOptions.targetPlatform != CompileService.TargetPlatform.JVM)
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
else {
val disposable = Disposer.newDisposable()
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
val repl = KotlinJvmReplService(
port,
JvmReplCompiler(
scriptCompilationConfiguration, scriptingHostConfiguration,
RemoteScriptConfigurationRefine(scriptCompilationConfigurationFacade),
messageCollector, disposable
),
null
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
@@ -1154,7 +1197,7 @@ class CompileServiceImpl(
)
try {
val compileServiceReporter = DaemonMessageReporterPrintStreamAdapter(serviceOutputStream)
if (args.none())
if (args.isEmpty())
throw IllegalArgumentException("Error: empty arguments list.")
log.info("Starting compilation with args: " + args.joinToString(" "))
val exitCode = checkedCompile(compileServiceReporter, rpcProfiler) {

View File

@@ -41,55 +41,9 @@ import kotlin.concurrent.read
import kotlin.concurrent.write
abstract class KotlinJvmReplServiceBase(
disposable: Disposable,
val compilerId: CompilerId,
templateClasspath: List<File>,
templateClassName: String,
protected val messageCollector: MessageCollector
protected val replCompiler: ReplCompiler?
) : ReplCompileAction, ReplCheckAction, CreateReplStageStateAction {
private val log by lazy { Logger.getLogger("replService") }
protected val configuration = CompilerConfiguration().apply {
put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
addJvmClasspathRoots(PathUtil.kotlinPathsForCompiler.let { listOf(it.stdlibPath, it.reflectPath, it.scriptRuntimePath) })
addJvmClasspathRoots(templateClasspath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
)
configureScripting(compilerId)
}
protected val replCompiler: ReplCompiler? by lazy {
try {
val projectEnvironment =
KotlinCoreEnvironment.ProjectEnvironment(
disposable,
KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(disposable, configuration)
)
ReplFactoryExtension.registerExtensionPoint(projectEnvironment.project)
projectEnvironment.registerExtensionsFromPlugins(configuration)
val replFactories = ReplFactoryExtension.getInstances(projectEnvironment.project)
if (replFactories.isEmpty()) {
throw java.lang.IllegalStateException("no scripting plugin loaded")
} else if (replFactories.size > 1) {
throw java.lang.IllegalStateException("several scripting plugins loaded")
}
replFactories.first().makeReplCompiler(
templateClassName,
templateClasspath,
this::class.java.classLoader,
configuration,
projectEnvironment
)
} catch (ex: Throwable) {
messageCollector.report(CompilerMessageSeverity.ERROR, "Unable to construct repl compiler: ${ex.message}")
throw IllegalStateException("Unable to use scripting/REPL in the daemon: ${ex.message}", ex)
}
}
protected val statesLock = ReentrantReadWriteLock()
protected val stateIdCounter = AtomicInteger()
@@ -119,16 +73,59 @@ abstract class KotlinJvmReplServiceBase(
}
open class KotlinJvmReplService(
fun makeLegacyReplCompiler(
disposable: Disposable,
val portForServers: Int,
compilerId: CompilerId,
templateClasspath: List<File>,
templateClassName: String,
messageCollector: MessageCollector,
messageCollector: MessageCollector
): ReplCompiler? {
val configuration = CompilerConfiguration().apply {
put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
addJvmClasspathRoots(PathUtil.kotlinPathsForCompiler.let { listOf(it.stdlibPath, it.reflectPath, it.scriptRuntimePath) })
addJvmClasspathRoots(templateClasspath)
put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script")
languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
)
configureScripting(compilerId)
}
return try {
val projectEnvironment =
KotlinCoreEnvironment.ProjectEnvironment(
disposable,
KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(disposable, configuration)
)
ReplFactoryExtension.registerExtensionPoint(projectEnvironment.project)
projectEnvironment.registerExtensionsFromPlugins(configuration)
val replFactories = ReplFactoryExtension.getInstances(projectEnvironment.project)
if (replFactories.isEmpty()) {
throw java.lang.IllegalStateException("no scripting plugin loaded")
} else if (replFactories.size > 1) {
throw java.lang.IllegalStateException("several scripting plugins loaded")
}
replFactories.first().makeReplCompiler(
templateClassName,
templateClasspath,
KotlinJvmReplServiceBase::class.java.classLoader,
configuration,
projectEnvironment
)
} catch (ex: Throwable) {
messageCollector.report(CompilerMessageSeverity.ERROR, "Unable to construct repl compiler: ${ex.message}")
throw IllegalStateException("Unable to use scripting/REPL in the daemon: ${ex.message}", ex)
}
}
open class KotlinJvmReplService(
val portForServers: Int,
replCompiler: ReplCompiler?,
@Deprecated("drop it")
protected val operationsTracer: RemoteOperationsTracer?
) : KotlinJvmReplServiceBase(disposable, compilerId, templateClasspath, templateClassName, messageCollector) {
) : KotlinJvmReplServiceBase(replCompiler) {
override fun before(s: String) {
operationsTracer?.before(s)

View File

@@ -10,15 +10,13 @@ package org.jetbrains.kotlin.daemon.experimental
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import io.ktor.network.sockets.Socket
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.channels.consumeEach
import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
@@ -27,11 +25,11 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.CompileServiceImplBase
import org.jetbrains.kotlin.daemon.CompilerSelector
import org.jetbrains.kotlin.daemon.*
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.experimental.*
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.*
import org.jetbrains.kotlin.daemon.experimental.CompileServiceTaskScheduler.*
import org.jetbrains.kotlin.daemon.nowSeconds
import org.jetbrains.kotlin.daemon.report.experimental.CompileServicesFacadeMessageCollector
import org.jetbrains.kotlin.daemon.report.experimental.DaemonMessageReporterAsync
import org.jetbrains.kotlin.daemon.report.experimental.getICReporterAsync
@@ -49,8 +47,15 @@ import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.*
import org.jetbrains.kotlin.daemon.common.experimental.*
import io.ktor.network.sockets.*
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.daemon.EventManager
import org.jetbrains.kotlin.daemon.report.DaemonMessageReporter
import org.jetbrains.kotlin.daemon.*
import kotlin.script.experimental.api.DirectScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ScriptConfigurationRefinementContext
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler
import kotlin.script.experimental.util.PropertiesCollection
// TODO: this classes should replace their non-experimental versions eventually.
@@ -355,8 +360,48 @@ class CompileServiceServerSideImpl(
val messageCollector =
CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
val repl = KotlinJvmReplServiceAsync(
disposable, serverSocketWithPort, compilerId, templateClasspath, templateClassName,
messageCollector
serverSocketWithPort,
makeLegacyReplCompiler(disposable, compilerId, templateClasspath, templateClassName, messageCollector)
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
CompileService.CallResult.Good(sessionId)
}
}
private class RemoteScriptConfigurationRefine(
val scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacadeAsync
) : ScriptCompilationConfigurationRefine {
override suspend fun invoke(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
scriptCompilationConfigurationFacade.refineConfiguration(refiningKey, context)
}
override suspend fun leaseReplSession(
aliveFlagPath: String?,
compilerArguments: Array<out String>,
compilationOptions: CompilationOptions,
servicesFacade: CompilerServicesFacadeBaseAsync,
scriptCompilationConfiguration: ScriptCompilationConfiguration,
scriptingHostConfiguration: ScriptingHostConfiguration,
scriptCompilationConfigurationFacade: ScriptCompilationConfigurationFacadeAsync
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
if (compilationOptions.targetPlatform != CompileService.TargetPlatform.JVM)
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
else {
val disposable = Disposer.newDisposable()
val messageCollector =
CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
val repl = KotlinJvmReplServiceAsync(
serverSocketWithPort,
JvmReplCompiler(
scriptCompilationConfiguration, scriptingHostConfiguration,
RemoteScriptConfigurationRefine(scriptCompilationConfigurationFacade),
messageCollector, disposable
)
)
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))

View File

@@ -5,27 +5,20 @@
package org.jetbrains.kotlin.daemon.experimental
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.IReplStageState
import org.jetbrains.kotlin.cli.common.repl.ReplCompiler
import org.jetbrains.kotlin.daemon.KotlinJvmReplServiceBase
import org.jetbrains.kotlin.daemon.common.CompileService
import org.jetbrains.kotlin.daemon.common.CompilerId
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.ServerSocketWrapper
import org.jetbrains.kotlin.daemon.getValidId
import java.io.File
import java.util.*
import kotlin.concurrent.read
import kotlin.concurrent.write
open class KotlinJvmReplServiceAsync(
disposable: Disposable,
val portForServers: ServerSocketWrapper,
compilerId: CompilerId,
templateClasspath: List<File>,
templateClassName: String,
messageCollector: MessageCollector
) : KotlinJvmReplServiceBase(disposable, compilerId, templateClasspath, templateClassName, messageCollector) {
replCompiler: ReplCompiler?
) : KotlinJvmReplServiceBase(replCompiler) {
protected val states = WeakHashMap<RemoteReplStateFacadeServerSide, Boolean>() // used as (missing) WeakHashSet

View File

@@ -42,10 +42,16 @@ import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
import kotlin.script.dependencies.Environment
import kotlin.script.dependencies.ScriptContents
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult
import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.asSuccess
import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import kotlin.script.experimental.jvm.updateClasspath
import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator
import kotlin.script.templates.ScriptTemplateDefinition
import kotlin.test.fail
@@ -813,6 +819,28 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
}
}
fun testDaemonReplNewLocalEvalNoParams() {
withDaemon(compilerWithScriptingId) { daemon ->
val hostConfiguration = defaultJvmScriptingHostConfiguration
val repl = KotlinRemoteReplCompilerClient(
daemon, null, CompileService.TargetPlatform.JVM,
emptyArray(),
TestMessageCollector(),
createCompilationConfigurationFromTemplate(
KotlinType(ScriptWithNoParam::class),
hostConfiguration,
CompilerDaemonTest::class
),
hostConfiguration
)
val localEvaluator = JvmReplEvaluator(ScriptEvaluationConfiguration())
doReplTestWithLocalEval(repl, localEvaluator)
repl.dispose()
}
}
fun testDaemonReplLocalEvalStandardTemplate() {
withDaemon(compilerWithScriptingId) { daemon ->
val repl = KotlinRemoteReplCompilerClient(daemon, null, CompileService.TargetPlatform.JVM, emptyArray(),
@@ -1011,6 +1039,7 @@ open class TestKotlinScriptDummyDependenciesResolver : DependenciesResolver {
}
}
@KotlinScript(compilationConfiguration = TestKotlinScriptDummyCompilationConfiguration::class)
@ScriptTemplateDefinition(resolver = TestKotlinScriptDummyDependenciesResolver::class)
abstract class ScriptWithNoParam
@@ -1024,6 +1053,13 @@ internal fun classpathFromClassloader(): List<File> {
) + additionalClasspath
}
object TestKotlinScriptDummyCompilationConfiguration : ScriptCompilationConfiguration(
{
defaultImports("org.jetbrains.kotlin.scripts.DependsOn", "org.jetbrains.kotlin.scripts.DependsOnTwo")
updateClasspath(classpathFromClassloader())
}
)
internal fun URL.toFile() =
try {
File(toURI().schemeSpecificPart)

View File

@@ -71,6 +71,8 @@ dependencies {
compile(project(":plugins:uast-kotlin"))
compile(project(":plugins:uast-kotlin-idea"))
compile(project(":kotlin-script-util")) { isTransitive = false }
compile(project(":kotlin-scripting-common"))
compile(project(":kotlin-scripting-jvm"))
compile(project(":kotlin-scripting-intellij"))
compile(project(":compiler:backend.jvm")) // Do not delete, for Pill

View File

@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.LegacyResolverWrapper
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import kotlin.script.experimental.api.DirectScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.asDiagnostics
import kotlin.script.experimental.api.valueOrNull
@@ -58,7 +59,7 @@ open class DefaultScriptConfigurationLoader(val project: Project) : ScriptConfig
val inputs = getInputsStamp(vFile, file)
val scriptingApiResult = try {
refineScriptCompilationConfiguration(
KtFileScriptSource(file), scriptDefinition, file.project
KtFileScriptSource(file), scriptDefinition, file.project, DirectScriptCompilationConfigurationRefine()
)
} catch (e: Throwable) {
if (e is ControlFlowException) throw e

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.jsr223
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.cli.common.repl.*
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.write
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
import kotlin.script.experimental.jvm.baseClassLoader
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
import kotlin.script.experimental.jvm.jvm
/**
* REPL Evaluation wrapper for "legacy" REPL APIs defined in the org.jetbrains.kotlin.cli.common.repl package
*/
class JvmReplEvaluator(
val baseScriptEvaluationConfiguration: ScriptEvaluationConfiguration,
val scriptEvaluator: ScriptEvaluator = BasicJvmScriptEvaluator()
) : ReplEvaluator {
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> =
JvmReplEvaluatorState(baseScriptEvaluationConfiguration, lock)
override fun eval(
state: IReplStageState<*>,
compileResult: ReplCompileResult.CompiledClasses,
scriptArgs: ScriptArgsWithTypes?,
invokeWrapper: InvokeWrapper?
): ReplEvalResult = state.lock.write {
val evalState = state.asState(JvmReplEvaluatorState::class.java)
val history = evalState.history as ReplStageHistoryWithReplace
val compiledScript = (compileResult.data as? KJvmCompiledScript<*>)
?: return ReplEvalResult.Error.CompileTime("Unable to access compiled script: ${compileResult.data}")
val lastSnippetClass = history.peek()?.item?.first
val historyBeforeSnippet = history.previousItems(compileResult.lineId).map { it.second }.toList()
val currentConfiguration = ScriptEvaluationConfiguration(baseScriptEvaluationConfiguration) {
if (historyBeforeSnippet.isNotEmpty()) {
previousSnippets.put(historyBeforeSnippet)
}
if (lastSnippetClass != null) {
jvm {
baseClassLoader(lastSnippetClass.java.classLoader)
}
}
if (scriptArgs != null) {
constructorArgs(*scriptArgs.scriptArgs)
}
}
val res = runBlocking { scriptEvaluator(compiledScript, currentConfiguration) }
when (res) {
is ResultWithDiagnostics.Success -> {
when (val retVal = res.value.returnValue) {
is ResultValue.Error -> {
history.replaceOrPush(compileResult.lineId, retVal.scriptClass to null)
ReplEvalResult.Error.Runtime(
retVal.error.message ?: "unknown error",
(retVal.error as? Exception) ?: (retVal.wrappingException as? Exception)
)
}
is ResultValue.Value -> {
history.replaceOrPush(compileResult.lineId, retVal.scriptClass to retVal.scriptInstance)
ReplEvalResult.ValueResult(retVal.name, retVal.value, retVal.type)
}
is ResultValue.Unit -> {
history.replaceOrPush(compileResult.lineId, retVal.scriptClass to retVal.scriptInstance)
ReplEvalResult.UnitResult()
}
else -> throw IllegalStateException("Unexpected snippet result value $retVal")
}
}
else ->
ReplEvalResult.Error.Runtime(
res.reports.joinToString("\n") { it.message + (it.exception?.let { e -> ": $e" } ?: "") },
res.reports.find { it.exception != null }?.exception as? Exception
)
}
}
}
open class JvmReplEvaluatorState(
scriptEvaluationConfiguration: ScriptEvaluationConfiguration,
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) : IReplStageState<Pair<KClass<*>?, Any?>> {
override val history: IReplStageHistory<Pair<KClass<*>?, Any?>> = ReplStageHistoryWithReplace(lock)
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
}
open class ReplStageHistoryWithReplace<T>(lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : BasicReplStageHistory<T>(lock) {
fun replace(id: ILineId, item: T): Boolean = lock.write {
for (idx in indices) {
if (get(idx).id == id) {
set(idx, ReplHistoryRecord(id, item))
return true
}
}
return false
}
fun replaceOrPush(id: ILineId, item: T) {
if (!replace(id, item)) {
tryResetTo(id)
push(id, item)
}
}
fun previousItems(id: ILineId): Sequence<T> = asSequence().takeWhile { it.id.no < id.no }.map { it.item }
}

View File

@@ -20,30 +20,63 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
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.KotlinRemoteReplCompilerClient
import org.jetbrains.kotlin.daemon.client.*
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.utils.KotlinPaths
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.util.concurrent.locks.ReentrantReadWriteLock
import javax.script.ScriptContext
import javax.script.ScriptEngineFactory
import javax.script.ScriptException
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.host.withDefaultsFrom
import kotlin.script.experimental.jsr223.defs.getScriptContext
import kotlin.script.experimental.jsr223.defs.jsr223
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
// TODO: need to manage resources here, i.e. call replCompiler.dispose when engine is collected
class KotlinJsr223JvmScriptEngine4Idea(
factory: ScriptEngineFactory,
templateClasspath: List<File>,
templateClassName: String,
private val getScriptArgs: (ScriptContext, Array<out KClass<out Any>>?) -> ScriptArgsWithTypes?,
private val scriptArgsTypes: Array<out KClass<out Any>>?
baseCompilationConfiguration: ScriptCompilationConfiguration,
baseEvaluationConfiguration: ScriptEvaluationConfiguration,
val getScriptArgs: (context: ScriptContext) -> ScriptArgsWithTypes?
) : KotlinJsr223JvmScriptEngineBase(factory) {
@Volatile
private var lastScriptContext: ScriptContext? = null
val jsr223HostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) {
jsr223 {
getScriptContext { lastScriptContext ?: getContext() }
}
}
val compilationConfiguration by lazy {
ScriptCompilationConfiguration(baseCompilationConfiguration) {
hostConfiguration.update { it.withDefaultsFrom(jsr223HostConfiguration) }
repl {
// Snippet classes should be named uniquely, to avoid classloading clashes in the "eval in eval" scenario
// TODO: consider applying the logic for any REPL, alternatively - develop other naming scheme to avoid clashes
makeSnippetIdentifier { configuration, snippetId ->
val scriptContext: ScriptContext? = configuration[ScriptCompilationConfiguration.jsr223.getScriptContext]?.invoke()
val engineState = scriptContext?.let {
it.getBindings(ScriptContext.ENGINE_SCOPE)?.get(KOTLIN_SCRIPT_STATE_BINDINGS_KEY)
}
if (engineState == null) makeDefaultSnippetIdentifier(snippetId)
else "ScriptingHost${System.identityHashCode(engineState).toString(16)}_${makeDefaultSnippetIdentifier(snippetId)}"
}
}
}
}
val evaluationConfiguration by lazy {
ScriptEvaluationConfiguration(baseEvaluationConfiguration) {
hostConfiguration.update { it.withDefaultsFrom(jsr223HostConfiguration) }
}
}
private val daemon by lazy {
val classPath = PathUtil.kotlinPathsForIdeaPlugin.classPath(KotlinPaths.ClassPaths.CompilerWithScripting)
assert(classPath.all { it.exists() })
@@ -73,16 +106,16 @@ class KotlinJsr223JvmScriptEngine4Idea(
CompileService.TargetPlatform.JVM,
emptyArray(),
messageCollector,
templateClasspath,
templateClassName
compilationConfiguration,
jsr223HostConfiguration,
ScriptCompilationConfigurationFacadeServer()
)
}
override fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? =
getScriptArgs(getContext(), scriptArgsTypes)
override fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes? = getScriptArgs(getContext())
private val localEvaluator: ReplFullEvaluator by lazy {
GenericReplCompilingEvaluator(replCompiler, templateClasspath, Thread.currentThread().contextClassLoader)
private val localEvaluator by lazy {
GenericReplCompilingEvaluatorBase(replCompiler, JvmReplEvaluator(evaluationConfiguration))
}
override val replEvaluator: ReplFullEvaluator get() = localEvaluator

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.jsr223
import javax.script.Bindings
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.jsr223.defs.KotlinJsr223DefaultScriptCompilationConfiguration
import kotlin.script.experimental.jsr223.defs.KotlinJsr223DefaultScriptEvaluationConfiguration
import kotlin.script.templates.standard.ScriptTemplateWithBindings
@Suppress("unused")
@KotlinScript(
compilationConfiguration = KotlinJsr223DefaultScriptCompilationConfiguration::class,
evaluationConfiguration = KotlinJsr223DefaultScriptEvaluationConfiguration::class
)
abstract class KotlinJsr223Script4Idea(val jsr223Bindings: Bindings) : ScriptTemplateWithBindings(jsr223Bindings)

View File

@@ -7,21 +7,57 @@ package org.jetbrains.kotlin.jsr223
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
import org.jetbrains.kotlin.script.util.KotlinJars
import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContextOrStlib
import java.io.File
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.experimental.api.KotlinType
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate
import kotlin.script.experimental.host.createEvaluationConfigurationFromTemplate
import kotlin.script.experimental.jsr223.defs.KotlinJsr223DefaultScript
import kotlin.script.experimental.jvm.JvmScriptCompilationConfigurationBuilder
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvm.updateClasspath
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
@Suppress("unused") // used in javax.script.ScriptEngineFactory META-INF file
class KotlinJsr223StandardScriptEngineFactory4Idea : KotlinJsr223JvmScriptEngineFactoryBase() {
private val scriptingHostConfiguration = defaultJvmScriptingHostConfiguration
private val compilationConfiguration =
createCompilationConfigurationFromTemplate(KotlinType(KotlinJsr223DefaultScript::class), scriptingHostConfiguration)
private val evaluationConfiguration =
createEvaluationConfigurationFromTemplate(KotlinType(KotlinJsr223DefaultScript::class), scriptingHostConfiguration)
private var lastClassLoader: ClassLoader? = null
private var lastClassPath: List<File>? = null
@Synchronized
protected fun JvmScriptCompilationConfigurationBuilder.dependenciesFromCurrentContext() {
val currentClassLoader = Thread.currentThread().contextClassLoader
val classPath = if (lastClassLoader == null || lastClassLoader != currentClassLoader) {
scriptCompilationClasspathFromContext(
classLoader = currentClassLoader,
wholeClasspath = true,
unpackJarCollections = true
).also {
lastClassLoader = currentClassLoader
lastClassPath = it
}
} else lastClassPath!!
updateClasspath(classPath)
}
override fun getScriptEngine(): ScriptEngine =
KotlinJsr223JvmScriptEngine4Idea(
this,
scriptCompilationClasspathFromContextOrStlib(wholeClasspath = true) + KotlinJars.kotlinScriptStandardJars,
"kotlin.script.templates.standard.ScriptTemplateWithBindings",
{ ctx, argTypes -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), argTypes ?: emptyArray()) },
arrayOf(Map::class)
)
ScriptCompilationConfiguration(compilationConfiguration) {
jvm {
dependenciesFromCurrentContext()
}
},
evaluationConfiguration
) { ScriptArgsWithTypes(arrayOf(it.getBindings(ScriptContext.ENGINE_SCOPE).orEmpty()), arrayOf(Bindings::class)) }
}

View File

@@ -5,10 +5,12 @@
package org.jetbrains.kotlin.idea.repl
import com.intellij.openapi.util.io.FileUtil
import com.intellij.testFramework.PlatformTestCase
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
import javax.script.ScriptContext
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
@@ -27,7 +29,7 @@ class IdeaJsr223Test : PlatformTestCase() {
assertNotNull(engine)
val res0 = assertFails { engine.eval("val x =") }
assertTrue("Unexpected check results: $res0", (res0 as? ScriptException)?.message?.contains("incomplete code") ?: false)
assertTrue("Unexpected check results: $res0", (res0 as? ScriptException)?.message?.contains("Expecting an expression") ?: false)
val res1 = engine.eval("val x = 5\nval y = listOf(x)")
assertNull("Unexpected eval result: $res1", res1)

View File

@@ -92,7 +92,7 @@ data class ScriptDiagnostic(
/**
* The result wrapper with diagnostics container
*/
sealed class ResultWithDiagnostics<out R> {
sealed class ResultWithDiagnostics<out R> : Serializable {
/**
* The diagnostic reports container
*/
@@ -115,6 +115,11 @@ sealed class ResultWithDiagnostics<out R> {
) : ResultWithDiagnostics<Nothing>() {
constructor(vararg reports: ScriptDiagnostic) : this(reports.asList())
}
companion object {
@JvmStatic
private val serialVersionUID = 0L
}
}
/**

View File

@@ -57,7 +57,9 @@ typealias MakeSnippetIdentifier = (ScriptCompilationConfiguration, ReplSnippetId
val ReplScriptCompilationConfigurationKeys.makeSnippetIdentifier by PropertiesCollection.key<MakeSnippetIdentifier>(
{ _, snippetId ->
makeDefaultSnippetIdentifier(snippetId)
})
},
isTransient = true
)
fun makeDefaultSnippetIdentifier(snippetId: ReplSnippetId) =
"Line_${snippetId.no}${if (snippetId.generation > REPL_SNIPPET_FIRST_GEN) "_gen_${snippetId.generation}" else ""}"

View File

@@ -259,50 +259,6 @@ data class RefineConfigurationOnAnnotationsData(
}
fun ScriptCompilationConfiguration.refineBeforeParsing(
script: SourceCode,
collectedData: ScriptCollectedData? = null
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
simpleRefineImpl(ScriptCompilationConfiguration.refineConfigurationBeforeParsing) { config, refineData ->
refineData.handler.invoke(ScriptConfigurationRefinementContext(script, config, collectedData))
}
fun ScriptCompilationConfiguration.refineOnAnnotations(
script: SourceCode,
collectedData: ScriptCollectedData
): ResultWithDiagnostics<ScriptCompilationConfiguration> {
val foundAnnotationNames = collectedData[ScriptCollectedData.foundAnnotations]?.mapTo(HashSet()) { it.annotationClass.java.name }
if (foundAnnotationNames.isNullOrEmpty()) return this.asSuccess()
val thisResult: ResultWithDiagnostics<ScriptCompilationConfiguration> = this.asSuccess()
return this[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]
?.fold(thisResult) { config, (annotations, handler) ->
config.onSuccess {
// checking that the collected data contains expected annotations
if (annotations.none { foundAnnotationNames.contains(it.typeName) }) it.asSuccess()
else handler.invoke(ScriptConfigurationRefinementContext(script, it, collectedData))
}
} ?: thisResult
}
fun ScriptCompilationConfiguration.refineBeforeCompiling(
script: SourceCode,
collectedData: ScriptCollectedData? = null
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
simpleRefineImpl(ScriptCompilationConfiguration.refineConfigurationBeforeCompiling) { config, refineData ->
refineData.handler.invoke(ScriptConfigurationRefinementContext(script, config, collectedData))
}
internal inline fun <Configuration: PropertiesCollection, RefineData> Configuration.simpleRefineImpl(
key: PropertiesCollection.Key<List<RefineData>>,
refineFn: (Configuration, RefineData) -> ResultWithDiagnostics<Configuration>
): ResultWithDiagnostics<Configuration> = (
this[key]
?.fold(this) { config, refineData ->
refineFn(config, refineData).valueOr { return it }
} ?: this
).asSuccess()
/**
* The functional interface to the script compiler
*/

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.script.experimental.api
import kotlinx.coroutines.runBlocking
import kotlin.script.experimental.util.PropertiesCollection
interface ScriptCompilationConfigurationRefine {
suspend operator fun invoke(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration>
}
class DirectScriptCompilationConfigurationRefine : ScriptCompilationConfigurationRefine {
override suspend operator fun invoke(
refiningKey: PropertiesCollection.Key<*>,
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration> = when (refiningKey) {
ScriptCompilationConfiguration.refineConfigurationBeforeParsing ->
context.compilationConfiguration
.simpleRefineImpl(ScriptCompilationConfiguration.refineConfigurationBeforeParsing) { config, refineData ->
refineData.handler.invoke(ScriptConfigurationRefinementContext(context.script, config, context.collectedData))
}
ScriptCompilationConfiguration.refineConfigurationOnAnnotations -> {
val foundAnnotationNames = context.collectedData?.get(ScriptCollectedData.foundAnnotations)
?.mapTo(HashSet()) { it.annotationClass.java.name }
if (foundAnnotationNames.isNullOrEmpty()) context.compilationConfiguration.asSuccess()
else {
val thisResult: ResultWithDiagnostics<ScriptCompilationConfiguration> = context.compilationConfiguration.asSuccess()
context.compilationConfiguration[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]
?.fold(thisResult) { config, (annotations, handler) ->
config.onSuccess {
// checking that the collected data contains expected annotations
if (annotations.none { foundAnnotationNames.contains(it.typeName) }) it.asSuccess()
else handler.invoke(
ScriptConfigurationRefinementContext(context.script, it, context.collectedData)
)
}
} ?: thisResult
}
}
ScriptCompilationConfiguration.refineConfigurationBeforeCompiling ->
context.compilationConfiguration
.simpleRefineImpl(ScriptCompilationConfiguration.refineConfigurationBeforeCompiling) { config, refineData ->
refineData.handler.invoke(ScriptConfigurationRefinementContext(context.script, config, context.collectedData))
}
else -> ResultWithDiagnostics
.Failure("Unknown refining key $refiningKey".asErrorDiagnostics())
}
}
@Suppress("unused") // left for API compatibility
@Deprecated("Use ScriptCompilationConfigurationRefine implementations directly")
fun ScriptCompilationConfiguration.refineBeforeParsing(
script: SourceCode,
collectedData: ScriptCollectedData? = null,
refine: ScriptCompilationConfigurationRefine = DirectScriptCompilationConfigurationRefine()
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
runBlocking {
refine(
ScriptCompilationConfiguration.refineConfigurationBeforeParsing,
ScriptConfigurationRefinementContext(script, this@refineBeforeParsing, collectedData)
)
}
@Suppress("unused") // left for API compatibility
@Deprecated("Use ScriptCompilationConfigurationRefine implementations directly")
fun ScriptCompilationConfiguration.refineOnAnnotations(
script: SourceCode,
collectedData: ScriptCollectedData,
refine: ScriptCompilationConfigurationRefine = DirectScriptCompilationConfigurationRefine()
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
runBlocking {
refine(
ScriptCompilationConfiguration.refineConfigurationOnAnnotations,
ScriptConfigurationRefinementContext(script, this@refineOnAnnotations, collectedData)
)
}
@Suppress("unused") // left for API compatibility
@Deprecated("Use ScriptCompilationConfigurationRefine implementations directly")
fun ScriptCompilationConfiguration.refineBeforeCompiling(
script: SourceCode,
collectedData: ScriptCollectedData? = null,
refine: ScriptCompilationConfigurationRefine = DirectScriptCompilationConfigurationRefine()
): ResultWithDiagnostics<ScriptCompilationConfiguration> =
runBlocking {
refine(
ScriptCompilationConfiguration.refineConfigurationBeforeCompiling,
ScriptConfigurationRefinementContext(script, this@refineBeforeCompiling, collectedData)
)
}
internal inline fun <Configuration: PropertiesCollection, RefineData> Configuration.simpleRefineImpl(
key: PropertiesCollection.Key<List<RefineData>>,
refineFn: (Configuration, RefineData) -> ResultWithDiagnostics<Configuration>
): ResultWithDiagnostics<Configuration> = (
this[key]
?.fold(this) { config, refineData ->
refineFn(config, refineData).valueOr { return it }
} ?: this
).asSuccess()

View File

@@ -98,7 +98,12 @@ data class ScriptConfigurationRefinementContext(
val script: SourceCode,
val compilationConfiguration: ScriptCompilationConfiguration,
val collectedData: ScriptCollectedData? = null
)
) : Serializable {
companion object {
@JvmStatic
private val serialVersionUID = 0L
}
}
interface ScriptEvaluationContextDataKeys

View File

@@ -13,6 +13,7 @@ import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.dependencies
import kotlin.script.experimental.jsr223.defs.KotlinJsr223DefaultScript
import kotlin.script.experimental.jvm.JvmDependencyFromClassLoader
import kotlin.script.experimental.jvm.JvmScriptCompilationConfigurationBuilder
import kotlin.script.experimental.jvm.jvm

View File

@@ -145,7 +145,7 @@ fun evaluateInRepl(
limit: Int = 0
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
val replCompilerProxy =
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration, DirectScriptCompilationConfigurationRefine())
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
val replEvaluator = BasicJvmScriptEvaluator()

View File

@@ -12,6 +12,8 @@ import javax.script.ScriptEngineFactory
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.host.withDefaultsFrom
import kotlin.script.experimental.jsr223.defs.getScriptContext
import kotlin.script.experimental.jsr223.defs.jsr223
import kotlin.script.experimental.jvm.baseClassLoader
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import kotlin.script.experimental.jvm.jvm

View File

@@ -21,7 +21,8 @@ open class JvmScriptCompiler(
val hostConfiguration = baseHostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration)
val compilerProxy: ScriptCompilerProxy = compilerProxy ?: ScriptJvmCompilerIsolated(hostConfiguration)
val compilerProxy: ScriptCompilerProxy =
compilerProxy ?: ScriptJvmCompilerIsolated(hostConfiguration, DirectScriptCompilationConfigurationRefine())
override suspend operator fun invoke(
script: SourceCode,

View File

@@ -5,6 +5,8 @@
package kotlin.script.experimental.jvmhost.repl
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState
@@ -23,10 +25,25 @@ class JvmReplCompiler(
val scriptCompilationConfiguration: ScriptCompilationConfiguration,
val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
val replCompilerProxy: KJvmReplCompilerProxy = KJvmReplCompilerImpl(
hostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration)
hostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration),
DirectScriptCompilationConfigurationRefine(), null, null
)
) : ReplCompiler {
constructor(
scriptCompilationConfiguration: ScriptCompilationConfiguration,
hostConfiguration: ScriptingHostConfiguration,
compilationConfigurationRefine: ScriptCompilationConfigurationRefine,
parentMessageCollector: MessageCollector?,
disposable: Disposable?
) : this(
scriptCompilationConfiguration, hostConfiguration,
KJvmReplCompilerImpl(
hostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration),
compilationConfigurationRefine, parentMessageCollector, disposable
)
)
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JvmReplCompilerState(replCompilerProxy, lock)
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = state.lock.write {

View File

@@ -1,12 +1,10 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.script.experimental.jsr223
package kotlin.script.experimental.jsr223.defs
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_STATE_BINDINGS_KEY
import javax.script.Bindings
import javax.script.ScriptEngine
import kotlin.script.experimental.annotations.KotlinScript
@@ -14,11 +12,12 @@ import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
import kotlin.script.experimental.api.refineConfiguration
import kotlin.script.experimental.api.refineConfigurationBeforeEvaluate
import kotlin.script.experimental.jvmhost.jsr223.configureProvidedPropertiesFromJsr223Context
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
import kotlin.script.experimental.jvmhost.jsr223.jsr223
import kotlin.script.templates.standard.ScriptTemplateWithBindings
// TODO: find the way to share it with org.jetbrains.kotlin.cli.common.repl.*
private const val KOTLIN_SCRIPT_STATE_BINDINGS_KEY = "kotlin.script.state"
private const val KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY = "kotlin.script.engine"
@Suppress("unused")
@KotlinScript(
compilationConfiguration = KotlinJsr223DefaultScriptCompilationConfiguration::class,

View File

@@ -1,9 +1,9 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.script.experimental.jvmhost.jsr223
package kotlin.script.experimental.jsr223.defs
import javax.script.ScriptContext
import kotlin.script.experimental.api.*
@@ -20,7 +20,7 @@ open class Jsr223HostConfigurationBuilder : PropertiesCollection.Builder(),
val ScriptingHostConfigurationKeys.jsr223 get() = Jsr223HostConfigurationBuilder()
val Jsr223HostConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>()
val Jsr223HostConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>(isTransient = true)
interface Jsr223CompilationConfigurationKeys

View File

@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.script.experimental.jvmhost.jsr223
package kotlin.script.experimental.jsr223.defs
import javax.script.ScriptContext
import kotlin.script.experimental.api.*

View File

@@ -43,9 +43,18 @@ class BridgeDependenciesResolver(
val script = getScriptSource(scriptContents) ?: scriptContents.toScriptSource()
// old infrastructure is deprecated, therefore using direct refiner, to reduce noise
val refine = DirectScriptCompilationConfigurationRefine()
val refineResults =
scriptCompilationConfiguration.refineOnAnnotations(script, processedScriptData).onSuccess {
it.refineBeforeCompiling(script, processedScriptData)
refine(
ScriptCompilationConfiguration.refineConfigurationOnAnnotations,
ScriptConfigurationRefinementContext(script, scriptCompilationConfiguration, processedScriptData)
).onSuccess {
refine(
ScriptCompilationConfiguration.refineConfigurationBeforeCompiling,
ScriptConfigurationRefinementContext(script, it, processedScriptData)
)
}
val refinedConfiguration = when (refineResults) {

View File

@@ -27,9 +27,9 @@ import kotlin.script.experimental.jvm.*
import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity
import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition
import kotlin.script.experimental.jvmhost.CompiledScriptJarsCache
import kotlin.script.experimental.jvmhost.jsr223.configureProvidedPropertiesFromJsr223Context
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
import kotlin.script.experimental.jvmhost.jsr223.jsr223
import kotlin.script.experimental.jsr223.defs.configureProvidedPropertiesFromJsr223Context
import kotlin.script.experimental.jsr223.defs.importAllBindings
import kotlin.script.experimental.jsr223.defs.jsr223
@Suppress("unused")
@KotlinScript(

View File

@@ -13,6 +13,8 @@ import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.valueOrNull
import kotlin.script.experimental.dependencies.ScriptDependencies
@@ -36,6 +38,8 @@ open class ScriptDependenciesProvider constructor(
open fun getScriptConfiguration(file: KtFile): ScriptCompilationConfigurationWrapper? = getScriptConfigurationResult(file)?.valueOrNull()
open fun registerRefineCallback(target: ScriptCompilationConfiguration, callBack: ScriptCompilationConfigurationRefine) {}
companion object {
fun getInstance(project: Project): ScriptDependenciesProvider? =
ServiceManager.getService(project, ScriptDependenciesProvider::class.java)

View File

@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.withCorrectExtension
import java.io.File
import java.io.Serializable
import java.net.URL
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
@@ -54,10 +55,14 @@ internal fun VirtualFile.getAnnotationEntries(project: Project): Iterable<KtAnno
/**
* The implementation of the SourceCode for a script located in a virtual file
*/
open class VirtualFileScriptSource(val virtualFile: VirtualFile, private val preloadedText: String? = null) :
FileBasedScriptSource()
open class VirtualFileScriptSource(
@Transient
val virtualFile: VirtualFile,
private val preloadedText: String? = null
) :
FileBasedScriptSource(), Serializable
{
override val file: File get() = File(virtualFile.path)
override val file = File(virtualFile.path)
override val externalLocation: URL get() = URL(virtualFile.url)
override val text: String by lazy { preloadedText ?: virtualFile.inputStream.bufferedReader().readText() }
override val name: String? get() = virtualFile.name
@@ -67,13 +72,24 @@ open class VirtualFileScriptSource(val virtualFile: VirtualFile, private val pre
this === other || (other as? VirtualFileScriptSource)?.let { virtualFile == it.virtualFile } == true
override fun hashCode(): Int = virtualFile.hashCode()
companion object {
@JvmStatic
private val serialVersionUID = 0L
}
}
/**
* The implementation of the SourceCode for a script located in a KtFile
*/
open class KtFileScriptSource(val ktFile: KtFile, preloadedText: String? = null) :
VirtualFileScriptSource(ktFile.virtualFile ?: ktFile.originalFile.virtualFile, preloadedText) {
open class KtFileScriptSource(
@Transient
val ktFile: KtFile,
preloadedText: String? = null
) :
VirtualFileScriptSource(ktFile.virtualFile ?: ktFile.originalFile.virtualFile, preloadedText),
Serializable
{
override val text: String by lazy { preloadedText ?: ktFile.text }
override val name: String? get() = ktFile.name
@@ -215,7 +231,8 @@ typealias ScriptCompilationConfigurationResult = ResultWithDiagnostics<ScriptCom
fun refineScriptCompilationConfiguration(
script: SourceCode,
definition: ScriptDefinition,
project: Project
project: Project,
scriptCompilationConfigurationRefine: ScriptCompilationConfigurationRefine
): ScriptCompilationConfigurationResult {
// TODO: add location information on refinement errors
val ktFileSource = script.toKtFileSource(definition, project)
@@ -225,15 +242,24 @@ fun refineScriptCompilationConfiguration(
val collectedData =
getScriptCollectedData(ktFileSource.ktFile, compilationConfiguration, project, definition.contextClassLoader)
return compilationConfiguration.refineOnAnnotations(script, collectedData)
.onSuccess {
it.refineBeforeCompiling(script, collectedData)
}.onSuccess {
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
ktFileSource,
it.adjustByDefinition(definition)
).asSuccess()
return runBlocking {
scriptCompilationConfigurationRefine(
ScriptCompilationConfiguration.refineConfigurationOnAnnotations,
ScriptConfigurationRefinementContext(script, compilationConfiguration, collectedData)
)
}.onSuccess {
runBlocking {
scriptCompilationConfigurationRefine(
ScriptCompilationConfiguration.refineConfigurationBeforeCompiling,
ScriptConfigurationRefinementContext(script, it, collectedData)
)
}
}.onSuccess {
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(
ktFileSource,
it.adjustByDefinition(definition)
).asSuccess()
}
} else {
val file = script.getVirtualFile(definition)
val scriptContents =

View File

@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerFromEnvironment
import kotlin.script.experimental.api.DirectScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
import kotlin.script.experimental.api.ScriptEvaluator
import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
@@ -43,7 +44,7 @@ class JvmCliScriptEvaluationExtension : AbstractScriptEvaluationExtension() {
}
override fun createScriptCompiler(environment: KotlinCoreEnvironment): ScriptCompilerProxy {
return ScriptJvmCompilerFromEnvironment(environment)
return ScriptJvmCompilerFromEnvironment(environment, DirectScriptCompilationConfigurationRefine())
}
override fun isAccepted(arguments: CommonCompilerArguments): Boolean =

View File

@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.scripting.compiler.plugin.definitions
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
@@ -15,11 +14,13 @@ import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
import java.io.File
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
import kotlin.script.experimental.api.ResultWithDiagnostics
import kotlin.script.experimental.api.DirectScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.baseClass
class CliScriptDependenciesProvider(project: Project) : ScriptDependenciesProvider(project) {
private val cacheLock = ReentrantReadWriteLock()
@@ -29,6 +30,19 @@ class CliScriptDependenciesProvider(project: Project) : ScriptDependenciesProvid
calculateRefinedConfiguration(file)
}
// keeping the same fifo logic in ScriptDefinitionProvider
private val scriptCompilationConfigurationRefines = ArrayList<Pair<String, ScriptCompilationConfigurationRefine>>()
private val defaultScriptCompilationConfigurationRefine by lazy {
DirectScriptCompilationConfigurationRefine()
}
override fun registerRefineCallback(target: ScriptCompilationConfiguration, callBack: ScriptCompilationConfigurationRefine) {
synchronized(this) {
scriptCompilationConfigurationRefines.add(target[ScriptCompilationConfiguration.baseClass]!!.typeName to callBack)
}
}
private fun calculateRefinedConfiguration(file: KtFile): ScriptCompilationConfigurationResult? {
val path = file.virtualFilePath
val cached = cache[path]
@@ -36,7 +50,15 @@ class CliScriptDependenciesProvider(project: Project) : ScriptDependenciesProvid
else {
val scriptDef = file.findScriptDefinition()
if (scriptDef != null) {
val result = refineScriptCompilationConfiguration(KtFileScriptSource(file), scriptDef, project)
val refineCallback = synchronized(this) {
val id = scriptDef.definitionId
scriptCompilationConfigurationRefines.find { it.first == id }?.second
?: defaultScriptCompilationConfigurationRefine
}
val result = refineScriptCompilationConfiguration(
KtFileScriptSource(file), scriptDef, project, refineCallback
)
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file.virtualFile, result.reports)

View File

@@ -9,6 +9,7 @@ import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageCollectorBasedReporter
import org.jetbrains.kotlin.cli.common.repl.IReplStageHistory
import org.jetbrains.kotlin.cli.common.repl.LineId
@@ -25,17 +26,26 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.ScriptingHostConfiguration
class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvmReplCompilerProxy {
class KJvmReplCompilerImpl(
val hostConfiguration: ScriptingHostConfiguration,
val compilationConfigurationRefine: ScriptCompilationConfigurationRefine,
val parentMessageCollector: MessageCollector? = null,
val externalDisposable: Disposable? = null
) : KJvmReplCompilerProxy {
override fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation {
val context = withMessageCollectorAndDisposable(disposeOnSuccess = false) { messageCollector, disposable ->
createIsolatedCompilationContext(
scriptCompilationConfiguration,
hostConfiguration,
messageCollector,
disposable
).asSuccess()
}.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") }
val context =
withMessageCollectorAndDisposable(
disposeOnSuccess = false, parentMessageCollector = parentMessageCollector, externalDisposable = externalDisposable
) { messageCollector, disposable ->
createIsolatedCompilationContext(
scriptCompilationConfiguration,
hostConfiguration,
messageCollector,
disposable,
compilationConfigurationRefine
).asSuccess()
}.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") }
return ReplCompilationState(context)
}
@@ -44,7 +54,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
scriptCompilationConfiguration: ScriptCompilationConfiguration,
project: Project
): ResultWithDiagnostics<Boolean> =
withMessageCollector(script) { messageCollector ->
withMessageCollector(script, parentMessageCollector) { messageCollector ->
val ktFile = getScriptKtFile(
script,
scriptCompilationConfiguration,
@@ -70,7 +80,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
// TODO: replace history with some interface based on CompiledScript
history: IReplStageHistory<ScriptDescriptor>
): ResultWithDiagnostics<CompiledScript<*>> =
withMessageCollector(snippet) { messageCollector ->
withMessageCollector(snippet, parentMessageCollector) { messageCollector ->
val context = (compilationState as? ReplCompilationState)?.context
?: return failure(

View File

@@ -4,16 +4,14 @@
*/
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -32,7 +30,10 @@ import kotlin.script.experimental.jvm.compilationCache
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
import kotlin.script.experimental.jvm.jvm
class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguration) : ScriptCompilerProxy {
class ScriptJvmCompilerIsolated(
val hostConfiguration: ScriptingHostConfiguration,
val scriptCompilationConfigurationRefine: ScriptCompilationConfigurationRefine
) : ScriptCompilerProxy {
override fun compile(
script: SourceCode,
@@ -40,12 +41,18 @@ class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguratio
): ResultWithDiagnostics<CompiledScript<*>> =
withMessageCollectorAndDisposable(script = script) { messageCollector, disposable ->
withScriptCompilationCache(script, scriptCompilationConfiguration, messageCollector) {
val initialConfiguration = scriptCompilationConfiguration.refineBeforeParsing(script).valueOr {
val initialConfiguration = runBlocking {
scriptCompilationConfigurationRefine(
ScriptCompilationConfiguration.refineConfigurationBeforeParsing,
ScriptConfigurationRefinementContext(script, scriptCompilationConfiguration)
)
}.valueOr {
return@withScriptCompilationCache it
}
val context = createIsolatedCompilationContext(
initialConfiguration, hostConfiguration, messageCollector, disposable
initialConfiguration, hostConfiguration, messageCollector, disposable,
scriptCompilationConfigurationRefine
)
compileImpl(script, context, messageCollector)
@@ -53,7 +60,10 @@ class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguratio
}
}
class ScriptJvmCompilerFromEnvironment(val environment: KotlinCoreEnvironment) : ScriptCompilerProxy {
class ScriptJvmCompilerFromEnvironment(
val environment: KotlinCoreEnvironment,
val scriptCompilationConfigurationRefine: ScriptCompilationConfigurationRefine
) : ScriptCompilerProxy {
override fun compile(
script: SourceCode,
@@ -63,11 +73,19 @@ class ScriptJvmCompilerFromEnvironment(val environment: KotlinCoreEnvironment) :
return withMessageCollector(script = script, parentMessageCollector = parentMessageCollector) { messageCollector ->
withScriptCompilationCache(script, scriptCompilationConfiguration, messageCollector) {
val initialConfiguration = scriptCompilationConfiguration.refineBeforeParsing(script).valueOr {
val initialConfiguration = runBlocking {
scriptCompilationConfigurationRefine(
ScriptCompilationConfiguration.refineConfigurationBeforeParsing,
ScriptConfigurationRefinementContext(script, scriptCompilationConfiguration)
)
}.valueOr {
return@withScriptCompilationCache it
}
val context = createCompilationContextFromEnvironment(initialConfiguration, environment, messageCollector)
val context = createCompilationContextFromEnvironment(
initialConfiguration, environment, messageCollector,
scriptCompilationConfigurationRefine
)
try {
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)

View File

@@ -30,11 +30,11 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.resolve.sam.SamWithReceiverResolver
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.sam.SamWithReceiverResolver
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
import org.jetbrains.kotlin.scripting.compiler.plugin.dependencies.ScriptsCompilationDependencies
import org.jetbrains.kotlin.scripting.compiler.plugin.dependencies.collectScriptsCompilationDependencies
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
import org.jetbrains.kotlin.scripting.definitions.annotationsForSamWithReceivers
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.ScriptCompilationConfigurationRefine
import kotlin.script.experimental.api.compilerOptions
import kotlin.script.experimental.api.dependencies
import kotlin.script.experimental.host.ScriptingHostConfiguration
@@ -63,7 +64,8 @@ internal fun createIsolatedCompilationContext(
baseScriptCompilationConfiguration: ScriptCompilationConfiguration,
hostConfiguration: ScriptingHostConfiguration,
messageCollector: ScriptDiagnosticsMessageCollector,
disposable: Disposable
disposable: Disposable,
scriptCompilationConfigurationRefine: ScriptCompilationConfigurationRefine
): SharedScriptCompilationContext {
val ignoredOptionsReportingState = IgnoredOptionsReportingState()
@@ -73,7 +75,9 @@ internal fun createIsolatedCompilationContext(
KotlinCoreEnvironment.createForProduction(
disposable, kotlinCompilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES
)
ScriptDependenciesProvider.getInstance(environment.project)?.registerRefineCallback(
baseScriptCompilationConfiguration, scriptCompilationConfigurationRefine
)
return SharedScriptCompilationContext(
disposable, initialScriptCompilationConfiguration, environment, ignoredOptionsReportingState
).applyConfigure()
@@ -82,10 +86,15 @@ internal fun createIsolatedCompilationContext(
internal fun createCompilationContextFromEnvironment(
baseScriptCompilationConfiguration: ScriptCompilationConfiguration,
environment: KotlinCoreEnvironment,
messageCollector: ScriptDiagnosticsMessageCollector
messageCollector: ScriptDiagnosticsMessageCollector,
scriptCompilationConfigurationRefine: ScriptCompilationConfigurationRefine
): SharedScriptCompilationContext {
val ignoredOptionsReportingState = IgnoredOptionsReportingState()
ScriptDependenciesProvider.getInstance(environment.project)?.registerRefineCallback(
baseScriptCompilationConfiguration, scriptCompilationConfigurationRefine
)
val initialScriptCompilationConfiguration =
baseScriptCompilationConfiguration.withUpdatesFromCompilerConfiguration(environment.configuration)

View File

@@ -36,12 +36,13 @@ internal fun makeCompiledModule(generationState: GenerationState) =
internal inline fun <T> withMessageCollectorAndDisposable(
script: SourceCode? = null,
parentMessageCollector: MessageCollector? = null,
disposable: Disposable = Disposer.newDisposable(),
externalDisposable: Disposable? = null,
disposeOnSuccess: Boolean = true,
body: (ScriptDiagnosticsMessageCollector, Disposable) -> ResultWithDiagnostics<T>
): ResultWithDiagnostics<T> {
var failed = false
val messageCollector = ScriptDiagnosticsMessageCollector(parentMessageCollector)
val disposable = externalDisposable ?: Disposer.newDisposable()
return try {
setIdeaIoUseFallback()
body(messageCollector, disposable).also {