Implement support for new script customizations in command line compiler
refactor and fix internals in many places to make it work add appropriate tests for main-kts case
This commit is contained in:
+12
-10
@@ -35,21 +35,23 @@ open class ScriptCompilationConfiguration(baseConfigurations: Iterable<ScriptCom
|
|||||||
|
|
||||||
object Default : ScriptCompilationConfiguration()
|
object Default : ScriptCompilationConfiguration()
|
||||||
|
|
||||||
/**
|
|
||||||
* An alternative to the constructor with base configuration, which returns a new configuration only if [body] adds anything
|
|
||||||
* to the original one, otherwise returns original
|
|
||||||
*/
|
|
||||||
fun withUpdates(body: Builder.() -> Unit = {}): ScriptCompilationConfiguration {
|
|
||||||
val newConfiguration = ScriptCompilationConfiguration(this, body = body)
|
|
||||||
return if (newConfiguration == this) this
|
|
||||||
else newConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ScriptCompilationConfiguration($providedProperties)"
|
return "ScriptCompilationConfiguration($providedProperties)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An alternative to the constructor with base configuration, which returns a new configuration only if [body] adds anything
|
||||||
|
* to the original one, otherwise returns original
|
||||||
|
*/
|
||||||
|
fun ScriptCompilationConfiguration?.with(body: ScriptCompilationConfiguration.Builder.() -> Unit): ScriptCompilationConfiguration {
|
||||||
|
val newConfiguration =
|
||||||
|
if (this == null) ScriptCompilationConfiguration(body = body)
|
||||||
|
else ScriptCompilationConfiguration(this, body = body)
|
||||||
|
return if (newConfiguration == this) this else newConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The script type display name
|
* The script type display name
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,6 +35,18 @@ open class ScriptEvaluationConfiguration(baseEvaluationConfigurations: Iterable<
|
|||||||
object Default : ScriptEvaluationConfiguration()
|
object Default : ScriptEvaluationConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An alternative to the constructor with base configuration, which returns a new configuration only if [body] adds anything
|
||||||
|
* to the original one, otherwise returns original
|
||||||
|
*/
|
||||||
|
fun ScriptEvaluationConfiguration?.with(body: ScriptEvaluationConfiguration.Builder.() -> Unit): ScriptEvaluationConfiguration {
|
||||||
|
val newConfiguration =
|
||||||
|
if (this == null) ScriptEvaluationConfiguration(body = body)
|
||||||
|
else ScriptEvaluationConfiguration(this, body = body)
|
||||||
|
return if (newConfiguration != this) newConfiguration else this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of actual script implicit receiver object, in the same order as specified in {@link ScriptCompilationConfigurationKeys#implicitReceivers}
|
* The list of actual script implicit receiver object, in the same order as specified in {@link ScriptCompilationConfigurationKeys#implicitReceivers}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ dependencies {
|
|||||||
allTestsRuntime(intellijDep()) { includeJars("openapi", "idea", "idea_rt", "log4j") }
|
allTestsRuntime(intellijDep()) { includeJars("openapi", "idea", "idea_rt", "log4j") }
|
||||||
testCompile(project(":kotlin-scripting-jvm-host"))
|
testCompile(project(":kotlin-scripting-jvm-host"))
|
||||||
testCompile(projectTests(":compiler:tests-common"))
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(project(":kotlin-scripting-compiler"))
|
||||||
testCompile(project(":daemon-common")) // TODO: fix import (workaround for jps build)
|
testCompile(project(":daemon-common")) // TODO: fix import (workaround for jps build)
|
||||||
|
|
||||||
testRuntimeOnly(project(":kotlin-compiler"))
|
testRuntimeOnly(project(":kotlin-compiler"))
|
||||||
testRuntimeOnly(project(":kotlin-scripting-compiler"))
|
|
||||||
testRuntimeOnly(project(":kotlin-reflect"))
|
testRuntimeOnly(project(":kotlin-reflect"))
|
||||||
testRuntimeOnly(commonDep("org.jetbrains.intellij.deps", "trove4j"))
|
testRuntimeOnly(commonDep("org.jetbrains.intellij.deps", "trove4j"))
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -9,6 +9,7 @@ import junit.framework.TestCase
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
|
import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.script.experimental.annotations.KotlinScript
|
import kotlin.script.experimental.annotations.KotlinScript
|
||||||
@@ -16,7 +17,6 @@ import kotlin.script.experimental.api.*
|
|||||||
import kotlin.script.experimental.host.toScriptSource
|
import kotlin.script.experimental.host.toScriptSource
|
||||||
import kotlin.script.experimental.jvm.*
|
import kotlin.script.experimental.jvm.*
|
||||||
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
|
import kotlin.script.experimental.jvmhost.createJvmCompilationConfigurationFromTemplate
|
||||||
import kotlin.script.experimental.jvmhost.impl.KJvmReplCompilerImpl
|
|
||||||
|
|
||||||
class ReplTest : TestCase() {
|
class ReplTest : TestCase() {
|
||||||
|
|
||||||
@@ -46,7 +46,8 @@ class ReplTest : TestCase() {
|
|||||||
evaluationConfiguration: ScriptEvaluationConfiguration,
|
evaluationConfiguration: ScriptEvaluationConfiguration,
|
||||||
snippets: Sequence<String>
|
snippets: Sequence<String>
|
||||||
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
): Sequence<ResultWithDiagnostics<EvaluationResult>> {
|
||||||
val replCompilerProxy = KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
val replCompilerProxy =
|
||||||
|
KJvmReplCompilerImpl(defaultJvmScriptingHostConfiguration)
|
||||||
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
val compilationState = replCompilerProxy.createReplCompilationState(compilationConfiguration)
|
||||||
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
val compilationHistory = BasicReplStageHistory<ScriptDescriptor>()
|
||||||
val replEvaluator = BasicJvmScriptEvaluator()
|
val replEvaluator = BasicJvmScriptEvaluator()
|
||||||
|
|||||||
+2
-2
@@ -7,6 +7,8 @@ package kotlin.script.experimental.jvmhost.test
|
|||||||
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.CompiledScriptClassLoader
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmCompiledModuleInMemory
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||||
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
@@ -27,8 +29,6 @@ import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
|
|||||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||||
import kotlin.script.experimental.jvmhost.*
|
import kotlin.script.experimental.jvmhost.*
|
||||||
import kotlin.script.experimental.jvmhost.impl.CompiledScriptClassLoader
|
|
||||||
import kotlin.script.experimental.jvmhost.impl.KJvmCompiledModuleInMemory
|
|
||||||
import kotlin.script.templates.standard.SimpleScriptTemplate
|
import kotlin.script.templates.standard.SimpleScriptTemplate
|
||||||
|
|
||||||
class ScriptingHostTest : TestCase() {
|
class ScriptingHostTest : TestCase() {
|
||||||
|
|||||||
-91
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2018 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.impl
|
|
||||||
|
|
||||||
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.jvm.compiler.KotlinCoreEnvironment
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
|
||||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
|
||||||
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
|
||||||
import kotlin.script.experimental.api.*
|
|
||||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
|
||||||
import kotlin.script.experimental.jvmhost.KJvmCompilerProxy
|
|
||||||
|
|
||||||
class KJvmCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvmCompilerProxy {
|
|
||||||
|
|
||||||
override fun compile(
|
|
||||||
script: SourceCode,
|
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
|
||||||
): ResultWithDiagnostics<CompiledScript<*>> =
|
|
||||||
withMessageCollectorAndDisposable(locationId = script.locationId) { messageCollector, disposable ->
|
|
||||||
|
|
||||||
val context = createSharedCompilationContext(scriptCompilationConfiguration, hostConfiguration, messageCollector, disposable)
|
|
||||||
|
|
||||||
val mainKtFile =
|
|
||||||
getScriptKtFile(script, context.baseScriptCompilationConfiguration, context.environment.project, messageCollector)
|
|
||||||
.valueOr { return it }
|
|
||||||
|
|
||||||
val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment(context, mainKtFile, messageCollector)
|
|
||||||
|
|
||||||
val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project)
|
|
||||||
val analysisResult = analyze(sourceFiles, context.environment)
|
|
||||||
|
|
||||||
if (!analysisResult.shouldGenerateCode) return failure(script, messageCollector, "no code to generate")
|
|
||||||
if (analysisResult.isError() || messageCollector.hasErrors()) return failure(messageCollector)
|
|
||||||
|
|
||||||
val generationState = generate(analysisResult, sourceFiles, context.environment.configuration)
|
|
||||||
|
|
||||||
val compiledScript =
|
|
||||||
makeCompiledScript(generationState, script, sourceFiles.first(), sourceDependencies) { ktFile ->
|
|
||||||
dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration
|
|
||||||
?: context.baseScriptCompilationConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultWithDiagnostics.Success(compiledScript, messageCollector.diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun analyze(sourceFiles: Collection<KtFile>, environment: KotlinCoreEnvironment): AnalysisResult {
|
|
||||||
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!!
|
|
||||||
|
|
||||||
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings)
|
|
||||||
|
|
||||||
analyzerWithCompilerReport.analyzeAndReport(sourceFiles) {
|
|
||||||
val project = environment.project
|
|
||||||
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
|
||||||
project,
|
|
||||||
sourceFiles,
|
|
||||||
NoScopeRecordCliBindingTrace(),
|
|
||||||
environment.configuration,
|
|
||||||
environment::createPackagePartProvider
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return analyzerWithCompilerReport.analysisResult
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generate(
|
|
||||||
analysisResult: AnalysisResult, sourceFiles: List<KtFile>, kotlinCompilerConfiguration: CompilerConfiguration
|
|
||||||
): GenerationState {
|
|
||||||
val generationState = GenerationState.Builder(
|
|
||||||
sourceFiles.first().project,
|
|
||||||
ClassBuilderFactories.BINARIES,
|
|
||||||
analysisResult.moduleDescriptor,
|
|
||||||
analysisResult.bindingContext,
|
|
||||||
sourceFiles,
|
|
||||||
kotlinCompilerConfiguration
|
|
||||||
).build()
|
|
||||||
|
|
||||||
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
|
|
||||||
return generationState
|
|
||||||
}
|
|
||||||
+3
-9
@@ -7,10 +7,11 @@
|
|||||||
|
|
||||||
package kotlin.script.experimental.jvmhost
|
package kotlin.script.experimental.jvmhost
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptJvmCompilerProxy
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerIsolated
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvmhost.impl.KJvmCompilerImpl
|
|
||||||
import kotlin.script.experimental.jvmhost.impl.withDefaults
|
import kotlin.script.experimental.jvmhost.impl.withDefaults
|
||||||
|
|
||||||
interface CompiledJvmScriptsCache {
|
interface CompiledJvmScriptsCache {
|
||||||
@@ -31,7 +32,7 @@ interface CompiledJvmScriptsCache {
|
|||||||
|
|
||||||
open class JvmScriptCompiler(
|
open class JvmScriptCompiler(
|
||||||
hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
||||||
val compilerProxy: KJvmCompilerProxy = KJvmCompilerImpl(hostConfiguration.withDefaults()),
|
val compilerProxy: ScriptJvmCompilerProxy = ScriptJvmCompilerIsolated(hostConfiguration.withDefaults()),
|
||||||
val cache: CompiledJvmScriptsCache = CompiledJvmScriptsCache.NoCache
|
val cache: CompiledJvmScriptsCache = CompiledJvmScriptsCache.NoCache
|
||||||
) : ScriptCompiler {
|
) : ScriptCompiler {
|
||||||
|
|
||||||
@@ -59,10 +60,3 @@ open class JvmScriptCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KJvmCompilerProxy {
|
|
||||||
fun compile(
|
|
||||||
script: SourceCode,
|
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
|
||||||
): ResultWithDiagnostics<CompiledScript<*>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -5,16 +5,20 @@
|
|||||||
|
|
||||||
package kotlin.script.experimental.jvmhost
|
package kotlin.script.experimental.jvmhost
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmCompiledModuleInMemory
|
||||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||||
import java.io.*
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
import java.util.jar.JarEntry
|
import java.util.jar.JarEntry
|
||||||
import java.util.jar.JarOutputStream
|
import java.util.jar.JarOutputStream
|
||||||
import java.util.jar.Manifest
|
import java.util.jar.Manifest
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.jvm.JvmDependency
|
import kotlin.script.experimental.jvm.JvmDependency
|
||||||
import kotlin.script.experimental.jvm.impl.*
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||||
|
import kotlin.script.experimental.jvm.impl.copyWithoutModule
|
||||||
|
import kotlin.script.experimental.jvm.impl.scriptMetadataPath
|
||||||
|
import kotlin.script.experimental.jvm.impl.toBytes
|
||||||
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
|
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContext
|
||||||
import kotlin.script.experimental.jvmhost.impl.KJvmCompiledModuleInMemory
|
|
||||||
|
|
||||||
// TODO: generate execution code (main)
|
// TODO: generate execution code (main)
|
||||||
|
|
||||||
|
|||||||
-29
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.project.Project
|
|
||||||
import org.jetbrains.kotlin.cli.common.repl.IReplStageHistory
|
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
|
||||||
import kotlin.script.experimental.api.*
|
|
||||||
|
|
||||||
interface KJvmReplCompilerProxy {
|
|
||||||
fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation
|
|
||||||
|
|
||||||
fun checkSyntax(
|
|
||||||
script: SourceCode,
|
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
|
||||||
project: Project
|
|
||||||
): ResultWithDiagnostics<Boolean>
|
|
||||||
|
|
||||||
|
|
||||||
fun compileReplSnippet(
|
|
||||||
compilationState: JvmReplCompilerState.Compilation,
|
|
||||||
snippet: SourceCode,
|
|
||||||
snippetId: ReplSnippetId,
|
|
||||||
history: IReplStageHistory<ScriptDescriptor>
|
|
||||||
): ResultWithDiagnostics<CompiledScript<*>>
|
|
||||||
}
|
|
||||||
+6
-80
@@ -5,18 +5,15 @@
|
|||||||
|
|
||||||
package kotlin.script.experimental.jvmhost.repl
|
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.common.repl.*
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerImpl
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState
|
||||||
import org.jetbrains.kotlin.scripting.repl.ReplCodeAnalyzer
|
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.KJvmReplCompilerProxy
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||||
import kotlin.concurrent.write
|
import kotlin.concurrent.write
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvmhost.impl.KJvmReplCompilerImpl
|
|
||||||
import kotlin.script.experimental.jvmhost.impl.withDefaults
|
import kotlin.script.experimental.jvmhost.impl.withDefaults
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +22,9 @@ import kotlin.script.experimental.jvmhost.impl.withDefaults
|
|||||||
class JvmReplCompiler(
|
class JvmReplCompiler(
|
||||||
val scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
val scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
|
||||||
val replCompilerProxy: KJvmReplCompilerProxy = KJvmReplCompilerImpl(hostConfiguration.withDefaults())
|
val replCompilerProxy: KJvmReplCompilerProxy = KJvmReplCompilerImpl(
|
||||||
|
hostConfiguration.withDefaults()
|
||||||
|
)
|
||||||
) : ReplCompiler {
|
) : ReplCompiler {
|
||||||
|
|
||||||
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JvmReplCompilerState(replCompilerProxy, lock)
|
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = JvmReplCompilerState(replCompilerProxy, lock)
|
||||||
@@ -69,79 +68,6 @@ class JvmReplCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
internal class SourceCodeFromReplCodeLine(
|
||||||
val codeLine: ReplCodeLine,
|
val codeLine: ReplCodeLine,
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile(project(":kotlin-main-kts"))
|
testCompile(project(":kotlin-main-kts"))
|
||||||
|
testCompileOnly(project(":compiler:cli"))
|
||||||
testCompile(project(":kotlin-scripting-jvm-host-embeddable"))
|
testCompile(project(":kotlin-scripting-jvm-host-embeddable"))
|
||||||
testCompile(commonDep("junit"))
|
testCompile(commonDep("junit"))
|
||||||
|
testCompile(projectTests(":kotlin-scripting-compiler")) { isTransitive = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
|||||||
+7
-3
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.mainKts.test
|
package org.jetbrains.kotlin.mainKts.test
|
||||||
|
|
||||||
import junit.framework.Assert.*
|
import junit.framework.Assert.*
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.runWithK2JVMCompiler
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@@ -71,9 +72,7 @@ class mainKtsIT {
|
|||||||
assertFalse("stderr thread not finished", stderrThread.isAlive)
|
assertFalse("stderr thread not finished", stderrThread.isAlive)
|
||||||
assertNull(stderrException.value)
|
assertNull(stderrException.value)
|
||||||
assertEquals(expectedOutPatterns.size, processOut.size)
|
assertEquals(expectedOutPatterns.size, processOut.size)
|
||||||
for (i in 0 until expectedOutPatterns.size) {
|
for ((expectedPattern, actualLine) in expectedOutPatterns.zip(processOut)) {
|
||||||
val expectedPattern = expectedOutPatterns[i]
|
|
||||||
val actualLine = processOut[i]
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"line \"$actualLine\" do not match with expected pattern \"$expectedPattern\"",
|
"line \"$actualLine\" do not match with expected pattern \"$expectedPattern\"",
|
||||||
Regex(expectedPattern).matches(actualLine)
|
Regex(expectedPattern).matches(actualLine)
|
||||||
@@ -92,4 +91,9 @@ class mainKtsIT {
|
|||||||
fun testResolveJunit() {
|
fun testResolveJunit() {
|
||||||
runWithKotlinc("$TEST_DATA_ROOT/hello-resolve-junit.main.kts", listOf("Hello, World!"))
|
runWithKotlinc("$TEST_DATA_ROOT/hello-resolve-junit.main.kts", listOf("Hello, World!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testImport() {
|
||||||
|
runWithK2JVMCompiler("$TEST_DATA_ROOT/import-test.main.kts", listOf("Hi from common", "Hi from middle", "sharedVar == 5"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import kotlin.script.experimental.jvm.jvm
|
|||||||
import kotlin.script.experimental.jvm.updateClasspath
|
import kotlin.script.experimental.jvm.updateClasspath
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@KotlinScript(fileExtension = "main.kts", compilationConfiguration = MainKtsScriptDefinition::class)
|
@KotlinScript(
|
||||||
|
fileExtension = "main.kts",
|
||||||
|
compilationConfiguration = MainKtsScriptDefinition::class,
|
||||||
|
evaluationConfiguration = MainKtsEvaluationConfiguration::class
|
||||||
|
)
|
||||||
abstract class MainKtsScript(val args: Array<String>)
|
abstract class MainKtsScript(val args: Array<String>)
|
||||||
|
|
||||||
object MainKtsScriptDefinition : ScriptCompilationConfiguration(
|
object MainKtsScriptDefinition : ScriptCompilationConfiguration(
|
||||||
@@ -40,6 +44,12 @@ object MainKtsScriptDefinition : ScriptCompilationConfiguration(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
object MainKtsEvaluationConfiguration : ScriptEvaluationConfiguration(
|
||||||
|
{
|
||||||
|
scriptsInstancesSharing(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
|
class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler {
|
||||||
private val resolver = FilesAndIvyResolver()
|
private val resolver = FilesAndIvyResolver()
|
||||||
|
|
||||||
|
|||||||
+33
-3
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.scripting.compiler.plugin
|
package org.jetbrains.kotlin.scripting.compiler.plugin
|
||||||
|
|
||||||
import com.intellij.core.JavaCoreProjectEnvironment
|
import com.intellij.core.JavaCoreProjectEnvironment
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR
|
import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR
|
||||||
@@ -16,12 +17,17 @@ import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension
|
|||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerFromEnvironment
|
||||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
|
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.script.experimental.api.constructorArgs
|
||||||
|
import kotlin.script.experimental.api.valueOr
|
||||||
|
import kotlin.script.experimental.api.with
|
||||||
|
import kotlin.script.experimental.host.toScriptSource
|
||||||
|
import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator
|
||||||
|
|
||||||
class JvmCliScriptEvaluationExtension : ScriptEvaluationExtension {
|
class JvmCliScriptEvaluationExtension : ScriptEvaluationExtension {
|
||||||
override fun isAccepted(arguments: CommonCompilerArguments): Boolean =
|
override fun isAccepted(arguments: CommonCompilerArguments): Boolean =
|
||||||
@@ -42,7 +48,7 @@ class JvmCliScriptEvaluationExtension : ScriptEvaluationExtension {
|
|||||||
|
|
||||||
configuration.addKotlinSourceRoot(sourcePath)
|
configuration.addKotlinSourceRoot(sourcePath)
|
||||||
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||||
val coreEnvironment =
|
val environment =
|
||||||
KotlinCoreEnvironment.createForProduction(projectEnvironment, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
KotlinCoreEnvironment.createForProduction(projectEnvironment, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||||
|
|
||||||
val scriptFile = File(sourcePath)
|
val scriptFile = File(sourcePath)
|
||||||
@@ -54,8 +60,32 @@ class JvmCliScriptEvaluationExtension : ScriptEvaluationExtension {
|
|||||||
return COMPILATION_ERROR
|
return COMPILATION_ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val script = scriptFile.toScriptSource()
|
||||||
|
|
||||||
|
val definition = scriptDefinitionProvider.findDefinition(scriptFile) ?: scriptDefinitionProvider.getDefaultDefinition()
|
||||||
|
|
||||||
val scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size)
|
val scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size)
|
||||||
|
|
||||||
return KotlinToJVMBytecodeCompiler.compileAndExecuteScript(coreEnvironment, scriptArgs)
|
val evaluationConfiguration = definition.evaluationConfiguration.with {
|
||||||
|
constructorArgs(scriptArgs.toTypedArray())
|
||||||
|
}
|
||||||
|
val scriptCompilationConfiguration = definition.compilationConfiguration
|
||||||
|
|
||||||
|
val scriptCompiler = ScriptJvmCompilerFromEnvironment(environment)
|
||||||
|
|
||||||
|
return runBlocking {
|
||||||
|
val compiledScript =
|
||||||
|
scriptCompiler.compile(script, scriptCompilationConfiguration)
|
||||||
|
.valueOr { return@runBlocking COMPILATION_ERROR }
|
||||||
|
/*val evalResult = */
|
||||||
|
BasicJvmScriptEvaluator().invoke(compiledScript, evaluationConfiguration)
|
||||||
|
.valueOr {
|
||||||
|
for (report in it.reports) {
|
||||||
|
messageCollector.report(ERROR, report.toString())
|
||||||
|
}
|
||||||
|
return@runBlocking ExitCode.SCRIPT_EXECUTION_ERROR
|
||||||
|
}
|
||||||
|
ExitCode.OK
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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.scripting.compiler.plugin
|
||||||
|
|
||||||
|
import kotlin.script.experimental.api.CompiledScript
|
||||||
|
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||||
|
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||||
|
import kotlin.script.experimental.api.SourceCode
|
||||||
|
|
||||||
|
interface ScriptJvmCompilerProxy {
|
||||||
|
fun compile(
|
||||||
|
script: SourceCode,
|
||||||
|
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||||
|
): ResultWithDiagnostics<CompiledScript<*>>
|
||||||
|
}
|
||||||
+1
-1
@@ -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.
|
* 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.impl
|
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.BytesUrlUtils
|
import org.jetbrains.kotlin.codegen.BytesUrlUtils
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
+1
-1
@@ -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.
|
* 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.impl
|
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledModule
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledModule
|
||||||
+41
-11
@@ -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.
|
* 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.impl
|
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
@@ -20,18 +20,23 @@ import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
|||||||
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.repl.KJvmReplCompilerProxy
|
||||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||||
import org.jetbrains.kotlin.scripting.repl.ReplCodeAnalyzer
|
import org.jetbrains.kotlin.scripting.repl.ReplCodeAnalyzer
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvmhost.repl.JvmReplCompilerState
|
|
||||||
import kotlin.script.experimental.jvmhost.repl.KJvmReplCompilerProxy
|
|
||||||
|
|
||||||
class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvmReplCompilerProxy {
|
class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvmReplCompilerProxy {
|
||||||
|
|
||||||
override fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation {
|
override fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation {
|
||||||
val context = withMessageCollectorAndDisposable(disposeOnSuccess = false) { messageCollector, disposable ->
|
val context = withMessageCollectorAndDisposable(disposeOnSuccess = false) { messageCollector, disposable ->
|
||||||
createSharedCompilationContext(scriptCompilationConfiguration, hostConfiguration, messageCollector, disposable).asSuccess()
|
createIsolatedCompilationContext(
|
||||||
|
scriptCompilationConfiguration,
|
||||||
|
hostConfiguration,
|
||||||
|
messageCollector,
|
||||||
|
disposable
|
||||||
|
).asSuccess()
|
||||||
}.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") }
|
}.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") }
|
||||||
return ReplCompilationState(context)
|
return ReplCompilationState(context)
|
||||||
}
|
}
|
||||||
@@ -42,7 +47,12 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
|||||||
project: Project
|
project: Project
|
||||||
): ResultWithDiagnostics<Boolean> =
|
): ResultWithDiagnostics<Boolean> =
|
||||||
withMessageCollector(script) { messageCollector ->
|
withMessageCollector(script) { messageCollector ->
|
||||||
val ktFile = getScriptKtFile(script, scriptCompilationConfiguration, project, messageCollector)
|
val ktFile = getScriptKtFile(
|
||||||
|
script,
|
||||||
|
scriptCompilationConfiguration,
|
||||||
|
project,
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
.valueOr { return it }
|
.valueOr { return it }
|
||||||
val errorHolder = object : MessageCollectorBasedReporter {
|
val errorHolder = object : MessageCollectorBasedReporter {
|
||||||
override val messageCollector = messageCollector
|
override val messageCollector = messageCollector
|
||||||
@@ -80,19 +90,34 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
val snippetKtFile =
|
val snippetKtFile =
|
||||||
getScriptKtFile(snippet, context.baseScriptCompilationConfiguration, context.environment.project, messageCollector)
|
getScriptKtFile(
|
||||||
|
snippet,
|
||||||
|
context.baseScriptCompilationConfiguration,
|
||||||
|
context.environment.project,
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
.valueOr { return it }
|
.valueOr { return it }
|
||||||
|
|
||||||
val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment(context, snippetKtFile, messageCollector)
|
val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment(
|
||||||
|
context,
|
||||||
|
snippetKtFile,
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
|
|
||||||
val analysisResult =
|
val analysisResult =
|
||||||
compilationState.analyzerEngine.analyzeReplLineWithImportedScripts(snippetKtFile, sourceFiles.drop(1), codeLine)
|
compilationState.analyzerEngine.analyzeReplLineWithImportedScripts(snippetKtFile, sourceFiles.drop(1), codeLine)
|
||||||
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
|
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
|
||||||
|
|
||||||
val scriptDescriptor = when (analysisResult) {
|
val scriptDescriptor = when (analysisResult) {
|
||||||
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return failure(messageCollector)
|
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return failure(
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||||
else -> return failure(snippet, messageCollector, "Unexpected result ${analysisResult::class.java}")
|
else -> return failure(
|
||||||
|
snippet,
|
||||||
|
messageCollector,
|
||||||
|
"Unexpected result ${analysisResult::class.java}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val type = (scriptDescriptor as ScriptDescriptor).resultValue?.returnType
|
val type = (scriptDescriptor as ScriptDescriptor).resultValue?.returnType
|
||||||
@@ -121,7 +146,12 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
|||||||
|
|
||||||
val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project)
|
val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project)
|
||||||
val compiledScript =
|
val compiledScript =
|
||||||
makeCompiledScript(generationState, snippet, sourceFiles.first(), sourceDependencies) { ktFile ->
|
makeCompiledScript(
|
||||||
|
generationState,
|
||||||
|
snippet,
|
||||||
|
sourceFiles.first(),
|
||||||
|
sourceDependencies
|
||||||
|
) { ktFile ->
|
||||||
dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration
|
dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration
|
||||||
?: context.baseScriptCompilationConfiguration
|
?: context.baseScriptCompilationConfiguration
|
||||||
}
|
}
|
||||||
@@ -131,7 +161,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class ReplCompilationState(val context: SharedScriptCompilationContext) : JvmReplCompilerState.Compilation {
|
internal class ReplCompilationState(val context: SharedScriptCompilationContext) : JvmReplCompilerState.Compilation {
|
||||||
override val disposable: Disposable get() = context.disposable
|
override val disposable: Disposable? get() = context.disposable
|
||||||
override val baseScriptCompilationConfiguration: ScriptCompilationConfiguration get() = context.baseScriptCompilationConfiguration
|
override val baseScriptCompilationConfiguration: ScriptCompilationConfiguration get() = context.baseScriptCompilationConfiguration
|
||||||
override val environment: KotlinCoreEnvironment get() = context.environment
|
override val environment: KotlinCoreEnvironment get() = context.environment
|
||||||
override val analyzerEngine: ReplCodeAnalyzer by lazy {
|
override val analyzerEngine: ReplCodeAnalyzer by lazy {
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* 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.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
|
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.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||||
|
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||||
|
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
||||||
|
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptJvmCompilerProxy
|
||||||
|
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
|
||||||
|
import kotlin.script.experimental.api.*
|
||||||
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
|
|
||||||
|
class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguration) : ScriptJvmCompilerProxy {
|
||||||
|
|
||||||
|
override fun compile(
|
||||||
|
script: SourceCode,
|
||||||
|
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||||
|
): ResultWithDiagnostics<CompiledScript<*>> =
|
||||||
|
withMessageCollectorAndDisposable(script = script) { messageCollector, disposable ->
|
||||||
|
|
||||||
|
val context = createIsolatedCompilationContext(
|
||||||
|
scriptCompilationConfiguration, hostConfiguration, messageCollector, disposable
|
||||||
|
)
|
||||||
|
|
||||||
|
compileImpl(script, context, messageCollector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScriptJvmCompilerFromEnvironment(val environment: KotlinCoreEnvironment) : ScriptJvmCompilerProxy {
|
||||||
|
|
||||||
|
override fun compile(
|
||||||
|
script: SourceCode,
|
||||||
|
scriptCompilationConfiguration: ScriptCompilationConfiguration
|
||||||
|
): ResultWithDiagnostics<CompiledScript<*>> {
|
||||||
|
val parentMessageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]
|
||||||
|
return withMessageCollector(script = script, parentMessageCollector = parentMessageCollector) { messageCollector ->
|
||||||
|
|
||||||
|
val context = createCompilationContextFromEnvironment(scriptCompilationConfiguration, environment, messageCollector)
|
||||||
|
|
||||||
|
try {
|
||||||
|
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
|
||||||
|
|
||||||
|
compileImpl(script, context, messageCollector)
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (parentMessageCollector != null)
|
||||||
|
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, parentMessageCollector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun compileImpl(
|
||||||
|
script: SourceCode,
|
||||||
|
context: SharedScriptCompilationContext,
|
||||||
|
messageCollector: ScriptDiagnosticsMessageCollector
|
||||||
|
): ResultWithDiagnostics<CompiledScript<*>> {
|
||||||
|
val mainKtFile =
|
||||||
|
getScriptKtFile(
|
||||||
|
script,
|
||||||
|
context.baseScriptCompilationConfiguration,
|
||||||
|
context.environment.project,
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
|
.valueOr { return it }
|
||||||
|
|
||||||
|
val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment(
|
||||||
|
context,
|
||||||
|
mainKtFile,
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
|
|
||||||
|
val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project)
|
||||||
|
val analysisResult = analyze(sourceFiles, context.environment)
|
||||||
|
|
||||||
|
if (!analysisResult.shouldGenerateCode) return failure(
|
||||||
|
script,
|
||||||
|
messageCollector,
|
||||||
|
"no code to generate"
|
||||||
|
)
|
||||||
|
if (analysisResult.isError() || messageCollector.hasErrors()) return failure(
|
||||||
|
messageCollector
|
||||||
|
)
|
||||||
|
|
||||||
|
val generationState =
|
||||||
|
generate(analysisResult, sourceFiles, context.environment.configuration)
|
||||||
|
|
||||||
|
val compiledScript =
|
||||||
|
makeCompiledScript(
|
||||||
|
generationState,
|
||||||
|
script,
|
||||||
|
sourceFiles.first(),
|
||||||
|
sourceDependencies
|
||||||
|
) { ktFile ->
|
||||||
|
dependenciesProvider?.getScriptConfigurationResult(ktFile)?.valueOrNull()?.configuration
|
||||||
|
?: context.baseScriptCompilationConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultWithDiagnostics.Success(compiledScript, messageCollector.diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun analyze(sourceFiles: Collection<KtFile>, environment: KotlinCoreEnvironment): AnalysisResult {
|
||||||
|
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!!
|
||||||
|
|
||||||
|
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings)
|
||||||
|
|
||||||
|
analyzerWithCompilerReport.analyzeAndReport(sourceFiles) {
|
||||||
|
val project = environment.project
|
||||||
|
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||||
|
project,
|
||||||
|
sourceFiles,
|
||||||
|
NoScopeRecordCliBindingTrace(),
|
||||||
|
environment.configuration,
|
||||||
|
environment::createPackagePartProvider
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return analyzerWithCompilerReport.analysisResult
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generate(
|
||||||
|
analysisResult: AnalysisResult, sourceFiles: List<KtFile>, kotlinCompilerConfiguration: CompilerConfiguration
|
||||||
|
): GenerationState {
|
||||||
|
val generationState = GenerationState.Builder(
|
||||||
|
sourceFiles.first().project,
|
||||||
|
ClassBuilderFactories.BINARIES,
|
||||||
|
analysisResult.moduleDescriptor,
|
||||||
|
analysisResult.bindingContext,
|
||||||
|
sourceFiles,
|
||||||
|
kotlinCompilerConfiguration
|
||||||
|
).build()
|
||||||
|
|
||||||
|
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
|
||||||
|
return generationState
|
||||||
|
}
|
||||||
+34
-9
@@ -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.
|
* 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.impl
|
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
@@ -42,14 +42,14 @@ import kotlin.script.experimental.jvm.util.KotlinJars
|
|||||||
import kotlin.script.experimental.jvm.withUpdatedClasspath
|
import kotlin.script.experimental.jvm.withUpdatedClasspath
|
||||||
|
|
||||||
internal class SharedScriptCompilationContext(
|
internal class SharedScriptCompilationContext(
|
||||||
val disposable: Disposable,
|
val disposable: Disposable?,
|
||||||
val baseScriptCompilationConfiguration: ScriptCompilationConfiguration,
|
val baseScriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
val environment: KotlinCoreEnvironment,
|
val environment: KotlinCoreEnvironment,
|
||||||
val ignoredOptionsReportingState: IgnoredOptionsReportingState
|
val ignoredOptionsReportingState: IgnoredOptionsReportingState
|
||||||
)
|
)
|
||||||
|
|
||||||
internal fun createSharedCompilationContext(
|
internal fun createIsolatedCompilationContext(
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
baseScriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
hostConfiguration: ScriptingHostConfiguration,
|
hostConfiguration: ScriptingHostConfiguration,
|
||||||
messageCollector: ScriptDiagnosticsMessageCollector,
|
messageCollector: ScriptDiagnosticsMessageCollector,
|
||||||
disposable: Disposable
|
disposable: Disposable
|
||||||
@@ -57,9 +57,7 @@ internal fun createSharedCompilationContext(
|
|||||||
val ignoredOptionsReportingState = IgnoredOptionsReportingState()
|
val ignoredOptionsReportingState = IgnoredOptionsReportingState()
|
||||||
|
|
||||||
val (initialScriptCompilationConfiguration, kotlinCompilerConfiguration) =
|
val (initialScriptCompilationConfiguration, kotlinCompilerConfiguration) =
|
||||||
createInitialConfigurations(
|
createInitialConfigurations(baseScriptCompilationConfiguration, hostConfiguration, messageCollector, ignoredOptionsReportingState)
|
||||||
scriptCompilationConfiguration, hostConfiguration, messageCollector, ignoredOptionsReportingState
|
|
||||||
)
|
|
||||||
val environment =
|
val environment =
|
||||||
KotlinCoreEnvironment.createForProduction(
|
KotlinCoreEnvironment.createForProduction(
|
||||||
disposable, kotlinCompilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES
|
disposable, kotlinCompilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||||
@@ -70,6 +68,25 @@ internal fun createSharedCompilationContext(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun createCompilationContextFromEnvironment(
|
||||||
|
baseScriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
|
environment: KotlinCoreEnvironment,
|
||||||
|
messageCollector: ScriptDiagnosticsMessageCollector
|
||||||
|
): SharedScriptCompilationContext {
|
||||||
|
val ignoredOptionsReportingState = IgnoredOptionsReportingState()
|
||||||
|
|
||||||
|
val initialScriptCompilationConfiguration =
|
||||||
|
baseScriptCompilationConfiguration.withUpdatesFromCompilerConfiguration(environment.configuration)
|
||||||
|
|
||||||
|
initialScriptCompilationConfiguration[ScriptCompilationConfiguration.compilerOptions]?.let { compilerOptions ->
|
||||||
|
environment.configuration.updateWithCompilerOptions(compilerOptions, messageCollector, ignoredOptionsReportingState, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return SharedScriptCompilationContext(
|
||||||
|
null, initialScriptCompilationConfiguration, environment, ignoredOptionsReportingState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun createInitialConfigurations(
|
internal fun createInitialConfigurations(
|
||||||
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
hostConfiguration: ScriptingHostConfiguration,
|
hostConfiguration: ScriptingHostConfiguration,
|
||||||
@@ -105,9 +122,17 @@ private fun CompilerConfiguration.updateWithCompilerOptions(
|
|||||||
val compilerArguments = K2JVMCompilerArguments()
|
val compilerArguments = K2JVMCompilerArguments()
|
||||||
parseCommandLineArguments(compilerOptions, compilerArguments)
|
parseCommandLineArguments(compilerOptions, compilerArguments)
|
||||||
|
|
||||||
reportArgumentsIgnoredGenerally(compilerArguments, messageCollector, ignoredOptionsReportingState)
|
reportArgumentsIgnoredGenerally(
|
||||||
|
compilerArguments,
|
||||||
|
messageCollector,
|
||||||
|
ignoredOptionsReportingState
|
||||||
|
)
|
||||||
if (isRefinement) {
|
if (isRefinement) {
|
||||||
reportArgumentsIgnoredFromRefinement(compilerArguments, messageCollector, ignoredOptionsReportingState)
|
reportArgumentsIgnoredFromRefinement(
|
||||||
|
compilerArguments,
|
||||||
|
messageCollector,
|
||||||
|
ignoredOptionsReportingState
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupCommonArguments(compilerArguments)
|
setupCommonArguments(compilerArguments)
|
||||||
+5
-4
@@ -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.
|
* 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.impl
|
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.cli.common.arguments.Argument
|
import org.jetbrains.kotlin.cli.common.arguments.Argument
|
||||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||||
@@ -17,7 +17,7 @@ import kotlin.script.experimental.api.ScriptDiagnostic
|
|||||||
import kotlin.script.experimental.api.SourceCode
|
import kotlin.script.experimental.api.SourceCode
|
||||||
import kotlin.script.experimental.api.asErrorDiagnostics
|
import kotlin.script.experimental.api.asErrorDiagnostics
|
||||||
|
|
||||||
internal class ScriptDiagnosticsMessageCollector : MessageCollector {
|
internal class ScriptDiagnosticsMessageCollector(private val parentMessageCollector: MessageCollector?) : MessageCollector {
|
||||||
|
|
||||||
private val _diagnostics = arrayListOf<ScriptDiagnostic>()
|
private val _diagnostics = arrayListOf<ScriptDiagnostic>()
|
||||||
|
|
||||||
@@ -25,11 +25,11 @@ internal class ScriptDiagnosticsMessageCollector : MessageCollector {
|
|||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
_diagnostics.clear()
|
_diagnostics.clear()
|
||||||
|
parentMessageCollector?.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasErrors(): Boolean =
|
override fun hasErrors(): Boolean =
|
||||||
_diagnostics.any { it.severity == ScriptDiagnostic.Severity.ERROR }
|
_diagnostics.any { it.severity == ScriptDiagnostic.Severity.ERROR } || parentMessageCollector?.hasErrors() == true
|
||||||
|
|
||||||
|
|
||||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
|
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
|
||||||
val mappedSeverity = when (severity) {
|
val mappedSeverity = when (severity) {
|
||||||
@@ -53,6 +53,7 @@ internal class ScriptDiagnosticsMessageCollector : MessageCollector {
|
|||||||
}
|
}
|
||||||
_diagnostics.add(ScriptDiagnostic(message, mappedSeverity, location?.path, mappedLocation))
|
_diagnostics.add(ScriptDiagnostic(message, mappedSeverity, location?.path, mappedLocation))
|
||||||
}
|
}
|
||||||
|
parentMessageCollector?.report(severity, message, location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+23
-12
@@ -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.
|
* 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.impl
|
package org.jetbrains.kotlin.scripting.compiler.plugin.impl
|
||||||
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
@@ -11,6 +11,7 @@ import com.intellij.openapi.util.Disposer
|
|||||||
import com.intellij.psi.PsiFileFactory
|
import com.intellij.psi.PsiFileFactory
|
||||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||||
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
|
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
@@ -22,7 +23,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.FileBasedScriptSource
|
import kotlin.script.experimental.host.FileBasedScriptSource
|
||||||
import kotlin.script.experimental.host.FileScriptSource
|
|
||||||
import kotlin.script.experimental.host.getMergedScriptText
|
import kotlin.script.experimental.host.getMergedScriptText
|
||||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||||
|
|
||||||
@@ -43,13 +43,14 @@ internal fun SourceCode.scriptFileName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun <T> withMessageCollectorAndDisposable(
|
internal inline fun <T> withMessageCollectorAndDisposable(
|
||||||
messageCollector: ScriptDiagnosticsMessageCollector = ScriptDiagnosticsMessageCollector(),
|
script: SourceCode? = null,
|
||||||
|
parentMessageCollector: MessageCollector? = null,
|
||||||
disposable: Disposable = Disposer.newDisposable(),
|
disposable: Disposable = Disposer.newDisposable(),
|
||||||
disposeOnSuccess: Boolean = true,
|
disposeOnSuccess: Boolean = true,
|
||||||
locationId: String? = null,
|
|
||||||
body: (ScriptDiagnosticsMessageCollector, Disposable) -> ResultWithDiagnostics<T>
|
body: (ScriptDiagnosticsMessageCollector, Disposable) -> ResultWithDiagnostics<T>
|
||||||
): ResultWithDiagnostics<T> {
|
): ResultWithDiagnostics<T> {
|
||||||
var failed = false
|
var failed = false
|
||||||
|
val messageCollector = ScriptDiagnosticsMessageCollector(parentMessageCollector)
|
||||||
return try {
|
return try {
|
||||||
setIdeaIoUseFallback()
|
setIdeaIoUseFallback()
|
||||||
body(messageCollector, disposable).also {
|
body(messageCollector, disposable).also {
|
||||||
@@ -57,7 +58,7 @@ internal inline fun <T> withMessageCollectorAndDisposable(
|
|||||||
}
|
}
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
failed = true
|
failed = true
|
||||||
failure(messageCollector, ex.asDiagnostics(path = locationId))
|
failure(messageCollector, ex.asDiagnostics(path = script?.locationId))
|
||||||
} finally {
|
} finally {
|
||||||
if (disposeOnSuccess || failed) {
|
if (disposeOnSuccess || failed) {
|
||||||
Disposer.dispose(disposable)
|
Disposer.dispose(disposable)
|
||||||
@@ -66,15 +67,17 @@ internal inline fun <T> withMessageCollectorAndDisposable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun <T> withMessageCollector(
|
internal inline fun <T> withMessageCollector(
|
||||||
script: SourceCode,
|
script: SourceCode? = null,
|
||||||
messageCollector: ScriptDiagnosticsMessageCollector = ScriptDiagnosticsMessageCollector(),
|
parentMessageCollector: MessageCollector? = null,
|
||||||
body: (ScriptDiagnosticsMessageCollector) -> ResultWithDiagnostics<T>
|
body: (ScriptDiagnosticsMessageCollector) -> ResultWithDiagnostics<T>
|
||||||
): ResultWithDiagnostics<T> =
|
): ResultWithDiagnostics<T> {
|
||||||
try {
|
val messageCollector = ScriptDiagnosticsMessageCollector(parentMessageCollector)
|
||||||
|
return try {
|
||||||
body(messageCollector)
|
body(messageCollector)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
failure(messageCollector, ex.asDiagnostics(path = script.locationId))
|
failure(messageCollector, ex.asDiagnostics(path = script?.locationId))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun getScriptKtFile(
|
internal fun getScriptKtFile(
|
||||||
script: SourceCode,
|
script: SourceCode,
|
||||||
@@ -91,8 +94,16 @@ internal fun getScriptKtFile(
|
|||||||
)
|
)
|
||||||
val ktFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
val ktFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
||||||
return when {
|
return when {
|
||||||
ktFile == null -> failure(script, messageCollector, "Unable to make PSI file from script")
|
ktFile == null -> failure(
|
||||||
ktFile.declarations.firstIsInstanceOrNull<KtScript>() == null -> failure(script, messageCollector, "Not a script file")
|
script,
|
||||||
|
messageCollector,
|
||||||
|
"Unable to make PSI file from script"
|
||||||
|
)
|
||||||
|
ktFile.declarations.firstIsInstanceOrNull<KtScript>() == null -> failure(
|
||||||
|
script,
|
||||||
|
messageCollector,
|
||||||
|
"Not a script file"
|
||||||
|
)
|
||||||
else -> ktFile.asSuccess()
|
else -> ktFile.asSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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.scripting.compiler.plugin.repl
|
||||||
|
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
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.*
|
||||||
|
|
||||||
|
interface KJvmReplCompilerProxy {
|
||||||
|
fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation
|
||||||
|
|
||||||
|
fun checkSyntax(
|
||||||
|
script: SourceCode,
|
||||||
|
scriptCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
|
project: Project
|
||||||
|
): ResultWithDiagnostics<Boolean>
|
||||||
|
|
||||||
|
|
||||||
|
fun compileReplSnippet(
|
||||||
|
compilationState: JvmReplCompilerState.Compilation,
|
||||||
|
snippet: SourceCode,
|
||||||
|
snippetId: ReplSnippetId,
|
||||||
|
history: IReplStageHistory<ScriptDescriptor>
|
||||||
|
): ResultWithDiagnostics<CompiledScript<*>>
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user