Remove ScriptCompileConfiguration as separate entity, refactor pieces accordingly

This commit is contained in:
Ilya Chernikov
2018-08-17 17:51:48 +02:00
parent bda8089004
commit acb0f6c6a9
18 changed files with 88 additions and 148 deletions
@@ -14,17 +14,13 @@ import kotlin.script.experimental.host.BasicScriptingHost
import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment
open class BasicJvmScriptingHost(
scriptDefinition: ScriptDefinition,
hostEnvironment: ScriptingEnvironment = defaultJvmScriptingEnvironment,
compiler: JvmScriptCompiler = JvmScriptCompiler(hostEnvironment),
evaluator: ScriptEvaluator = BasicJvmScriptEvaluator()
) : BasicScriptingHost(scriptDefinition, compiler, evaluator)
) : BasicScriptingHost(compiler, evaluator)
inline fun <reified T : Any> makeBasicHostFromAnnotatedScriptBaseClass(
hostEnvironment: ScriptingEnvironment = defaultJvmScriptingEnvironment
) =
BasicJvmScriptingHost(
createScriptDefinitionFromAnnotatedBaseClass(KotlinType(T::class), hostEnvironment),
hostEnvironment
)
inline fun <reified T : Any> createBasicScriptDefinitionFromAnnotatedBaseClass(
hostEnvironment: ScriptingEnvironment = defaultJvmScriptingEnvironment,
noinline body: ScriptDefinition.Builder.() -> Unit = {}
): ScriptDefinition = createScriptDefinitionFromAnnotatedBaseClass(KotlinType(T::class), hostEnvironment, ScriptDefinition::class, body)
@@ -47,12 +47,10 @@ import kotlin.script.experimental.jvmhost.JvmScriptEvaluationEnvironment
import kotlin.script.experimental.jvmhost.KJvmCompilerProxy
import kotlin.script.experimental.jvmhost.baseClassLoader
import kotlin.script.experimental.util.getFirstFromChainOrNull
import kotlin.script.experimental.util.getMergedFromChainOrNull
import kotlin.script.experimental.util.getOrError
class KJvmCompiledScript<out ScriptBase : Any>(
override val definition: ScriptDefinition,
override val additionalConfiguration: ScriptCompileConfiguration?,
private val generationState: GenerationState,
private val scriptClassFQName: String
) : CompiledScript<ScriptBase> {
@@ -60,7 +58,7 @@ class KJvmCompiledScript<out ScriptBase : Any>(
override suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment?): ResultWithDiagnostics<ScriptBase> = try {
val baseClassLoader = scriptEvaluationEnvironment?.get(JvmScriptEvaluationEnvironment.baseClassLoader)
?: Thread.currentThread().contextClassLoader
val dependencies = additionalConfiguration?.get(ScriptDefinition.dependencies)
val dependencies = definition[ScriptDefinition.dependencies]
?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() }
// TODO: previous dependencies and classloaders should be taken into account here
val classLoaderWithDeps =
@@ -80,8 +78,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
override fun compile(
script: ScriptSource,
scriptDefinition: ScriptDefinition,
additionalConfiguration: ScriptCompileConfiguration?
scriptDefinition: ScriptDefinition
): ResultWithDiagnostics<CompiledScript<*>> {
val messageCollector = ScriptDiagnosticsMessageCollector()
@@ -92,13 +89,12 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
setIdeaIoUseFallback()
var environment: KotlinCoreEnvironment? = null
var updatedScriptCompileConfiguration = additionalConfiguration
var updatedDefinition = scriptDefinition
fun updateClasspath(classpath: List<File>) {
environment!!.updateClasspath(classpath.map(::JvmClasspathRoot))
if (classpath.isNotEmpty()) {
updatedScriptCompileConfiguration = ScriptCompileConfiguration {
include(updatedScriptCompileConfiguration)
updatedDefinition = ScriptDefinition(updatedDefinition) {
dependencies.append(JvmDependency(classpath))
}
}
@@ -108,20 +104,20 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
val kotlinCompilerConfiguration = org.jetbrains.kotlin.config.CompilerConfiguration().apply {
add(
JVMConfigurationKeys.SCRIPT_DEFINITIONS,
BridgeScriptDefinition(scriptDefinition, additionalConfiguration, hostEnvironment, ::updateClasspath)
BridgeScriptDefinition(scriptDefinition, hostEnvironment, ::updateClasspath)
)
put<MessageCollector>(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
var isModularJava = false
getFirstFromChainOrNull(ScriptCompileConfiguration.jvm.javaHome, updatedScriptCompileConfiguration, hostEnvironment)?.let {
getFirstFromChainOrNull(ScriptDefinition.jvm.javaHome, updatedDefinition, hostEnvironment)?.let {
put(JVMConfigurationKeys.JDK_HOME, it)
isModularJava = CoreJrtFileSystem.isModularJdk(it)
}
getMergedFromChainOrNull(ScriptDefinition.dependencies, scriptDefinition, updatedScriptCompileConfiguration)?.let {
updatedDefinition[ScriptDefinition.dependencies]?.let { dependencies ->
addJvmClasspathRoots(
it.flatMap {
dependencies.flatMap {
(it as JvmDependency).classpath
}
)
@@ -151,7 +147,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings)
val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
val scriptText = getMergedScriptText(script, updatedScriptCompileConfiguration)
val scriptText = getMergedScriptText(script, updatedDefinition)
val scriptFileName = "script" // TODO: extract from file/url if available
val virtualFile = LightVirtualFile(
"$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}",
@@ -196,7 +192,7 @@ class KJvmCompilerImpl(val hostEnvironment: ScriptingEnvironment) : KJvmCompiler
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION
)
val res = KJvmCompiledScript<Any>(scriptDefinition, updatedScriptCompileConfiguration, generationState, scriptFileName.capitalize())
val res = KJvmCompiledScript<Any>(updatedDefinition, generationState, scriptFileName.capitalize())
return ResultWithDiagnostics.Success(res, messageCollector.diagnostics)
} catch (ex: Throwable) {
@@ -242,7 +238,6 @@ class ScriptDiagnosticsMessageCollector : MessageCollector {
internal class BridgeScriptDefinition(
scriptDefinition: ScriptDefinition,
additionalCompilationConfiguration: ScriptCompileConfiguration?,
hostEnvironment: ScriptingEnvironment,
updateClasspath: (List<File>) -> Unit
) : KotlinScriptDefinition(
@@ -253,12 +248,11 @@ internal class BridgeScriptDefinition(
) {
override val acceptedAnnotations = run {
val cl = this::class.java.classLoader
getFirstFromChainOrNull(ScriptDefinition.refineConfigurationOnAnnotations, scriptDefinition, additionalCompilationConfiguration)
?.annotations
scriptDefinition[ScriptDefinition.refineConfigurationOnAnnotations]?.annotations
?.map { (cl.loadClass(it.typeName) as Class<out Annotation>).kotlin }
?: emptyList()
}
override val dependencyResolver: DependenciesResolver =
BridgeDependenciesResolver(scriptDefinition, additionalCompilationConfiguration, updateClasspath)
BridgeDependenciesResolver(scriptDefinition, updateClasspath)
}
@@ -5,23 +5,9 @@
package kotlin.script.experimental.jvmhost.impl
import kotlin.script.experimental.api.ScriptCompileConfiguration
import kotlin.script.experimental.api.ScriptingEnvironment
import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment
internal fun mergeConfigurations(vararg configurations: ScriptCompileConfiguration?): ScriptCompileConfiguration? {
val nonEmptyConfigurations = configurations.filter { it != null && it.properties.isNotEmpty() }
return when {
nonEmptyConfigurations.isEmpty() -> null
nonEmptyConfigurations.size == 1 -> nonEmptyConfigurations.first()!!
else -> ScriptCompileConfiguration {
for (configuration in nonEmptyConfigurations) {
include(configuration!!)
}
}
}
}
fun ScriptingEnvironment.withDefaults(): ScriptingEnvironment =
if (this == defaultJvmScriptingEnvironment || defaultJvmScriptingEnvironment.properties.all {
this.properties.containsKey(it.key)
@@ -10,20 +10,19 @@ package kotlin.script.experimental.jvmhost
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.defaultJvmScriptingEnvironment
import kotlin.script.experimental.jvmhost.impl.KJvmCompilerImpl
import kotlin.script.experimental.jvmhost.impl.mergeConfigurations
import kotlin.script.experimental.jvmhost.impl.withDefaults
interface CompiledJvmScriptsCache {
fun get(script: ScriptSource, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?): CompiledScript<*>?
fun store(compiledScript: CompiledScript<*>, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?)
fun get(script: ScriptSource, scriptDefinition: ScriptDefinition): CompiledScript<*>?
fun store(compiledScript: CompiledScript<*>, scriptDefinition: ScriptDefinition)
object NoCache : CompiledJvmScriptsCache {
override fun get(
script: ScriptSource, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?
script: ScriptSource, scriptDefinition: ScriptDefinition
): CompiledScript<*>? = null
override fun store(
compiledScript: CompiledScript<*>, scriptDefinition: ScriptDefinition, configuration: ScriptCompileConfiguration?
compiledScript: CompiledScript<*>, scriptDefinition: ScriptDefinition
) {
}
}
@@ -37,25 +36,23 @@ open class JvmScriptCompiler(
override suspend operator fun invoke(
script: ScriptSource,
scriptDefinition: ScriptDefinition,
additionalConfiguration: ScriptCompileConfiguration?
scriptDefinition: ScriptDefinition
): ResultWithDiagnostics<CompiledScript<*>> {
val refineConfigurationFn = scriptDefinition[ScriptDefinition.refineConfigurationBeforeParsing]
val refinedConfiguration =
refineConfigurationFn?.invoke(ScriptDataFacade(script, scriptDefinition, additionalConfiguration))?.let {
refineConfigurationFn?.handler?.invoke(ScriptDataFacade(script, scriptDefinition))?.let {
when (it) {
is ResultWithDiagnostics.Failure -> return it
is ResultWithDiagnostics.Success -> it.value
}
}
val actualConfiguration = mergeConfigurations(additionalConfiguration, refinedConfiguration)
val cached = cache.get(script, scriptDefinition, actualConfiguration)
} ?: scriptDefinition
val cached = cache.get(script, refinedConfiguration)
if (cached != null) return cached.asSuccess()
return compilerProxy.compile(script, scriptDefinition, actualConfiguration).also {
return compilerProxy.compile(script, refinedConfiguration).also {
if (it is ResultWithDiagnostics.Success) {
cache.store(it.value, scriptDefinition, actualConfiguration)
cache.store(it.value, refinedConfiguration)
}
}
}
@@ -64,8 +61,7 @@ open class JvmScriptCompiler(
interface KJvmCompilerProxy {
fun compile(
script: ScriptSource,
scriptDefinition: ScriptDefinition,
additionalConfiguration: ScriptCompileConfiguration?
scriptDefinition: ScriptDefinition
): ResultWithDiagnostics<CompiledScript<*>>
}