Implement "legacy" REPL wrappers on top of the "new" scripting infrastructure
This commit is contained in:
+6
@@ -96,5 +96,11 @@ open class AggregatedReplStageState<T1, T2>(val state1: IReplStageState<T1>, val
|
||||
override fun getNextLineNo() = state1.getNextLineNo()
|
||||
|
||||
override val currentGeneration: Int get() = state1.currentGeneration
|
||||
|
||||
override fun dispose() {
|
||||
state2.dispose()
|
||||
state1.dispose()
|
||||
super.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@ sealed class ReplCompileResult : Serializable {
|
||||
val classes: List<CompiledClassData>,
|
||||
val hasResult: Boolean,
|
||||
val classpathAddendum: List<File>,
|
||||
val type: String?
|
||||
val type: String?,
|
||||
val data: Any? // TODO: temporary; migration to new scripting infrastructure
|
||||
) : ReplCompileResult() {
|
||||
companion object { private val serialVersionUID: Long = 2L }
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ interface IReplStageState<T> {
|
||||
else throw IllegalArgumentException("$this is not an expected instance of IReplStageState")
|
||||
|
||||
fun dispose() {
|
||||
history.reset()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -249,4 +249,10 @@ interface CompiledScript<out ScriptBase : Any> {
|
||||
*/
|
||||
val otherScripts: List<CompiledScript<*>>
|
||||
get() = emptyList()
|
||||
|
||||
/**
|
||||
* The name and the type of the script's result field, if any
|
||||
*/
|
||||
val resultField: Pair<String, KotlinType>?
|
||||
get() = null
|
||||
}
|
||||
|
||||
@@ -50,6 +50,13 @@ val ScriptEvaluationConfigurationKeys.providedProperties by PropertiesCollection
|
||||
*/
|
||||
val ScriptEvaluationConfigurationKeys.constructorArgs by PropertiesCollection.key<List<Any?>>()
|
||||
|
||||
/**
|
||||
* If the script is a snippet in a REPL, this property expected to contain previous REPL snippets in historical order
|
||||
* For the first snippet in a REPL an empty list should be passed explicitly
|
||||
* An array of the previous snippets will be passed to the current snippet constructor
|
||||
*/
|
||||
val ScriptEvaluationConfigurationKeys.previousSnippets by PropertiesCollection.key<List<Any>>()
|
||||
|
||||
@Deprecated("use scriptsInstancesSharing flag instead", level = DeprecationLevel.ERROR)
|
||||
val ScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key<MutableMap<KClass<*>, EvaluationResult>>()
|
||||
|
||||
@@ -101,6 +108,11 @@ sealed class ResultValue {
|
||||
override fun toString(): String = "$name: $type = $value"
|
||||
}
|
||||
|
||||
class UnitValue(val scriptInstance: Any) : ResultValue() {
|
||||
override fun toString(): String = "Unit"
|
||||
}
|
||||
|
||||
// TODO: obsolete it, use differently named value in the saving evaluators
|
||||
object Unit : ResultValue()
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,10 @@ open class PropertiesCollection(private val properties: Map<Key<*>, Any?> = empt
|
||||
data[this] = v
|
||||
}
|
||||
|
||||
fun <T> PropertiesCollection.Key<T>.put(v: T) {
|
||||
data[this] = v
|
||||
}
|
||||
|
||||
// generic for lists
|
||||
|
||||
operator fun <T> PropertiesCollection.Key<in List<T>>.invoke(vararg vals: T) {
|
||||
|
||||
+12
-6
@@ -10,7 +10,10 @@ 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.MessageCollectorBasedReporter
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.common.repl.IReplStageHistory
|
||||
import org.jetbrains.kotlin.cli.common.repl.LineId
|
||||
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
|
||||
import org.jetbrains.kotlin.cli.common.repl.scriptResultFieldName
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
||||
@@ -32,7 +35,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
||||
return ReplCompilationState(context)
|
||||
}
|
||||
|
||||
fun checkSyntax(
|
||||
override fun checkSyntax(
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||
project: Project
|
||||
@@ -44,13 +47,18 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
||||
override val messageCollector = messageCollector
|
||||
}
|
||||
val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(ktFile, errorHolder)
|
||||
if (syntaxErrorReport.isHasErrors) failure(messageCollector) else true.asSuccess()
|
||||
when {
|
||||
syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof -> false.asSuccess(messageCollector.diagnostics)
|
||||
syntaxErrorReport.isHasErrors -> failure(messageCollector)
|
||||
else -> true.asSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
fun compileReplSnippet(
|
||||
override fun compileReplSnippet(
|
||||
compilationState: JvmReplCompilerState.Compilation,
|
||||
snippet: SourceCode,
|
||||
snippetId: ReplSnippetId,
|
||||
// TODO: replace history with some interface based on CompiledScript
|
||||
history: IReplStageHistory<ScriptDescriptor>
|
||||
): ResultWithDiagnostics<CompiledScript<*>> =
|
||||
withMessageCollector(snippet) { messageCollector ->
|
||||
@@ -108,7 +116,6 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
||||
CompilationErrorHandler.THROW_EXCEPTION
|
||||
)
|
||||
|
||||
val generatedClassname = makeScriptBaseName(codeLine)
|
||||
history.push(LineId(codeLine), scriptDescriptor)
|
||||
|
||||
val compiledScript =
|
||||
@@ -133,4 +140,3 @@ internal class ReplCompilationState(val context: SharedScriptCompilationContext)
|
||||
internal fun makeReplCodeLine(id: ReplSnippetId, code: SourceCode): ReplCodeLine =
|
||||
ReplCodeLine(id.no, id.generation, code.text)
|
||||
|
||||
|
||||
|
||||
+1
-4
@@ -62,10 +62,7 @@ internal fun createSharedCompilationContext(
|
||||
scriptCompilationConfiguration, hostConfiguration, scriptCompilationState, messageCollector, ignoredOptionsReportingState
|
||||
)
|
||||
val environment =
|
||||
if (System.getProperty("idea.is.unit.test") == "true") KotlinCoreEnvironment.createForTests(
|
||||
disposable, kotlinCompilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
)
|
||||
else KotlinCoreEnvironment.createForProduction(
|
||||
KotlinCoreEnvironment.createForProduction(
|
||||
disposable, kotlinCompilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
)
|
||||
|
||||
|
||||
+11
-1
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.scripting.dependencies.ScriptsCompilationDependencies
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import java.util.*
|
||||
@@ -71,7 +72,7 @@ internal inline fun <T> withMessageCollectorAndDisposable(
|
||||
failure(messageCollector, ex.asDiagnostics(path = locationId))
|
||||
} finally {
|
||||
if (disposeOnSuccess || failed) {
|
||||
disposable.dispose()
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,6 +135,7 @@ internal fun makeCompiledScript(
|
||||
containingKtFile.virtualFile?.path,
|
||||
getScriptConfiguration(sourceFile),
|
||||
it.fqName.asString(),
|
||||
null,
|
||||
makeOtherScripts(it),
|
||||
null
|
||||
)
|
||||
@@ -145,10 +147,18 @@ internal fun makeCompiledScript(
|
||||
}
|
||||
|
||||
val module = makeCompiledModule(generationState)
|
||||
|
||||
val resultField = with(generationState.replSpecific) {
|
||||
// TODO: pass it in the configuration instead
|
||||
if (!hasResult || resultType == null || scriptResultFieldName == null) null
|
||||
else scriptResultFieldName!! to KotlinType(DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(resultType!!))
|
||||
}
|
||||
|
||||
return KJvmCompiledScript(
|
||||
script.locationId,
|
||||
getScriptConfiguration(ktScript.containingKtFile),
|
||||
ktScript.fqName.asString(),
|
||||
resultField,
|
||||
makeOtherScripts(ktScript),
|
||||
module
|
||||
)
|
||||
|
||||
+15
-102
@@ -5,112 +5,25 @@
|
||||
|
||||
package kotlin.script.experimental.jvmhost.repl
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.cli.common.repl.IReplStageHistory
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.scripting.repl.ReplCodeAnalyzer
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvmhost.impl.KJvmCompilerImpl
|
||||
import kotlin.script.experimental.jvmhost.impl.withDefaults
|
||||
|
||||
class JvmReplCompiler(
|
||||
val scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||
val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
||||
val replCompilerProxy: KJvmReplCompilerProxy = KJvmCompilerImpl(hostConfiguration.withDefaults())
|
||||
) : ReplCompiler {
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JvmReplCompilerState(replCompilerProxy, lock)
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
import kotlin.script.experimental.api.*
|
||||
|
||||
interface KJvmReplCompilerProxy {
|
||||
fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation
|
||||
}
|
||||
|
||||
class JvmReplCompilerStageHistory(private val state: JvmReplCompilerState) :
|
||||
BasicReplStageHistory<ScriptDescriptor>(state.lock) {
|
||||
fun checkSyntax(
|
||||
script: SourceCode,
|
||||
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||
project: Project
|
||||
): ResultWithDiagnostics<Boolean>
|
||||
|
||||
override fun reset(): Iterable<ILineId> {
|
||||
val removedCompiledLines = super.reset()
|
||||
val removedAnalyzedLines = state.compilation.analyzerEngine.reset()
|
||||
|
||||
checkConsistent(removedCompiledLines, removedAnalyzedLines)
|
||||
return removedCompiledLines
|
||||
}
|
||||
|
||||
override fun resetTo(id: ILineId): Iterable<ILineId> {
|
||||
val removedCompiledLines = super.resetTo(id)
|
||||
val removedAnalyzedLines = state.compilation.analyzerEngine.resetToLine(id)
|
||||
|
||||
checkConsistent(removedCompiledLines, removedAnalyzedLines)
|
||||
return removedCompiledLines
|
||||
}
|
||||
|
||||
private fun checkConsistent(removedCompiledLines: Iterable<ILineId>, removedAnalyzedLines: List<ReplCodeLine>) {
|
||||
removedCompiledLines.zip(removedAnalyzedLines).forEach { (removedCompiledLine, removedAnalyzedLine) ->
|
||||
if (removedCompiledLine != LineId(removedAnalyzedLine)) {
|
||||
throw IllegalStateException("History mismatch when resetting lines: ${removedCompiledLine.no} != $removedAnalyzedLine")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JvmReplCompilerState(
|
||||
val replCompilerProxy: KJvmReplCompilerProxy,
|
||||
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
) : IReplStageState<ScriptDescriptor> {
|
||||
|
||||
override val history = JvmReplCompilerStageHistory(this)
|
||||
|
||||
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
|
||||
|
||||
override fun dispose() {
|
||||
lock.write {
|
||||
_compilation?.disposable?.dispose()
|
||||
_compilation = null
|
||||
super.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
fun getCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): Compilation = lock.write {
|
||||
if (_compilation == null) {
|
||||
initializeCompilation(scriptCompilationConfiguration)
|
||||
}
|
||||
_compilation!!
|
||||
}
|
||||
|
||||
internal val compilation: Compilation
|
||||
get() = _compilation ?: throw IllegalStateException("Compilation state is either not initializad or already destroyed")
|
||||
|
||||
private var _compilation: Compilation? = null
|
||||
|
||||
val isCompilationInitialized get() = _compilation != null
|
||||
|
||||
private fun initializeCompilation(scriptCompilationConfiguration: ScriptCompilationConfiguration) {
|
||||
if (_compilation != null) throw IllegalStateException("Compilation state is already initialized")
|
||||
_compilation = replCompilerProxy.createReplCompilationState(scriptCompilationConfiguration)
|
||||
}
|
||||
|
||||
interface Compilation {
|
||||
val disposable: Disposable
|
||||
val baseScriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
val environment: KotlinCoreEnvironment
|
||||
val analyzerEngine: ReplCodeAnalyzer
|
||||
}
|
||||
}
|
||||
fun compileReplSnippet(
|
||||
compilationState: JvmReplCompilerState.Compilation,
|
||||
snippet: SourceCode,
|
||||
snippetId: ReplSnippetId,
|
||||
history: IReplStageHistory<ScriptDescriptor>
|
||||
): ResultWithDiagnostics<CompiledScript<*>>
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 kotlin.script.experimental.jvmhost.repl
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.scripting.repl.ReplCodeAnalyzer
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvmhost.impl.KJvmReplCompilerImpl
|
||||
import kotlin.script.experimental.jvmhost.impl.withDefaults
|
||||
|
||||
/**
|
||||
* REPL Compilation wrapper for "legacy" REPL APIs defined in the org.jetbrains.kotlin.cli.common.repl package
|
||||
*/
|
||||
class JvmReplCompiler(
|
||||
val scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||
val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
||||
val replCompilerProxy: KJvmReplCompilerProxy = KJvmReplCompilerImpl(hostConfiguration.withDefaults())
|
||||
) : ReplCompiler {
|
||||
|
||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JvmReplCompilerState(replCompilerProxy, lock)
|
||||
|
||||
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = state.lock.write {
|
||||
val replCompilerState = state.asState(JvmReplCompilerState::class.java)
|
||||
val compilation = replCompilerState.getCompilationState(scriptCompilationConfiguration)
|
||||
val res =
|
||||
replCompilerProxy.checkSyntax(
|
||||
codeLine.toSourceCode(scriptCompilationConfiguration),
|
||||
compilation.baseScriptCompilationConfiguration,
|
||||
compilation.environment.project
|
||||
)
|
||||
when {
|
||||
// TODO: implement diagnostics rendering
|
||||
res is ResultWithDiagnostics.Success && res.value -> ReplCheckResult.Ok()
|
||||
res is ResultWithDiagnostics.Success && !res.value -> ReplCheckResult.Incomplete()
|
||||
else -> ReplCheckResult.Error(res.reports.joinToString("\n") { it.message })
|
||||
}
|
||||
}
|
||||
|
||||
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult = state.lock.write {
|
||||
val replCompilerState = state.asState(JvmReplCompilerState::class.java)
|
||||
val compilation = replCompilerState.getCompilationState(scriptCompilationConfiguration)
|
||||
val snippet = codeLine.toSourceCode(scriptCompilationConfiguration)
|
||||
val snippetId = ReplSnippetIdImpl(codeLine.no, codeLine.generation, snippet)
|
||||
when (val res = replCompilerProxy.compileReplSnippet(compilation, snippet, snippetId, replCompilerState.history)) {
|
||||
is ResultWithDiagnostics.Success ->
|
||||
ReplCompileResult.CompiledClasses(
|
||||
LineId(codeLine),
|
||||
replCompilerState.history.map { it.id },
|
||||
snippet.name!!,
|
||||
emptyList(),
|
||||
res.value.resultField != null,
|
||||
emptyList(),
|
||||
res.value.resultField?.second?.typeName,
|
||||
res.value
|
||||
)
|
||||
else -> ReplCompileResult.Error(res.reports.joinToString("\n") { it.message })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JvmReplCompilerStageHistory(private val state: JvmReplCompilerState) :
|
||||
BasicReplStageHistory<ScriptDescriptor>(state.lock) {
|
||||
|
||||
override fun reset(): Iterable<ILineId> {
|
||||
val removedCompiledLines = super.reset()
|
||||
val removedAnalyzedLines = state.compilation.analyzerEngine.reset()
|
||||
|
||||
checkConsistent(removedCompiledLines, removedAnalyzedLines)
|
||||
return removedCompiledLines
|
||||
}
|
||||
|
||||
override fun resetTo(id: ILineId): Iterable<ILineId> {
|
||||
val removedCompiledLines = super.resetTo(id)
|
||||
val removedAnalyzedLines = state.compilation.analyzerEngine.resetToLine(id)
|
||||
|
||||
checkConsistent(removedCompiledLines, removedAnalyzedLines)
|
||||
return removedCompiledLines
|
||||
}
|
||||
|
||||
private fun checkConsistent(removedCompiledLines: Iterable<ILineId>, removedAnalyzedLines: List<ReplCodeLine>) {
|
||||
removedCompiledLines.zip(removedAnalyzedLines).forEach { (removedCompiledLine, removedAnalyzedLine) ->
|
||||
if (removedCompiledLine != LineId(removedAnalyzedLine)) {
|
||||
throw IllegalStateException("History mismatch when resetting lines: ${removedCompiledLine.no} != $removedAnalyzedLine")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JvmReplCompilerState(
|
||||
val replCompilerProxy: KJvmReplCompilerProxy,
|
||||
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
) : IReplStageState<ScriptDescriptor> {
|
||||
|
||||
override val history = JvmReplCompilerStageHistory(this)
|
||||
|
||||
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
|
||||
|
||||
override fun dispose() {
|
||||
lock.write {
|
||||
_compilation?.disposable?.let {
|
||||
Disposer.dispose(it)
|
||||
}
|
||||
_compilation = null
|
||||
super.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
fun getCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): Compilation = lock.write {
|
||||
if (_compilation == null) {
|
||||
initializeCompilation(scriptCompilationConfiguration)
|
||||
}
|
||||
_compilation!!
|
||||
}
|
||||
|
||||
internal val compilation: Compilation
|
||||
get() = _compilation ?: throw IllegalStateException("Compilation state is either not initializad or already destroyed")
|
||||
|
||||
private var _compilation: Compilation? = null
|
||||
|
||||
val isCompilationInitialized get() = _compilation != null
|
||||
|
||||
private fun initializeCompilation(scriptCompilationConfiguration: ScriptCompilationConfiguration) {
|
||||
if (_compilation != null) throw IllegalStateException("Compilation state is already initialized")
|
||||
_compilation = replCompilerProxy.createReplCompilationState(scriptCompilationConfiguration)
|
||||
}
|
||||
|
||||
interface Compilation {
|
||||
val disposable: Disposable
|
||||
val baseScriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||
val environment: KotlinCoreEnvironment
|
||||
val analyzerEngine: ReplCodeAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
internal class SourceCodeFromReplCodeLine(
|
||||
val codeLine: ReplCodeLine,
|
||||
compilationConfiguration: ScriptCompilationConfiguration
|
||||
) : SourceCode {
|
||||
override val text: String get() = codeLine.code
|
||||
override val name: String = "${makeScriptBaseName(codeLine)}.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}"
|
||||
override val locationId: String? = null
|
||||
}
|
||||
|
||||
internal fun ReplCodeLine.toSourceCode(compilationConfiguration: ScriptCompilationConfiguration): SourceCode =
|
||||
SourceCodeFromReplCodeLine(this, compilationConfiguration)
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 kotlin.script.experimental.jvmhost.repl
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.write
|
||||
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 compiledScript = (compileResult.data as? KJvmCompiledScript<*>)
|
||||
?: return ReplEvalResult.Error.CompileTime("Unable to access compiled script: ${compileResult.data}")
|
||||
|
||||
val lastSnippetInstance = evalState.history.peek()?.item
|
||||
val currentConfiguration = ScriptEvaluationConfiguration(baseScriptEvaluationConfiguration) {
|
||||
if (evalState.history.isNotEmpty()) {
|
||||
previousSnippets.put(evalState.history.map { it.item })
|
||||
}
|
||||
if (lastSnippetInstance != null) {
|
||||
jvm {
|
||||
baseClassLoader(lastSnippetInstance::class.java.classLoader)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val res = runBlocking { scriptEvaluator(compiledScript, currentConfiguration) }
|
||||
|
||||
when (res) {
|
||||
is ResultWithDiagnostics.Success -> when (val retVal = res.value.returnValue) {
|
||||
is ResultValue.Value -> {
|
||||
evalState.history.push(compileResult.lineId, retVal.scriptInstance)
|
||||
// TODO: the latter check is temporary while the result is used to return the instance too
|
||||
if (retVal.type.isNotBlank())
|
||||
ReplEvalResult.ValueResult(retVal.name, retVal.value, retVal.type)
|
||||
else
|
||||
ReplEvalResult.UnitResult()
|
||||
}
|
||||
is ResultValue.UnitValue -> {
|
||||
evalState.history.push(compileResult.lineId, retVal.scriptInstance)
|
||||
ReplEvalResult.UnitResult()
|
||||
}
|
||||
else -> throw IllegalStateException("Expecting value with script instance, got $retVal")
|
||||
}
|
||||
else -> ReplEvalResult.Error.Runtime(res.reports.joinToString("\n") { it.message })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class JvmReplEvaluatorState(
|
||||
scriptEvaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
) : IReplStageState<Any> {
|
||||
|
||||
override val history: IReplStageHistory<Any> = BasicReplStageHistory(lock)
|
||||
|
||||
override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get()
|
||||
|
||||
val topClassLoader: ClassLoader = scriptEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]!!
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 kotlin.script.experimental.jvmhost.test
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase.resetApplicationToNull
|
||||
import java.io.Closeable
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler
|
||||
import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator
|
||||
|
||||
// Adapted form GenericReplTest
|
||||
|
||||
class LegacyReplTest : KtUsefulTestCase() {
|
||||
fun testReplBasics() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
val res1 = repl.replCompiler.check(repl.state, ReplCodeLine(0, 0, "val x ="))
|
||||
TestCase.assertTrue("Unexpected check results: $res1", res1 is ReplCheckResult.Incomplete)
|
||||
|
||||
assertEvalResult(repl, "val l1 = listOf(1 + 2)\nl1.first()", 3)
|
||||
|
||||
assertEvalUnit(repl, "val x = 5")
|
||||
|
||||
assertEvalResult(repl, "x + 2", 7)
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplErrors() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
repl.compileAndEval(repl.nextCodeLine("val x = 10"))
|
||||
|
||||
val res = repl.compileAndEval(repl.nextCodeLine("java.util.fish"))
|
||||
TestCase.assertTrue("Expected compile error", res.first is ReplCompileResult.Error)
|
||||
|
||||
val result = repl.compileAndEval(repl.nextCodeLine("x"))
|
||||
assertEquals(res.second.toString(), 10, (result.second as? ReplEvalResult.ValueResult)?.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplCodeFormat() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
val codeLine0 = ReplCodeLine(0, 0, "val l1 = 1\r\nl1\r\n")
|
||||
val res0 = repl.replCompiler.check(repl.state, codeLine0)
|
||||
val res0c = res0 as? ReplCheckResult.Ok
|
||||
TestCase.assertNotNull("Unexpected compile result: $res0", res0c)
|
||||
}
|
||||
}
|
||||
|
||||
fun testRepPackage() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
assertEvalResult(repl, "package mypackage\n\nval x = 1\nx+2", 3)
|
||||
|
||||
assertEvalResult(repl, "x+4", 5)
|
||||
}
|
||||
}
|
||||
|
||||
fun test256Evals() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
repl.compileAndEval(ReplCodeLine(0, 0, "val x0 = 0"))
|
||||
|
||||
val evals = 256
|
||||
for (i in 1..evals) {
|
||||
repl.compileAndEval(ReplCodeLine(i, 0, "val x$i = x${i-1} + 1"))
|
||||
}
|
||||
|
||||
val res = repl.compileAndEval(ReplCodeLine(evals + 1, 0, "x$evals"))
|
||||
assertEquals(res.second.toString(), evals, (res.second as? ReplEvalResult.ValueResult)?.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplSlowdownKt22740() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
repl.compileAndEval(ReplCodeLine(0, 0, "class Test<T>(val x: T) { fun <R> map(f: (T) -> R): R = f(x) }".trimIndent()))
|
||||
|
||||
// We expect that analysis time is not exponential
|
||||
for (i in 1..60) {
|
||||
repl.compileAndEval(ReplCodeLine(i, 0, "fun <T> Test<T>.map(f: (T) -> Double): List<Double> = listOf(f(this.x))"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplResultFieldWithFunction() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
assertEvalResultIs<Function0<Int>>(repl, "{ 1 + 2 }")
|
||||
assertEvalResultIs<Function0<Int>>(repl, "res0")
|
||||
assertEvalResult(repl, "res0()", 3)
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplResultField() {
|
||||
LegacyTestRepl().use { repl ->
|
||||
assertEvalResult(repl, "5 * 4", 20)
|
||||
assertEvalResult(repl, "res0 + 3", 23)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertEvalUnit(repl: LegacyTestRepl, line: String) {
|
||||
val compiledClasses = checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.compiledEvaluator.eval(repl.state, compiledClasses!!)
|
||||
val unitResult = evalResult as? ReplEvalResult.UnitResult
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", unitResult)
|
||||
}
|
||||
|
||||
private fun<R> assertEvalResult(repl: LegacyTestRepl, line: String, expectedResult: R) {
|
||||
val compiledClasses = checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.compiledEvaluator.eval(repl.state, compiledClasses!!)
|
||||
val valueResult = evalResult as? ReplEvalResult.ValueResult
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertEquals(expectedResult, valueResult!!.value)
|
||||
}
|
||||
|
||||
private inline fun<reified R> assertEvalResultIs(repl: LegacyTestRepl, line: String) {
|
||||
val compiledClasses = checkCompile(repl, line)
|
||||
|
||||
val evalResult = repl.compiledEvaluator.eval(repl.state, compiledClasses!!)
|
||||
val valueResult = evalResult as? ReplEvalResult.ValueResult
|
||||
TestCase.assertNotNull("Unexpected eval result: $evalResult", valueResult)
|
||||
TestCase.assertTrue(valueResult!!.value is R)
|
||||
}
|
||||
|
||||
private fun checkCompile(repl: LegacyTestRepl, line: String): ReplCompileResult.CompiledClasses? {
|
||||
val codeLine = repl.nextCodeLine(line)
|
||||
val compileResult = repl.replCompiler.compile(repl.state, codeLine)
|
||||
val compiledClasses = compileResult as? ReplCompileResult.CompiledClasses
|
||||
TestCase.assertNotNull("Unexpected compile result: $compileResult", compiledClasses)
|
||||
return compiledClasses
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class LegacyTestRepl : Closeable {
|
||||
val application = ApplicationManager.getApplication()
|
||||
|
||||
val currentLineCounter = AtomicInteger()
|
||||
|
||||
fun nextCodeLine(code: String): ReplCodeLine = ReplCodeLine(currentLineCounter.getAndIncrement(), 0, code)
|
||||
|
||||
val replCompiler: JvmReplCompiler by lazy {
|
||||
JvmReplCompiler(simpleScriptompilationConfiguration)
|
||||
}
|
||||
|
||||
val compiledEvaluator: ReplEvaluator by lazy {
|
||||
JvmReplEvaluator(simpleScriptEvaluationConfiguration)
|
||||
}
|
||||
|
||||
val state by lazy {
|
||||
val stateLock = ReentrantReadWriteLock()
|
||||
AggregatedReplStageState(replCompiler.createState(stateLock), compiledEvaluator.createState(stateLock), stateLock)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
state.dispose()
|
||||
resetApplicationToNull(application)
|
||||
}
|
||||
}
|
||||
|
||||
private fun LegacyTestRepl.compileAndEval(codeLine: ReplCodeLine): Pair<ReplCompileResult, ReplEvalResult?> {
|
||||
|
||||
val compRes = replCompiler.compile(state, codeLine)
|
||||
|
||||
val evalRes = (compRes as? ReplCompileResult.CompiledClasses)?.let {
|
||||
|
||||
compiledEvaluator.eval(state, it)
|
||||
}
|
||||
return compRes to evalRes
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 kotlin.script.experimental.jvmhost.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.jvm.*
|
||||
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
|
||||
import kotlin.script.experimental.jvmhost.impl.KJvmReplCompilerImpl
|
||||
|
||||
class ReplTest : TestCase() {
|
||||
|
||||
companion object {
|
||||
const val TEST_DATA_DIR = "libraries/scripting/jvm-host/testData"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCompileAndEval() {
|
||||
val out = captureOut {
|
||||
chechEvaluateInReplNoErrors(
|
||||
simpleScriptompilationConfiguration,
|
||||
simpleScriptEvaluationConfiguration,
|
||||
sequenceOf(
|
||||
"val x = 3",
|
||||
"x + 4",
|
||||
"println(\"x = \$x\")"
|
||||
),
|
||||
sequenceOf(null, 7, null)
|
||||
)
|
||||
}
|
||||
Assert.assertEquals("x = 3", out)
|
||||
}
|
||||
|
||||
fun evaluateInRepl(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
snippets: Sequence<String>
|
||||
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
||||
val replCompilerProxy = KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
||||
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
||||
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
||||
val replEvaluator = BasicJvmScriptEvaluator()
|
||||
var currentEvalConfig = evaluationConfiguration
|
||||
return snippets.mapIndexed { snippetNo, snippetText ->
|
||||
val snippetSource = snippetText.toScriptSource("Line_$snippetNo.simplescript.kts")
|
||||
val snippetId = ReplSnippetIdImpl(snippetNo, 0, snippetSource)
|
||||
replCompilerProxy.compileReplSnippet(compilationState, snippetSource, snippetId, compilationHistory)
|
||||
.onSuccess {
|
||||
runBlocking {
|
||||
replEvaluator(it, currentEvalConfig)
|
||||
}
|
||||
}
|
||||
.onSuccess {
|
||||
val snippetInstance = when (val retVal = it.returnValue) {
|
||||
is ResultValue.Value -> retVal.scriptInstance
|
||||
is ResultValue.UnitValue -> retVal.scriptInstance
|
||||
else -> throw IllegalStateException("Expecting value with script instance, got $it")
|
||||
}
|
||||
currentEvalConfig = ScriptEvaluationConfiguration(currentEvalConfig) {
|
||||
previousSnippets.append(snippetInstance)
|
||||
jvm {
|
||||
baseClassLoader(snippetInstance::class.java.classLoader)
|
||||
}
|
||||
}
|
||||
it.asSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun chechEvaluateInReplNoErrors(
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||
snippets: Sequence<String>,
|
||||
expected: Sequence<Any?>
|
||||
) {
|
||||
val expectedIter = expected.iterator()
|
||||
evaluateInRepl(compilationConfiguration, evaluationConfiguration, snippets).forEachIndexed { index, res ->
|
||||
when (res) {
|
||||
is ResultWithDiagnostics.Failure -> Assert.fail("#$index: Expected result, got $res")
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
val expectedVal = expectedIter.next()
|
||||
val resVal = res.value.returnValue
|
||||
if (resVal is ResultValue.Value && resVal.type.isNotBlank()) // TODO: the latter check is temporary while the result is used to return the instance too
|
||||
Assert.assertEquals("#$index: Expected $expectedVal, got $resVal", expectedVal, resVal.value)
|
||||
else
|
||||
Assert.assertTrue("#$index: Expected $expectedVal, got Unit", expectedVal == null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@KotlinScript(fileExtension = "simplescript.kts")
|
||||
abstract class SimpleScript
|
||||
|
||||
val simpleScriptompilationConfiguration = createJvmCompilationConfigurationFromTemplate<SimpleScript> {
|
||||
jvm {
|
||||
dependenciesFromCurrentContext(wholeClasspath = true)
|
||||
}
|
||||
}
|
||||
|
||||
val simpleScriptEvaluationConfiguration = ScriptEvaluationConfiguration()
|
||||
+2
-2
@@ -526,9 +526,9 @@ private class FileBasedScriptCache(val baseDir: File) : ScriptingCacheWithCounte
|
||||
get() = _retrievedScripts
|
||||
}
|
||||
|
||||
private fun captureOut(body: () -> Unit): String = captureOutAndErr(body).first
|
||||
internal fun captureOut(body: () -> Unit): String = captureOutAndErr(body).first
|
||||
|
||||
private fun captureOutAndErr(body: () -> Unit): Pair<String, String> {
|
||||
internal fun captureOutAndErr(body: () -> Unit): Pair<String, String> {
|
||||
val outStream = ByteArrayOutputStream()
|
||||
val errStream = ByteArrayOutputStream()
|
||||
val prevOut = System.out
|
||||
|
||||
+17
-6
@@ -43,7 +43,15 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
||||
?.resultOrNull()
|
||||
?: configuration
|
||||
|
||||
scriptClass.evalWithConfigAndOtherScriptsResults(refinedEvalConfiguration, importedScriptsEvalResults).let {
|
||||
val instance =
|
||||
scriptClass.evalWithConfigAndOtherScriptsResults(refinedEvalConfiguration, importedScriptsEvalResults)
|
||||
|
||||
val resultValue = compiledScript.resultField?.let { (resultFieldName, resultType) ->
|
||||
val resultField = scriptClass.java.getDeclaredField(resultFieldName).apply { isAccessible = true }
|
||||
ResultValue.Value(resultFieldName, resultField.get(instance), resultType.typeName, instance)
|
||||
} ?: ResultValue.Value("", instance, "", instance)
|
||||
|
||||
EvaluationResult(resultValue, refinedEvalConfiguration).let {
|
||||
sharedScripts?.put(scriptClass, it)
|
||||
ResultWithDiagnostics.Success(it)
|
||||
}
|
||||
@@ -61,9 +69,15 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
||||
private fun KClass<*>.evalWithConfigAndOtherScriptsResults(
|
||||
refinedEvalConfiguration: ScriptEvaluationConfiguration,
|
||||
importedScriptsEvalResults: List<EvaluationResult>
|
||||
): EvaluationResult {
|
||||
): Any {
|
||||
val args = ArrayList<Any?>()
|
||||
|
||||
refinedEvalConfiguration[ScriptEvaluationConfiguration.previousSnippets]?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
args.add(it.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
refinedEvalConfiguration[ScriptEvaluationConfiguration.constructorArgs]?.let {
|
||||
args.addAll(it)
|
||||
}
|
||||
@@ -81,10 +95,7 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
|
||||
val ctor = java.constructors.single()
|
||||
val instance = ctor.newInstance(*args.toArray())
|
||||
|
||||
return EvaluationResult(
|
||||
ResultValue.Value("", instance, "", instance),
|
||||
refinedEvalConfiguration
|
||||
)
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-3
@@ -16,6 +16,7 @@ internal class KJvmCompiledScriptData(
|
||||
var sourceLocationId: String?,
|
||||
var compilationConfiguration: ScriptCompilationConfiguration,
|
||||
var scriptClassFQName: String,
|
||||
var resultField: Pair<String, KotlinType>?,
|
||||
var otherScripts: List<CompiledScript<*>> = emptyList()
|
||||
) : Serializable {
|
||||
|
||||
@@ -24,6 +25,7 @@ internal class KJvmCompiledScriptData(
|
||||
outputStream.writeObject(sourceLocationId)
|
||||
outputStream.writeObject(otherScripts)
|
||||
outputStream.writeObject(scriptClassFQName)
|
||||
outputStream.writeObject(resultField)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -32,11 +34,12 @@ internal class KJvmCompiledScriptData(
|
||||
sourceLocationId = inputStream.readObject() as String?
|
||||
otherScripts = inputStream.readObject() as List<CompiledScript<*>>
|
||||
scriptClassFQName = inputStream.readObject() as String
|
||||
resultField = inputStream.readObject() as Pair<String, KotlinType>?
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private val serialVersionUID = 3L
|
||||
private val serialVersionUID = 4L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +52,13 @@ class KJvmCompiledScript<out ScriptBase : Any> internal constructor(
|
||||
sourceLocationId: String?,
|
||||
compilationConfiguration: ScriptCompilationConfiguration,
|
||||
scriptClassFQName: String,
|
||||
resultField: Pair<String, KotlinType>?,
|
||||
otherScripts: List<CompiledScript<*>> = emptyList(),
|
||||
compiledModule: KJvmCompiledModule? // module should be null for imported (other) scripts, so only one reference to the module is kept
|
||||
): this(KJvmCompiledScriptData(sourceLocationId, compilationConfiguration, scriptClassFQName, otherScripts), compiledModule)
|
||||
) : this(
|
||||
KJvmCompiledScriptData(sourceLocationId, compilationConfiguration, scriptClassFQName, resultField, otherScripts),
|
||||
compiledModule
|
||||
)
|
||||
|
||||
override val sourceLocationId: String?
|
||||
get() = data.sourceLocationId
|
||||
@@ -65,6 +72,9 @@ class KJvmCompiledScript<out ScriptBase : Any> internal constructor(
|
||||
val scriptClassFQName: String
|
||||
get() = data.scriptClassFQName
|
||||
|
||||
override val resultField: Pair<String, KotlinType>?
|
||||
get() = data.resultField
|
||||
|
||||
override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?): ResultWithDiagnostics<KClass<*>> = try {
|
||||
// ensuring proper defaults are used
|
||||
val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||
@@ -168,7 +178,8 @@ fun KJvmCompiledScript<*>.toBytes(): ByteArray {
|
||||
} finally {
|
||||
try {
|
||||
oos?.close()
|
||||
} catch (e: IOException) {}
|
||||
} catch (e: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -115,7 +115,8 @@ open class GenericReplCompiler(
|
||||
classpathAddendum ?: emptyList(),
|
||||
generationState.replSpecific.resultType?.let {
|
||||
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(it)
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user