Refactor configurations handling:

- rearrange compile call parameters for clarity, more defaults
- remove baseConfiguration method - it is now covered by defaultConfiguration
for static part, and refineConfiguration call if a config parameter is
specified
- implement proper configurations chaining, documented in comment to compile function
- minor renamings and refactorings
This commit is contained in:
Ilya Chernikov
2018-03-28 16:08:45 +02:00
parent 4a4edf3458
commit 191b1cfefa
10 changed files with 48 additions and 35 deletions
@@ -39,7 +39,7 @@ val myJvmConfigParams = jvmJavaHomeParams + with(ScriptCompileConfigurationPrope
) )
) )
), ),
updateConfigurationOnAnnotations(DependsOn::class, Repository::class) refineConfigurationOnAnnotations(DependsOn::class, Repository::class)
) )
} }
@@ -49,9 +49,6 @@ class MyConfigurator(val environment: ScriptingEnvironment) : ScriptCompilationC
override val defaultConfiguration = ScriptCompileConfiguration(environment, myJvmConfigParams) override val defaultConfiguration = ScriptCompileConfiguration(environment, myJvmConfigParams)
override suspend fun baseConfiguration(scriptSource: ScriptSource): ResultWithDiagnostics<ScriptCompileConfiguration> =
defaultConfiguration.asSuccess()
override suspend fun refineConfiguration( override suspend fun refineConfiguration(
scriptSource: ScriptSource, scriptSource: ScriptSource,
configuration: ScriptCompileConfiguration, configuration: ScriptCompileConfiguration,
@@ -9,8 +9,8 @@ interface ScriptCompiler {
suspend fun compile( suspend fun compile(
script: ScriptSource, script: ScriptSource,
configuration: ScriptCompileConfiguration, configurator: ScriptCompilationConfigurator? = null,
configurator: ScriptCompilationConfigurator? = null additionalConfiguration: ScriptCompileConfiguration? = null // overrides parameters from configurator.defaultConfiguration
): ResultWithDiagnostics<CompiledScript<*>> ): ResultWithDiagnostics<CompiledScript<*>>
} }
@@ -21,8 +21,6 @@ interface ScriptCompilationConfigurator {
val defaultConfiguration: ScriptCompileConfiguration val defaultConfiguration: ScriptCompileConfiguration
suspend fun baseConfiguration(scriptSource: ScriptSource): ResultWithDiagnostics<ScriptCompileConfiguration>
suspend fun refineConfiguration( suspend fun refineConfiguration(
scriptSource: ScriptSource, scriptSource: ScriptSource,
configuration: ScriptCompileConfiguration, configuration: ScriptCompileConfiguration,
@@ -33,8 +33,10 @@ object ScriptCompileConfigurationProperties {
val compilerOptions by typedKey<List<String>>() // Q: CommonCompilerOptions instead? val compilerOptions by typedKey<List<String>>() // Q: CommonCompilerOptions instead?
val updateConfigurationOnAnnotations by typedKey<List<KClass<out Annotation>>>() val refineBeforeParsing by typedKey<Boolean>() // default: false
val updateConfigurationOnSections by typedKey<List<String>>() val refineConfigurationOnAnnotations by typedKey<List<KClass<out Annotation>>>()
val refineConfigurationOnSections by typedKey<List<String>>()
} }
@@ -12,9 +12,6 @@ class PassThroughCompilationConfigurator(val environment: ScriptingEnvironment)
override val defaultConfiguration = ScriptCompileConfiguration(environment) override val defaultConfiguration = ScriptCompileConfiguration(environment)
override suspend fun baseConfiguration(scriptSource: ScriptSource): ResultWithDiagnostics<ScriptCompileConfiguration> =
defaultConfiguration.asSuccess()
override suspend fun refineConfiguration( override suspend fun refineConfiguration(
script: ScriptSource, script: ScriptSource,
configuration: ScriptCompileConfiguration, configuration: ScriptCompileConfiguration,
@@ -35,7 +35,7 @@ abstract class BasicScriptingHost<ScriptBase : Any>(
environment: ScriptEvaluationEnvironment environment: ScriptEvaluationEnvironment
): ResultWithDiagnostics<EvaluationResult> = ): ResultWithDiagnostics<EvaluationResult> =
runInCoroutineContext { runInCoroutineContext {
val compiled = compiler.compile(script, compileConfiguration, configurator) val compiled = compiler.compile(script, configurator, compileConfiguration)
when (compiled) { when (compiled) {
is ResultWithDiagnostics.Failure -> compiled is ResultWithDiagnostics.Failure -> compiled
is ResultWithDiagnostics.Success -> { is ResultWithDiagnostics.Success -> {
@@ -17,12 +17,19 @@ class TypedKeyDelegate<T> {
fun <T> typedKey() = TypedKeyDelegate<T>() fun <T> typedKey() = TypedKeyDelegate<T>()
class ChainedPropertyBag(private val parent: ChainedPropertyBag? = null, pairs: Iterable<Pair<TypedKey<*>, Any?>>) { class ChainedPropertyBag private constructor(private val parent: ChainedPropertyBag?, private val data: Map<TypedKey<*>, Any?>) {
constructor(parent: ChainedPropertyBag? = null, pairs: Iterable<Pair<TypedKey<*>, Any?>>) :
this(parent, HashMap<TypedKey<*>, Any?>().also { it.putAll(pairs) })
constructor(pairs: Iterable<Pair<TypedKey<*>, Any?>>) : this(null, pairs) constructor(pairs: Iterable<Pair<TypedKey<*>, Any?>>) : this(null, pairs)
constructor(parent: ChainedPropertyBag, vararg pairs: Pair<TypedKey<*>, Any?>) : this(parent, pairs.asIterable()) constructor(parent: ChainedPropertyBag, vararg pairs: Pair<TypedKey<*>, Any?>) : this(parent, pairs.asIterable())
constructor(vararg pairs: Pair<TypedKey<*>, Any?>) : this(null, pairs.asIterable()) constructor(vararg pairs: Pair<TypedKey<*>, Any?>) : this(null, pairs.asIterable())
private val data = HashMap<TypedKey<*>, Any?>().also { it.putAll(pairs) } fun cloneWithNewParent(newParent: ChainedPropertyBag?): ChainedPropertyBag = when {
newParent == null -> this
parent == null -> ChainedPropertyBag(newParent, data)
else -> ChainedPropertyBag(parent.cloneWithNewParent(newParent), data)
}
inline operator fun <reified T> get(key: TypedKey<T>): T = getUnchecked(key) as T inline operator fun <reified T> get(key: TypedKey<T>): T = getUnchecked(key) as T
@@ -73,8 +73,8 @@ class KJVMCompilerImpl : KJVMCompilerProxy {
override fun compile( override fun compile(
script: ScriptSource, script: ScriptSource,
scriptCompilerConfiguration: ScriptCompileConfiguration, configurator: ScriptCompilationConfigurator?,
configurator: ScriptCompilationConfigurator? additionalConfiguration: ScriptCompileConfiguration
): ResultWithDiagnostics<CompiledScript<*>> { ): ResultWithDiagnostics<CompiledScript<*>> {
val messageCollector = ScriptDiagnosticsMessageCollector() val messageCollector = ScriptDiagnosticsMessageCollector()
@@ -83,7 +83,7 @@ class KJVMCompilerImpl : KJVMCompilerProxy {
try { try {
var environment: KotlinCoreEnvironment? = null var environment: KotlinCoreEnvironment? = null
var updatedScriptCompileConfiguration = scriptCompilerConfiguration var updatedScriptCompileConfiguration = additionalConfiguration
fun updateClasspath(classpath: List<File>) { fun updateClasspath(classpath: List<File>) {
environment!!.updateClasspath(classpath.map(::JvmClasspathRoot)) environment!!.updateClasspath(classpath.map(::JvmClasspathRoot))
@@ -100,19 +100,19 @@ class KJVMCompilerImpl : KJVMCompilerProxy {
val kotlinCompilerConfiguration = org.jetbrains.kotlin.config.CompilerConfiguration().apply { val kotlinCompilerConfiguration = org.jetbrains.kotlin.config.CompilerConfiguration().apply {
add( add(
JVMConfigurationKeys.SCRIPT_DEFINITIONS, JVMConfigurationKeys.SCRIPT_DEFINITIONS,
BridgeScriptDefinition(scriptCompilerConfiguration, configurator, ::updateClasspath) BridgeScriptDefinition(additionalConfiguration, configurator, ::updateClasspath)
) )
put<MessageCollector>(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) put<MessageCollector>(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
var isModularJava = false var isModularJava = false
scriptCompilerConfiguration.getOrNull(JvmScriptCompileConfigurationProperties.javaHomeDir)?.let { additionalConfiguration.getOrNull(JvmScriptCompileConfigurationProperties.javaHomeDir)?.let {
put(JVMConfigurationKeys.JDK_HOME, it) put(JVMConfigurationKeys.JDK_HOME, it)
isModularJava = CoreJrtFileSystem.isModularJdk(it) isModularJava = CoreJrtFileSystem.isModularJdk(it)
} }
var explicitStdlib = false var explicitStdlib = false
scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.dependencies)?.let { additionalConfiguration.getOrNull(ScriptCompileConfigurationProperties.dependencies)?.let {
addJvmClasspathRoots( addJvmClasspathRoots(
it.flatMap { it.flatMap {
(it as JvmDependency).classpath.also { (it as JvmDependency).classpath.also {
@@ -152,7 +152,7 @@ class KJVMCompilerImpl : KJVMCompilerProxy {
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings) val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings)
val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
val scriptText = getMergedScriptText(script, scriptCompilerConfiguration) val scriptText = getMergedScriptText(script, additionalConfiguration)
val scriptFileName = "script" // TODO: extract from file/url if available val scriptFileName = "script" // TODO: extract from file/url if available
val virtualFile = LightVirtualFile( val virtualFile = LightVirtualFile(
"$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}", "$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}",
@@ -247,7 +247,8 @@ internal class BridgeScriptDefinition(
updateClasspath: (List<File>) -> Unit updateClasspath: (List<File>) -> Unit
) : KotlinScriptDefinition(scriptCompilerConfiguration[ScriptingEnvironmentProperties.baseClass] as KClass<out Any>) { ) : KotlinScriptDefinition(scriptCompilerConfiguration[ScriptingEnvironmentProperties.baseClass] as KClass<out Any>) {
override val acceptedAnnotations = override val acceptedAnnotations =
scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.updateConfigurationOnAnnotations)?.toList() ?: emptyList() scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineConfigurationOnAnnotations)?.toList()
?: emptyList()
override val dependencyResolver: DependenciesResolver = override val dependencyResolver: DependenciesResolver =
BridgeDependenciesResolver(scriptConfigurator, scriptCompilerConfiguration, updateClasspath) BridgeDependenciesResolver(scriptConfigurator, scriptCompilerConfiguration, updateClasspath)
@@ -16,20 +16,31 @@ open class JvmScriptCompiler(
override suspend fun compile( override suspend fun compile(
script: ScriptSource, script: ScriptSource,
configuration: ScriptCompileConfiguration, configurator: ScriptCompilationConfigurator?,
configurator: ScriptCompilationConfigurator? additionalConfiguration: ScriptCompileConfiguration?
): ResultWithDiagnostics<CompiledScript<*>> { ): ResultWithDiagnostics<CompiledScript<*>> {
val refinedConfiguration = configurator?.refineConfiguration(script, configuration)?.let { val baseConfiguration = additionalConfiguration?.cloneWithNewParent(configurator?.defaultConfiguration)
when (it) { ?: configurator?.defaultConfiguration
is ResultWithDiagnostics.Failure -> return it ?: ScriptCompileConfiguration()
is ResultWithDiagnostics.Success -> it.value val refinedConfiguration =
if (baseConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineBeforeParsing) == true) {
if (configurator == null) {
return ResultWithDiagnostics.Failure("Non-null configurator expected".asErrorDiagnostics())
}
configurator.refineConfiguration(script, baseConfiguration).let {
when (it) {
is ResultWithDiagnostics.Failure -> return it
is ResultWithDiagnostics.Success -> it.value
}
}
} else {
baseConfiguration
} }
} ?: configuration
val cached = cache.get(script, refinedConfiguration) val cached = cache.get(script, refinedConfiguration)
if (cached != null) return cached.asSuccess() if (cached != null) return cached.asSuccess()
return compilerProxy.compile(script, refinedConfiguration, configurator).also { return compilerProxy.compile(script, configurator, refinedConfiguration).also {
if (it is ResultWithDiagnostics.Success) { if (it is ResultWithDiagnostics.Success) {
cache.store(it.value, refinedConfiguration) cache.store(it.value, refinedConfiguration)
} }
@@ -45,8 +56,8 @@ interface CompiledJvmScriptsCache {
interface KJVMCompilerProxy { interface KJVMCompilerProxy {
fun compile( fun compile(
script: ScriptSource, script: ScriptSource,
scriptCompilerConfiguration: ScriptCompileConfiguration, configurator: ScriptCompilationConfigurator?,
configurator: ScriptCompilationConfigurator? additionalConfiguration: ScriptCompileConfiguration
): ResultWithDiagnostics<CompiledScript<*>> ): ResultWithDiagnostics<CompiledScript<*>>
} }
@@ -47,7 +47,7 @@ class KotlinScriptDefinitionAdapterFromNewAPI(val scriptDefinition: ScriptDefini
} }
override val acceptedAnnotations: List<KClass<out Annotation>> by lazy { override val acceptedAnnotations: List<KClass<out Annotation>> by lazy {
scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.updateConfigurationOnAnnotations)?.toList() scriptDefinition.compilationConfigurator.defaultConfiguration.getOrNull(ScriptCompileConfigurationProperties.refineConfigurationOnAnnotations)?.toList()
?: emptyList() ?: emptyList()
} }