From f59e393e37d1d745261e6a2db9921b3fe5ccf7fc Mon Sep 17 00:00:00 2001 From: "Vitaliy.Tikhonov" Date: Mon, 2 Sep 2019 21:04:08 +0300 Subject: [PATCH] [CLI] add support running scripts in js compiler, extract common code with jvm part --- .../arguments/CommonCompilerArguments.kt | 6 ++ .../common/arguments/K2JSCompilerArguments.kt | 3 + .../arguments/K2JVMCompilerArguments.kt | 6 -- .../jetbrains/kotlin/cli/js/K2JSCompiler.java | 6 +- .../jetbrains/kotlin/cli/js/K2JsIrCompiler.kt | 68 ++++++++++++++----- .../kotlin/cli/common/CLICompiler.kt | 55 +++++++++++++-- .../jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt | 62 +++-------------- .../kotlin/cli/metadata/K2MetadataCompiler.kt | 4 +- compiler/testData/cli/js/jsExtraHelp.out | 3 + compiler/testData/cli/js/jsHelp.out | 1 + compiler/testData/cli/jvm/extraHelp.out | 4 +- compiler/testData/cli/jvm/help.out | 2 +- .../org/jetbrains/kotlin/utils/PathUtil.kt | 6 +- .../AbstractScriptEvaluationExtension.kt | 15 ++-- .../plugin/JsScriptEvaluationExtension.kt | 37 +++++----- .../plugin/JvmCliScriptEvaluationExtension.kt | 16 ++--- .../compiler/plugin/pluginRegisrar.kt | 1 + prepare/compiler/build.gradle.kts | 2 + 18 files changed, 175 insertions(+), 122 deletions(-) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt index 874993309fe..fe140a5b9fc 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.kt @@ -76,6 +76,9 @@ abstract class CommonCompilerArguments : CommonToolArguments() { ) var progressiveMode by FreezableVar(false) + @Argument(value = "-script", description = "Evaluate the script file") + var script: Boolean by FreezableVar(false) + @Argument(value = "-P", valueDescription = PLUGIN_OPTION_FORMAT, description = "Pass an option to a plugin") var pluginOptions: Array? by FreezableVar(null) @@ -304,6 +307,9 @@ abstract class CommonCompilerArguments : CommonToolArguments() { ) var useFir: Boolean by FreezableVar(false) + @Argument(value = "-Xdisable-default-scripting-plugin", description = "Do not enable scripting plugin by default") + var disableDefaultScriptingPlugin: Boolean by FreezableVar(false) + open fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> { return HashMap, Any>().apply { put(AnalysisFlags.skipMetadataVersionCheck, skipMetadataVersionCheck) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt index 557a0d0939b..821af5b93ae 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt @@ -137,4 +137,7 @@ class K2JSCompilerArguments : CommonCompilerArguments() { @Argument(value = "-Xmetadata-only", description = "Generate *.meta.js and *.kjsm files only") var metadataOnly: Boolean by FreezableVar(false) + + @Argument(value = "-Xenable-js-scripting", description = "Enable experimental support of .kts files using K/JS (with -Xir only)") + var enableJsScripting: Boolean by FreezableVar(false) } diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index bdcd9e56dc4..31a03bbf26d 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -45,9 +45,6 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { @Argument(value = "-no-reflect", description = "Don't include kotlin-reflect.jar into classpath") var noReflect: Boolean by FreezableVar(false) - @Argument(value = "-script", description = "Evaluate the script file") - var script: Boolean by FreezableVar(false) - @Argument( value = "-script-templates", valueDescription = "", @@ -254,9 +251,6 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { ) var jvmDefault: String by FreezableVar(JvmDefaultMode.DEFAULT.description) - @Argument(value = "-Xdisable-default-scripting-plugin", description = "Do not enable scripting plugin by default") - var disableDefaultScriptingPlugin: Boolean by FreezableVar(false) - @Argument(value = "-Xdisable-standard-script", description = "Disable standard kotlin script support") var disableStandardScript: Boolean by FreezableVar(false) diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index 6093b7d35cc..82714736ac1 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -95,6 +95,9 @@ public class K2JSCompiler extends CLICompiler { return irCompiler; } + @Override + protected void addPlatformOptions(@NotNull List $self, @NotNull K2JSCompilerArguments arguments) {} + static { moduleKindMap.put(K2JsArgumentConstants.MODULE_PLAIN, ModuleKind.PLAIN); moduleKindMap.put(K2JsArgumentConstants.MODULE_COMMONJS, ModuleKind.COMMON_JS); @@ -195,8 +198,7 @@ public class K2JSCompiler extends CLICompiler { return COMPILATION_ERROR; } - ExitCode pluginLoadResult = - PluginCliParser.loadPluginsSafe(arguments.getPluginClasspaths(), arguments.getPluginOptions(), configuration); + ExitCode pluginLoadResult = loadPlugins(paths, arguments, configuration); if (pluginLoadResult != ExitCode.OK) return pluginLoadResult; configuration.put(JSConfigurationKeys.LIBRARIES, configureLibraries(arguments, paths, messageCollector)); diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index ab8986d6150..1823c363ba4 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -9,11 +9,11 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.cli.common.* -import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR -import org.jetbrains.kotlin.cli.common.ExitCode.OK +import org.jetbrains.kotlin.cli.common.ExitCode.* import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot +import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.* import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector @@ -43,6 +43,7 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.utils.JsMetadataVersion import org.jetbrains.kotlin.utils.KotlinPaths +import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.join import java.io.File import java.io.IOException @@ -70,6 +71,33 @@ class K2JsIrCompiler : CLICompiler() { ): ExitCode { val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) + val pluginLoadResult = loadPlugins(paths, arguments, configuration) + if (pluginLoadResult != ExitCode.OK) return pluginLoadResult + + //TODO: add to configuration everything that may come in handy at script compiler and use it there + if (arguments.script) { + + if (!arguments.enableJsScripting) { + messageCollector.report(ERROR, "Script for K/JS should be enabled explicitly, see -Xenable-js-scripting") + return COMPILATION_ERROR + } + + configuration.put(CommonConfigurationKeys.MODULE_NAME, "repl.kts") + + val environment = KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(rootDisposable, configuration) + val projectEnv = KotlinCoreEnvironment.ProjectEnvironment(rootDisposable, environment) + projectEnv.registerExtensionsFromPlugins(configuration) + + val scriptingEvaluators = ScriptEvaluationExtension.getInstances(projectEnv.project) + val scriptingEvaluator = scriptingEvaluators.find { it.isAccepted(arguments) } + if (scriptingEvaluator == null) { + messageCollector.report(ERROR, "Unable to evaluate script, no scripting plugin loaded") + return COMPILATION_ERROR + } + + return scriptingEvaluator.eval(arguments, configuration, projectEnv) + } + if (arguments.freeArgs.isEmpty() && !IncrementalCompilation.isEnabledForJs()) { if (arguments.version) { return OK @@ -78,13 +106,6 @@ class K2JsIrCompiler : CLICompiler() { return COMPILATION_ERROR } - val pluginLoadResult = PluginCliParser.loadPluginsSafe( - arguments.pluginClasspaths, - arguments.pluginOptions, - configuration - ) - if (pluginLoadResult != OK) return pluginLoadResult - val libraries: List = configureLibraries(arguments.libraries) val friendLibraries: List = configureLibraries(arguments.friendModules) @@ -99,11 +120,11 @@ class K2JsIrCompiler : CLICompiler() { val environmentForJS = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JS_CONFIG_FILES) - - val project = environmentForJS.project + val projectJs = environmentForJS.project + val configurationJs = environmentForJS.configuration val sourcesFiles = environmentForJS.getSourceFiles() - environmentForJS.configuration.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage) + configurationJs.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage) if (!checkKotlinPackageUsage(environmentForJS, sourcesFiles)) return ExitCode.COMPILATION_ERROR @@ -128,9 +149,11 @@ class K2JsIrCompiler : CLICompiler() { val outputFile = File(outputFilePath) - configuration.put(CommonConfigurationKeys.MODULE_NAME, FileUtil.getNameWithoutExtension(outputFile)) + configurationJs.put(CommonConfigurationKeys.MODULE_NAME, FileUtil.getNameWithoutExtension(outputFile)) - val config = JsConfig(project, configuration) + // TODO: in this method at least 3 different compiler configurations are used (original, env.configuration, jsConfig.configuration) + // Such situation seems a bit buggy... + val config = JsConfig(projectJs, configurationJs) val outputDir: File = outputFile.parentFile ?: outputFile.absoluteFile.parentFile!! try { config.configuration.put(JSConfigurationKeys.OUTPUT_DIR, outputDir.canonicalFile) @@ -179,9 +202,9 @@ class K2JsIrCompiler : CLICompiler() { val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector) val compiledModule = compile( - project, + projectJs, sourcesFiles, - configuration, + config.configuration, phaseConfig, allDependencies = resolvedLibraries, friendDependencies = friendDependencies, @@ -293,6 +316,8 @@ class K2JsIrCompiler : CLICompiler() { return JsMetadataVersion(*versionArray) } + override fun MutableList.addPlatformOptions(arguments: K2JSCompilerArguments) {} + companion object { private val moduleKindMap = mapOf( K2JsArgumentConstants.MODULE_PLAIN to ModuleKind.PLAIN, @@ -349,4 +374,15 @@ fun messageCollectorLogger(collector: MessageCollector) = object : Logger { (collector as? GroupingMessageCollector)?.flush() kotlin.error(message) } +} + +fun loadPluginsForTests(configuration: CompilerConfiguration): ExitCode { + var pluginClasspaths: Iterable = emptyList() + val kotlinPaths = PathUtil.kotlinPathsForCompiler + val libPath = kotlinPaths.libPath.takeIf { it.exists() && it.isDirectory } ?: File(".") + val (jars, _) = + PathUtil.KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS.mapNotNull { File(libPath, it) }.partition { it.exists() } + pluginClasspaths = jars.map { it.canonicalPath } + pluginClasspaths + + return PluginCliParser.loadPluginsSafe(pluginClasspaths, mutableListOf(), configuration) } \ No newline at end of file diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt index 6ade627586b..123c05e4906 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.kt @@ -24,11 +24,10 @@ import org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR import org.jetbrains.kotlin.cli.common.ExitCode.INTERNAL_ERROR import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback +import org.jetbrains.kotlin.cli.common.messages.* import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO -import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil -import org.jetbrains.kotlin.cli.common.messages.MessageRenderer +import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion @@ -36,8 +35,10 @@ import org.jetbrains.kotlin.progress.CompilationCanceledException import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.utils.KotlinPaths +import org.jetbrains.kotlin.utils.PathUtil import java.io.File import java.io.PrintStream +import java.util.ArrayList abstract class CLICompiler : CLITool() { @@ -134,5 +135,51 @@ abstract class CLICompiler : CLITool() { rootDisposable: Disposable, paths: KotlinPaths? ): ExitCode + + protected abstract fun MutableList.addPlatformOptions(arguments: A) + + protected fun loadPlugins(paths: KotlinPaths?, arguments: A, configuration: CompilerConfiguration): ExitCode { + var pluginClasspaths: Iterable = arguments.pluginClasspaths?.asIterable() ?: emptyList() + val pluginOptions = arguments.pluginOptions?.toMutableList() ?: ArrayList() + + if (!arguments.disableDefaultScriptingPlugin) { + val explicitOrLoadedScriptingPlugin = + pluginClasspaths.any { File(it).name.startsWith(PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_NAME) } || + tryLoadScriptingPluginFromCurrentClassLoader(configuration) + if (!explicitOrLoadedScriptingPlugin) { + val kotlinPaths = paths ?: PathUtil.kotlinPathsForCompiler + val libPath = kotlinPaths.libPath.takeIf { it.exists() && it.isDirectory } ?: File(".") + val (jars, missingJars) = + PathUtil.KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS.map { File(libPath, it) }.partition { it.exists() } + if (missingJars.isEmpty()) { + pluginClasspaths = jars.map { it.canonicalPath } + pluginClasspaths + } else { + val messageCollector = configuration.getNotNull(MESSAGE_COLLECTOR_KEY) + messageCollector.report( + CompilerMessageSeverity.LOGGING, + "Scripting plugin will not be loaded: not all required jars are present in the classpath (missing files: $missingJars)" + ) + } + } + pluginOptions.addPlatformOptions(arguments) + } else { + pluginOptions.add("plugin:kotlin.scripting:disable=true") + } + return PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration) + } + + private fun tryLoadScriptingPluginFromCurrentClassLoader(configuration: CompilerConfiguration): Boolean = try { + val pluginRegistrarClass = PluginCliParser::class.java.classLoader.loadClass( + "org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar" + ) + val pluginRegistrar = pluginRegistrarClass.newInstance() as? ComponentRegistrar + if (pluginRegistrar != null) { + configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, pluginRegistrar) + true + } else false + } catch (_: Throwable) { + // TODO: add finer error processing and logging + false + } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index e493bfa6f1e..df87436a5e7 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -198,59 +198,17 @@ class K2JVMCompiler : CLICompiler() { } } - private fun loadPlugins(paths: KotlinPaths?, arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration): ExitCode { - var pluginClasspaths: Iterable = arguments.pluginClasspaths?.asIterable() ?: emptyList() - val pluginOptions = arguments.pluginOptions?.toMutableList() ?: ArrayList() - - if (!arguments.disableDefaultScriptingPlugin) { - val explicitOrLoadedScriptingPlugin = - pluginClasspaths.any { File(it).name.startsWith(PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_NAME) } || - tryLoadScriptingPluginFromCurrentClassLoader(configuration) - // if scripting plugin is not enabled explicitly (probably from another path) and not in the classpath already, - // try to find and enable it implicitly - if (!explicitOrLoadedScriptingPlugin) { - val kotlinPaths = paths ?: PathUtil.kotlinPathsForCompiler - val libPath = kotlinPaths.libPath.takeIf { it.exists() && it.isDirectory } ?: File(".") - val (jars, missingJars) = - PathUtil.KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS.mapNotNull { File(libPath, it) }.partition { it.exists() } - if (missingJars.isEmpty()) { - pluginClasspaths = jars.map { it.canonicalPath } + pluginClasspaths - } else { - val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - messageCollector.report( - LOGGING, - "Scripting plugin will not be loaded: not all required jars are present in the classpath (missing files: $missingJars)" - ) - } - } - if (arguments.scriptTemplates?.isNotEmpty() == true) { - pluginOptions.add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}") - } - if (arguments.scriptResolverEnvironment?.isNotEmpty() == true) { - pluginOptions.add( - "plugin:kotlin.scripting:script-resolver-environment=${arguments.scriptResolverEnvironment!!.joinToString( - "," - )}" - ) - } - } else { - pluginOptions.add("plugin:kotlin.scripting:disable=true") + override fun MutableList.addPlatformOptions(arguments: K2JVMCompilerArguments) { + if (arguments.scriptTemplates?.isNotEmpty() == true) { + add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}") + } + if (arguments.scriptResolverEnvironment?.isNotEmpty() == true) { + add( + "plugin:kotlin.scripting:script-resolver-environment=${arguments.scriptResolverEnvironment!!.joinToString( + "," + )}" + ) } - return PluginCliParser.loadPluginsSafe(pluginClasspaths, pluginOptions, configuration) - } - - private fun tryLoadScriptingPluginFromCurrentClassLoader(configuration: CompilerConfiguration): Boolean = try { - val pluginRegistrarClass = PluginCliParser::class.java.classLoader.loadClass( - "org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar" - ) - val pluginRegistrar = pluginRegistrarClass.newInstance() as? ComponentRegistrar - if (pluginRegistrar != null) { - configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, pluginRegistrar) - true - } else false - } catch (_: Throwable) { - // TODO: add finer error processing and logging - false } private fun createCoreEnvironment( diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt index 40bafde9216..1d0badbdaf5 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/K2MetadataCompiler.kt @@ -49,6 +49,8 @@ class K2MetadataCompiler : CLICompiler() { // No specific arguments yet } + override fun MutableList.addPlatformOptions(arguments: K2MetadataCompilerArguments) {} + override fun doExecute( arguments: K2MetadataCompilerArguments, configuration: CompilerConfiguration, @@ -57,7 +59,7 @@ class K2MetadataCompiler : CLICompiler() { ): ExitCode { val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - val pluginLoadResult = PluginCliParser.loadPluginsSafe(arguments.pluginClasspaths, arguments.pluginOptions, configuration) + val pluginLoadResult = loadPlugins(paths, arguments, configuration) if (pluginLoadResult != ExitCode.OK) return pluginLoadResult for (arg in arguments.freeArgs) { diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index 879f2d82b11..25d45dc2953 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -1,5 +1,6 @@ Usage: kotlinc-js where advanced options include: + -Xenable-js-scripting Enable experimental support of .kts files using K/JS (with -Xir only) -Xfriend-modules= Paths to friend modules -Xfriend-modules-disabled Disable internal declaration export -Xir Use IR backend @@ -17,6 +18,8 @@ where advanced options include: Should be a subset of sources passed as free arguments -Xcoroutines={enable|warn|error} Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier + -Xdisable-default-scripting-plugin + Do not enable scripting plugin by default -Xdisable-phases Disable backend phases -Xdump-directory Dump backend state into directory -Xdump-fqname FqName of declaration that should be dumped diff --git a/compiler/testData/cli/js/jsHelp.out b/compiler/testData/cli/js/jsHelp.out index 652cd610bc3..91226cda95d 100644 --- a/compiler/testData/cli/js/jsHelp.out +++ b/compiler/testData/cli/js/jsHelp.out @@ -28,6 +28,7 @@ where possible options include: instead of going through a graceful migration cycle. Code written in the progressive mode is backward compatible; however, code written in non-progressive mode may cause compilation errors in the progressive mode. + -script Evaluate the script file -nowarn Generate no warnings -verbose Enable verbose logging output -version Display compiler version diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 6e2ebb111dd..a6df038022b 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -17,8 +17,6 @@ where advanced options include: default is 'disable' in language version 1.2 and below, 'enable' since language version 1.3 -Xdump-declarations-to= Path to JSON file to dump Java to Kotlin declaration mappings - -Xdisable-default-scripting-plugin - Do not enable scripting plugin by default -Xdisable-standard-script Disable standard kotlin script support -Xfriend-paths= Paths to output directories for friend modules (whose internals should be visible) -Xmultifile-parts-inherit Compile multifile classes as a hierarchy of parts and facade @@ -79,6 +77,8 @@ where advanced options include: Should be a subset of sources passed as free arguments -Xcoroutines={enable|warn|error} Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier + -Xdisable-default-scripting-plugin + Do not enable scripting plugin by default -Xdisable-phases Disable backend phases -Xdump-directory Dump backend state into directory -Xdump-fqname FqName of declaration that should be dumped diff --git a/compiler/testData/cli/jvm/help.out b/compiler/testData/cli/jvm/help.out index 14117439e9f..af969a2a1b5 100644 --- a/compiler/testData/cli/jvm/help.out +++ b/compiler/testData/cli/jvm/help.out @@ -10,7 +10,6 @@ where possible options include: -no-jdk Don't include Java runtime into classpath -no-reflect Don't include kotlin-reflect.jar into classpath -no-stdlib Don't include kotlin-stdlib.jar or kotlin-reflect.jar into classpath - -script Evaluate the script file -script-templates Script definition template classes -Werror Report an error if there are any warnings @@ -26,6 +25,7 @@ where possible options include: instead of going through a graceful migration cycle. Code written in the progressive mode is backward compatible; however, code written in non-progressive mode may cause compilation errors in the progressive mode. + -script Evaluate the script file -nowarn Generate no warnings -verbose Enable verbose logging output -version Display compiler version diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt index b88a60a6b8d..0431730a054 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt @@ -66,6 +66,8 @@ object PathUtil { const val KOTLIN_SCRIPTING_COMMON_JAR = "$KOTLIN_SCRIPTING_COMMON_NAME.jar" const val KOTLIN_SCRIPTING_JVM_NAME = "kotlin-scripting-jvm" const val KOTLIN_SCRIPTING_JVM_JAR = "$KOTLIN_SCRIPTING_JVM_NAME.jar" + const val KOTLIN_SCRIPTING_JS_NAME = "kotlin-scripting-js" + const val KOTLIN_SCRIPTING_JS_JAR = "$KOTLIN_SCRIPTING_JS_NAME.jar" const val KOTLIN_DAEMON_NAME = "kotlin-daemon" const val KTOR_NAME = "ktor-network-1.0.1" const val KOTLIN_DAEMON_JAR = "$KOTLIN_SCRIPTING_JVM_NAME.jar" @@ -75,10 +77,12 @@ object PathUtil { const val KOTLINX_COROUTINES_CORE_JAR = "$KOTLINX_COROUTINES_CORE_NAME.jar" const val KOTLIN_SCRIPTING_COMPILER_IMPL_NAME = "kotlin-scripting-compiler-impl" const val KOTLIN_SCRIPTING_COMPILER_IMPL_JAR = "$KOTLIN_SCRIPTING_COMPILER_IMPL_NAME.jar" + const val JS_ENGINES_NAME = "js.engines" + const val JS_ENGINES_JAR = "$JS_ENGINES_NAME.jar" val KOTLIN_SCRIPTING_PLUGIN_CLASSPATH_JARS = arrayOf( KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMPILER_IMPL_JAR, - KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR + KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR, KOTLIN_SCRIPTING_JS_JAR, JS_ENGINES_JAR ) const val KOTLIN_TEST_NAME = "kotlin-test" diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/AbstractScriptEvaluationExtension.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/AbstractScriptEvaluationExtension.kt index 4a158cad68b..98e5018edc1 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/AbstractScriptEvaluationExtension.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/AbstractScriptEvaluationExtension.kt @@ -23,8 +23,6 @@ import kotlin.script.experimental.host.toScriptSource abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension { - abstract fun getSourcePath(arguments: CommonCompilerArguments): String - abstract fun setupScriptConfiguration(configuration: CompilerConfiguration, sourcePath: String) abstract fun createEnvironment( @@ -40,11 +38,7 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension { scriptCompilationConfiguration: ScriptCompilationConfiguration ): ResultWithDiagnostics> - abstract suspend fun preprocessEvaluation( - scriptEvaluator: ScriptEvaluator, - scriptCompilationConfiguration: ScriptCompilationConfiguration, - evaluationConfiguration: ScriptEvaluationConfiguration - ) + protected abstract fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration() override fun eval( arguments: CommonCompilerArguments, @@ -57,12 +51,14 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension { messageCollector.report(CompilerMessageSeverity.ERROR, "Unable to process the script, scripting plugin is not configured") return ExitCode.COMPILATION_ERROR } - val sourcePath = getSourcePath(arguments) + val sourcePath = arguments.freeArgs.first() setupScriptConfiguration(configuration, sourcePath) val environment = createEnvironment(projectEnvironment, configuration) + if (messageCollector.hasErrors()) return ExitCode.COMPILATION_ERROR + val scriptFile = File(sourcePath) if (scriptFile.isDirectory || !scriptDefinitionProvider.isScript(scriptFile)) { val extensionHint = @@ -82,6 +78,8 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension { val evaluationConfiguration = definition.evaluationConfiguration.with { constructorArgs(scriptArgs.toTypedArray()) + platformEvaluationConfiguration() + } val scriptCompilationConfiguration = definition.compilationConfiguration @@ -99,7 +97,6 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension { return@runBlocking ExitCode.COMPILATION_ERROR } - preprocessEvaluation(scriptEvaluator, scriptCompilationConfiguration, evaluationConfiguration) val evalResult = scriptEvaluator.invoke(compiledScript, evaluationConfiguration).valueOr { for (report in it.reports) { messageCollector.report(report.severity.toCompilerMessageSeverity(), report.render(withSeverity = false)) diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JsScriptEvaluationExtension.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JsScriptEvaluationExtension.kt index d34969f52a7..003351c8680 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JsScriptEvaluationExtension.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JsScriptEvaluationExtension.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.platform import org.jetbrains.kotlin.scripting.repl.js.CompiledToJsScript import org.jetbrains.kotlin.scripting.repl.js.JsScriptCompiler +import org.jetbrains.kotlin.scripting.repl.js.JsScriptDependencyCompiler import org.jetbrains.kotlin.scripting.repl.js.JsScriptEvaluator import kotlin.script.experimental.api.* import kotlin.script.experimental.host.ScriptingHostConfiguration @@ -35,10 +36,6 @@ fun loadScriptConfiguration(configuration: CompilerConfiguration) { class JsScriptEvaluationExtension : AbstractScriptEvaluationExtension() { - override fun getSourcePath(arguments: CommonCompilerArguments): String { - return (arguments as K2JSCompilerArguments).scriptPath!! - } - override fun setupScriptConfiguration(configuration: CompilerConfiguration, sourcePath: String) { loadScriptConfiguration(configuration) } @@ -59,8 +56,12 @@ class JsScriptEvaluationExtension : AbstractScriptEvaluationExtension() { } private var environment: KotlinCoreEnvironment? = null + private var dependencyJsCode: String? = null private val scriptCompiler: JsScriptCompiler by lazy { - JsScriptCompiler(environment!!) + val env = environment ?: error("Expected environment is initialized prior to compiler instantiation") + JsScriptCompiler(env).apply { + dependencyJsCode = JsScriptDependencyCompiler(env.configuration, nameTables, symbolTable).compile(dependencies) + } } override suspend fun compilerInvoke( @@ -68,22 +69,22 @@ class JsScriptEvaluationExtension : AbstractScriptEvaluationExtension() { script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration ): ResultWithDiagnostics> { + this.environment = environment - return scriptCompiler.invoke(script, scriptCompilationConfiguration) + + return scriptCompiler.invoke(script, scriptCompilationConfiguration).onSuccess { + val compiledResult = it as CompiledToJsScript + val actualResult = dependencyJsCode?.let { d -> + dependencyJsCode = null + CompiledToJsScript(d + "\n" + compiledResult.jsCode, compiledResult.compilationConfiguration) + } ?: compiledResult + + ResultWithDiagnostics.Success(actualResult) + } } - override suspend fun preprocessEvaluation( - scriptEvaluator: ScriptEvaluator, - scriptCompilationConfiguration: ScriptCompilationConfiguration, - evaluationConfiguration: ScriptEvaluationConfiguration - ) { - scriptEvaluator.invoke( - CompiledToJsScript( - scriptCompiler.scriptDependencyBinary, - scriptCompilationConfiguration - ), - evaluationConfiguration - ) + override fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration() { + } override fun isAccepted(arguments: CommonCompilerArguments): Boolean { diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt index d46372a4f28..5d7fba2b972 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt @@ -16,11 +16,15 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerFromEnvironment import kotlin.script.experimental.api.* import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator +import kotlin.script.experimental.jvm.baseClassLoader +import kotlin.script.experimental.jvm.jvm class JvmCliScriptEvaluationExtension : AbstractScriptEvaluationExtension() { - override fun getSourcePath(arguments: CommonCompilerArguments): String { - return arguments.freeArgs.first() + override fun ScriptEvaluationConfiguration.Builder.platformEvaluationConfiguration() { + jvm { + baseClassLoader(null) + } } override fun setupScriptConfiguration(configuration: CompilerConfiguration, sourcePath: String) { @@ -53,14 +57,6 @@ class JvmCliScriptEvaluationExtension : AbstractScriptEvaluationExtension() { return scriptCompiler.compile(script, scriptCompilationConfiguration) } - override suspend fun preprocessEvaluation( - scriptEvaluator: ScriptEvaluator, - scriptCompilationConfiguration: ScriptCompilationConfiguration, - evaluationConfiguration: ScriptEvaluationConfiguration - ) { - //do nothing - } - override fun isAccepted(arguments: CommonCompilerArguments): Boolean = arguments is K2JVMCompilerArguments && arguments.script } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt index b25026665a4..39bc85c4e4f 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt @@ -51,6 +51,7 @@ class ScriptingCompilerConfigurationComponentRegistrar : ComponentRegistrar { ) ) ScriptEvaluationExtension.registerExtensionIfRequired(project, JvmCliScriptEvaluationExtension()) + ScriptEvaluationExtension.registerExtensionIfRequired(project, JsScriptEvaluationExtension()) ShellExtension.registerExtensionIfRequired(project, JvmCliReplShellExtension()) ReplFactoryExtension.registerExtensionIfRequired(project, JvmStandardReplFactoryExtension() diff --git a/prepare/compiler/build.gradle.kts b/prepare/compiler/build.gradle.kts index 1ec6c82c94c..17df0c969a1 100644 --- a/prepare/compiler/build.gradle.kts +++ b/prepare/compiler/build.gradle.kts @@ -83,6 +83,8 @@ val distLibraryProjects = listOfNotNull( ":kotlin-scripting-compiler", ":kotlin-scripting-compiler-impl", ":kotlin-scripting-jvm", + ":kotlin-scripting-js", + ":js:js.engines", ":kotlin-stdlib-js-ir".takeIf { kotlinBuildProperties.jsIrDist }, ":kotlin-source-sections-compiler-plugin", ":kotlin-test:kotlin-test-js",