diff --git a/libraries/scripting/jvm-host/build.gradle.kts b/libraries/scripting/jvm-host/build.gradle.kts new file mode 100644 index 00000000000..ba4640e293b --- /dev/null +++ b/libraries/scripting/jvm-host/build.gradle.kts @@ -0,0 +1,29 @@ + +import org.jetbrains.kotlin.gradle.dsl.Coroutines + +apply { + plugin("kotlin") +} + +jvmTarget = "1.6" + +dependencies { + compile(project(":kotlin-script-runtime")) + compile(project(":kotlin-stdlib")) + compile(project(":kotlin-scripting-common")) + compile(project(":kotlin-scripting-jvm")) + compileOnly(project(":compiler:cli")) + compileOnly(intellijCoreDep()) +} + +sourceSets { + "main" { projectDefault() } + "test" {} +} + +kotlin.experimental.coroutines = Coroutines.ENABLE + +standardPublicJars() + +publish() + diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt new file mode 100644 index 00000000000..591c65346be --- /dev/null +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJVMCompilerImpl.kt @@ -0,0 +1,223 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. 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 com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vfs.CharsetToolkit +import com.intellij.psi.PsiFileFactory +import com.intellij.psi.impl.PsiFileFactoryImpl +import com.intellij.testFramework.LightVirtualFile +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.* +import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot +import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots +import org.jetbrains.kotlin.cli.jvm.config.addJvmSdkRoots +import org.jetbrains.kotlin.codegen.ClassBuilderFactories +import org.jetbrains.kotlin.codegen.GeneratedClassLoader +import org.jetbrains.kotlin.codegen.KotlinCodegenFacade +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.parsing.KotlinParserDefinition +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.script.KotlinScriptDefinition +import org.jetbrains.kotlin.utils.PathUtil +import java.io.File +import java.net.URLClassLoader +import kotlin.reflect.KClass +import kotlin.script.experimental.api.* +import kotlin.script.experimental.dependencies.DependenciesResolver +import kotlin.script.experimental.host.getMergedScriptText +import kotlin.script.experimental.jvm.JvmDependency +import kotlin.script.experimental.jvm.JvmScriptCompileConfigurationParams +import kotlin.script.experimental.jvm.JvmScriptEvaluationEnvironmentParams +import kotlin.script.experimental.jvm.KJVMCompilerProxy +import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver + +class KJVMCompiledScript( + override val configuration: ScriptCompileConfiguration, + val generationState: GenerationState, + val scriptClassFQName: String +) : CompiledScript { + + override suspend fun instantiate(scriptEvaluationEnvironment: ScriptEvaluationEnvironment): ResultWithDiagnostics = try { + val baseClassLoader = scriptEvaluationEnvironment.getOrNull(JvmScriptEvaluationEnvironmentParams.baseClassLoader) + val dependencies = configuration.getOrNull(ScriptCompileConfigurationParams.dependencies) + ?.flatMap { (it as? JvmDependency)?.classpath?.map { it.toURI().toURL() } ?: emptyList() } + // TODO: previous dependencies and classloaders should be taken into account here + val classLoaderWithDeps = + if (dependencies == null) baseClassLoader + else URLClassLoader(dependencies.toTypedArray(), baseClassLoader) + val classLoader = GeneratedClassLoader(generationState.factory, classLoaderWithDeps) + + val clazz = classLoader.loadClass(scriptClassFQName) + (clazz as? ScriptBase)?.asSuccess() + ?: ResultWithDiagnostics.Failure("Compiled class expected to be a subclass of the , but got ${clazz.javaClass.name}".asErrorDiagnostics()) + } catch (e: Throwable) { + ResultWithDiagnostics.Failure(ScriptDiagnostic("Unable to instantiate class $scriptClassFQName", exception = e)) + } +} + +class KJVMCompilerImpl : KJVMCompilerProxy { + + override fun compile( + scriptCompilerConfiguration: ScriptCompileConfiguration, + configurator: ScriptConfigurator? + ): ResultWithDiagnostics> { + val messageCollector = ScriptDiagnosticsMessageCollector() + + fun failure(vararg diagnostics: ScriptDiagnostic): ResultWithDiagnostics.Failure = + ResultWithDiagnostics.Failure(*messageCollector.diagnostics.toTypedArray(), *diagnostics) + + try { + var environment: KotlinCoreEnvironment? = null + var updatedScriptCompileConfiguration = scriptCompilerConfiguration + + fun updateClasspath(classpath: Iterable) { + environment!!.updateClasspath(classpath.map(::JvmClasspathRoot)) + val updatedDeps = updatedScriptCompileConfiguration.getOrNull(ScriptCompileConfigurationParams.dependencies)?.plus( + JvmDependency(classpath) + ) ?: listOf(JvmDependency(classpath)) + updatedScriptCompileConfiguration = updatedScriptCompileConfiguration.cloneWith( + ScriptCompileConfigurationParams.dependencies to updatedDeps + ) + } + + val disposable = Disposer.newDisposable() + val kotlinCompilerConfiguration = org.jetbrains.kotlin.config.CompilerConfiguration().apply { + add( + JVMConfigurationKeys.SCRIPT_DEFINITIONS, + BridgeScriptDefinition(scriptCompilerConfiguration, configurator, ::updateClasspath) + ) + put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) + put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) + + scriptCompilerConfiguration.getOrNull(JvmScriptCompileConfigurationParams.javaHomeDir)?.let { + put(JVMConfigurationKeys.JDK_HOME, it) + } + + scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationParams.dependencies)?.let { + addJvmClasspathRoots(it.flatMap { (it as JvmDependency).classpath }) + } + put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script") // TODO" take meaningful and valid name from somewhere + languageVersionSettings = LanguageVersionSettingsImpl( + LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.skipMetadataVersionCheck to true) + ) + } + environment = KotlinCoreEnvironment.createForProduction( + disposable, + kotlinCompilerConfiguration, + EnvironmentConfigFiles.JVM_CONFIG_FILES + ) + + val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, environment.configuration.languageVersionSettings) + + val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl + val scriptText = scriptCompilerConfiguration[ScriptCompileConfigurationParams.scriptSourceFragments].getMergedScriptText() + val scriptFileName = "script" // TODO: extract from file/url if available + val virtualFile = LightVirtualFile( + "$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}", + KotlinLanguage.INSTANCE, + StringUtil.convertLineSeparators(scriptText) + ).apply { + charset = CharsetToolkit.UTF8_CHARSET + } + val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile? + ?: return failure("Unable to make PSI file from script".asErrorDiagnostics()) + + val sourceFiles = listOf(psiFile) + + analyzerWithCompilerReport.analyzeAndReport(sourceFiles) { + val project = environment.project + TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( + project, + sourceFiles, + NoScopeRecordCliBindingTrace(), + environment.configuration, + environment::createPackagePartProvider + ) + } + val analysisResult = analyzerWithCompilerReport.analysisResult + + if (!analysisResult.shouldGenerateCode) return failure("no code to generate".asErrorDiagnostics()) + if (analysisResult.isError() || messageCollector.hasErrors()) return failure() + + val generationState = GenerationState.Builder( + psiFile.project, + ClassBuilderFactories.binaries(false), + analysisResult.moduleDescriptor, + analysisResult.bindingContext, + sourceFiles, + kotlinCompilerConfiguration + ).build() + generationState.beforeCompile() + KotlinCodegenFacade.generatePackage( + generationState, + psiFile.script!!.containingKtFile.packageFqName, + setOf(psiFile.script!!.containingKtFile), + org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION + ) + + val res = KJVMCompiledScript(updatedScriptCompileConfiguration, generationState, scriptFileName.capitalize()) + + return ResultWithDiagnostics.Success(res, messageCollector.diagnostics) + } catch (ex: Throwable) { + return failure(ex.asDiagnostics()) + } + } +} + +class ScriptDiagnosticsMessageCollector : MessageCollector { + + private val _diagnostics = arrayListOf() + + val diagnostics: List get() = _diagnostics + + override fun clear() { + _diagnostics.clear() + } + + override fun hasErrors(): Boolean = + _diagnostics.any { it.severity == ScriptDiagnostic.Severity.ERROR } + + + override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) { + val mappedSeverity = when (severity) { + CompilerMessageSeverity.EXCEPTION, + CompilerMessageSeverity.ERROR -> ScriptDiagnostic.Severity.ERROR + CompilerMessageSeverity.STRONG_WARNING, + CompilerMessageSeverity.WARNING -> ScriptDiagnostic.Severity.WARNING + CompilerMessageSeverity.INFO -> ScriptDiagnostic.Severity.INFO + CompilerMessageSeverity.LOGGING -> ScriptDiagnostic.Severity.DEBUG + else -> null + } + if (mappedSeverity != null) { + val mappedLocation = location?.let { + ScriptSource.Location(ScriptSource.Position(it.line, it.column)) + } + _diagnostics.add(ScriptDiagnostic(message, mappedSeverity, mappedLocation)) + } + } +} + +// A bridge to the current scripting + +internal class BridgeScriptDefinition( + scriptCompilerConfiguration: ScriptCompileConfiguration, + scriptConfigurator: ScriptConfigurator?, + updateClasspath: (List) -> Unit +) : KotlinScriptDefinition(scriptCompilerConfiguration[ScriptCompileConfigurationParams.scriptSignature].scriptBase as KClass) { + override val acceptedAnnotations = + scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationParams.updateConfigurationOnAnnotations)?.toList() ?: emptyList() + + override val dependencyResolver: DependenciesResolver = + BridgeDependenciesResolver(scriptConfigurator, scriptCompilerConfiguration, updateClasspath) +} + diff --git a/libraries/scripting/jvm/build.gradle.kts b/libraries/scripting/jvm/build.gradle.kts new file mode 100644 index 00000000000..aa1e57bfb28 --- /dev/null +++ b/libraries/scripting/jvm/build.gradle.kts @@ -0,0 +1 @@ +import org.jetbrains.kotlin.gradle.dsl.Coroutines apply { plugin("kotlin") } jvmTarget = "1.6" dependencies { compile(project(":kotlin-script-runtime")) compile(projectDist(":kotlin-stdlib")) compile(project(":kotlin-scripting-common")) } sourceSets { "main" { projectDefault() } "test" {} } kotlin.experimental.coroutines = Coroutines.ENABLE dist() ideaPlugin() standardPublicJars() publish() \ No newline at end of file diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt new file mode 100644 index 00000000000..c3b9f308685 --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. 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.jvm.impl + +import kotlinx.coroutines.experimental.runBlocking +import java.io.File +import kotlin.script.dependencies.Environment +import kotlin.script.dependencies.ScriptContents +import kotlin.script.experimental.api.* +import kotlin.script.experimental.dependencies.AsyncDependenciesResolver +import kotlin.script.experimental.dependencies.DependenciesResolver +import kotlin.script.experimental.dependencies.ScriptDependencies +import kotlin.script.experimental.dependencies.ScriptReport +import kotlin.script.experimental.host.toScriptSource +import kotlin.script.experimental.jvm.JvmDependency +import kotlin.script.experimental.jvm.defaultConfiguration +import kotlin.script.experimental.jvm.mapToLegacyScriptReportPosition +import kotlin.script.experimental.jvm.mapToLegacyScriptReportSeverity + +class BridgeDependenciesResolver( + val scriptConfigurator: ScriptConfigurator?, + val baseScriptCompilerConfiguration: ScriptCompileConfiguration = scriptConfigurator.defaultConfiguration, + val onClasspathUpdated: (List) -> Unit = {} +) : AsyncDependenciesResolver { + + override fun resolve(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult = + runBlocking { + resolveAsync(scriptContents, environment) + } + + override suspend fun resolveAsync(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult { + return try { + + val diagnostics = arrayListOf() + val processedScriptData = + ProcessedScriptData(ProcessedScriptDataParams.annotations to scriptContents.annotations) + + val scriptCompilerConfiguration = baseScriptCompilerConfiguration.cloneWith( + ScriptCompileConfigurationParams.scriptSourceFragments to scriptContents.toScriptSourceFragments() + ) + + val refinedConfiguration = scriptConfigurator?.let { + val res = scriptConfigurator.refineConfiguration(scriptCompilerConfiguration, processedScriptData) + when (res) { + is ResultWithDiagnostics.Failure -> + return@resolveAsync DependenciesResolver.ResolveResult.Failure(res.reports.mapScriptReportsToDiagnostics()) + is ResultWithDiagnostics.Success -> { + diagnostics.addAll(res.reports.mapScriptReportsToDiagnostics()) + res.value + } + } + } ?: scriptCompilerConfiguration + + val newClasspath = refinedConfiguration.getOrNull(ScriptCompileConfigurationParams.dependencies) + ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() + if (refinedConfiguration != scriptCompilerConfiguration) { + val oldClasspath = scriptCompilerConfiguration.getOrNull(ScriptCompileConfigurationParams.dependencies) + ?.flatMap { (it as JvmDependency).classpath } ?: emptyList() + if (newClasspath != oldClasspath) { + onClasspathUpdated(newClasspath) + } + } + DependenciesResolver.ResolveResult.Success( + ScriptDependencies( + classpath = newClasspath, // TODO: maybe it should return only increment from the initial config + imports = refinedConfiguration.getOrNull(ScriptCompileConfigurationParams.importedPackages)?.toList() + ?: emptyList() + ), + diagnostics + ) + } catch (e: Throwable) { + DependenciesResolver.ResolveResult.Failure( + ScriptReport( + e.message ?: "unknown error $e" + ) + ) + } + } +} + +internal fun List.mapScriptReportsToDiagnostics() = + map { ScriptReport(it.message, mapToLegacyScriptReportSeverity(it.severity), mapToLegacyScriptReportPosition(it.location)) } + +internal fun ScriptContents.toScriptSourceFragments(): ScriptSourceFragments = + ScriptSourceFragments( + when { + text != null -> text!!.toString().toScriptSource() + file != null -> file!!.toScriptSource() + else -> throw IllegalArgumentException("Unable to convert script contents $this into script source") + }, + null + ) + diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt new file mode 100644 index 00000000000..7cbc1f80fe3 --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptCompilation.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("unused") + +package kotlin.script.experimental.jvm + +import kotlin.script.experimental.api.* + +open class JvmScriptCompiler( + val compilerProxy: KJVMCompilerProxy, + val cache: CompiledJvmScriptsCache +) : ScriptCompiler { + + override suspend fun compile(configuration: ScriptCompileConfiguration, configurator: ScriptConfigurator?): ResultWithDiagnostics> { + val refinedConfiguration = configurator?.refineConfiguration(configuration)?.let { + when (it) { + is ResultWithDiagnostics.Failure -> return it + is ResultWithDiagnostics.Success -> it.value + ?: return ResultWithDiagnostics.Failure("Null script compile configuration received".asErrorDiagnostics()) + } + } ?: configuration + val cached = cache[refinedConfiguration[ScriptCompileConfigurationParams.scriptSourceFragments]] + + if (cached != null) return cached.asSuccess() + + return compilerProxy.compile(refinedConfiguration, configurator).also { + if (it is ResultWithDiagnostics.Success) { + cache.store(it.value as CompiledScript<*>) + } + } + } +} + +interface CompiledJvmScriptsCache { + operator fun get(script: ScriptSourceFragments): CompiledScript<*>? + fun store(compiledScript: CompiledScript<*>) +} + +interface KJVMCompilerProxy { + fun compile( + scriptCompilerConfiguration: ScriptCompileConfiguration, + configurator: ScriptConfigurator? + ): ResultWithDiagnostics> +} + +class DummyCompiledJvmScriptCache : CompiledJvmScriptsCache { + override operator fun get(script: ScriptSourceFragments): CompiledScript<*>? = null + override fun store(compiledScript: CompiledScript<*>) {} +} + diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt new file mode 100644 index 00000000000..9e083c68270 --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptConfiguration.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. 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.jvm + +import kotlinx.coroutines.experimental.runBlocking +import kotlin.script.experimental.api.* +import java.io.File + +fun jvmConfigWithJavaHome(vararg params: Pair, Any?>): ScriptCompileConfiguration = + ScriptCompileConfiguration( + JvmScriptCompileConfigurationParams.javaHomeDir to File(System.getProperty("java.home")), + *params + ) + +val ScriptConfigurator?.defaultConfiguration: ScriptCompileConfiguration + get() = this?.let { runBlocking { baseConfiguration(null) } }?.resultOrNull() ?: ScriptCompileConfiguration() \ No newline at end of file diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt new file mode 100644 index 00000000000..773540a0c7d --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptData.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. 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.jvm + +import java.io.File +import kotlin.script.experimental.api.ScriptDependency +import kotlin.script.experimental.api.TypedKey + +object JvmScriptCompileConfigurationParams { + + val javaHomeDir = TypedKey("javaHomeDir") +} + +class JvmDependency(val classpath: Iterable): ScriptDependency + diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt new file mode 100644 index 00000000000..1eae78a9933 --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("unused") + +package kotlin.script.experimental.jvm + +import kotlin.script.experimental.api.ScriptConfigurator +import kotlin.script.experimental.api.ScriptRunner +import kotlin.script.experimental.api.typedKey +import kotlin.script.experimental.host.BasicScriptingHost + +open class JvmBasicScriptingHost( + configurationExtractor: ScriptConfigurator, + compiler: JvmScriptCompiler, + runner: ScriptRunner +) : BasicScriptingHost(configurationExtractor, compiler, runner) + +object JvmScriptEvaluationEnvironmentParams { + val baseClassLoader by typedKey() +} diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptUtil.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptUtil.kt new file mode 100644 index 00000000000..c7bfe8b23d5 --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptUtil.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("unused") + +package kotlin.script.experimental.jvm + +import kotlin.script.experimental.api.ScriptDiagnostic +import kotlin.script.experimental.api.ScriptSource +import kotlin.script.dependencies.ScriptContents +import kotlin.script.dependencies.ScriptDependenciesResolver +import kotlin.script.experimental.dependencies.ScriptReport + +fun mapLegacyDiagnosticSeverity(severity: ScriptDependenciesResolver.ReportSeverity): ScriptDiagnostic.Severity = when (severity) { + ScriptDependenciesResolver.ReportSeverity.ERROR -> ScriptDiagnostic.Severity.ERROR + ScriptDependenciesResolver.ReportSeverity.WARNING -> ScriptDiagnostic.Severity.WARNING + ScriptDependenciesResolver.ReportSeverity.INFO -> ScriptDiagnostic.Severity.INFO + ScriptDependenciesResolver.ReportSeverity.DEBUG -> ScriptDiagnostic.Severity.DEBUG +} + +fun mapToLegacyScriptReportSeverity(severity: ScriptDiagnostic.Severity): ScriptReport.Severity = when (severity) { + ScriptDiagnostic.Severity.ERROR -> ScriptReport.Severity.ERROR + ScriptDiagnostic.Severity.WARNING -> ScriptReport.Severity.WARNING + ScriptDiagnostic.Severity.INFO -> ScriptReport.Severity.INFO + ScriptDiagnostic.Severity.DEBUG -> ScriptReport.Severity.DEBUG +} + +fun mapLegacyScriptPosition(pos: ScriptContents.Position?): ScriptSource.Location? = + pos?.let { ScriptSource.Location(ScriptSource.Position(pos.line, pos.col)) } + +fun mapToLegacyScriptReportPosition(pos: ScriptSource.Location?): ScriptReport.Position? = + pos?.let { ScriptReport.Position(pos.start.line, pos.start.col) } diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/runners/BasicJvmScriptRunner.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/runners/BasicJvmScriptRunner.kt new file mode 100644 index 00000000000..5ee7a2139bd --- /dev/null +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/runners/BasicJvmScriptRunner.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. 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.jvm.runners + +import kotlin.reflect.KClass +import kotlin.script.experimental.api.* + +open class BasicJvmScriptRunner(val baseClass: KClass? = null) : ScriptRunner { + + override suspend fun run( + compiledScript: CompiledScript, + scriptEvaluationEnvironment: ScriptEvaluationEnvironment + ): ResultWithDiagnostics = + try { + val obj = compiledScript.instantiate(scriptEvaluationEnvironment) + when (obj) { + is ResultWithDiagnostics.Failure -> obj + is ResultWithDiagnostics.Success -> { + // in the future, when (if) we'll stop to compile everything into constructor + // run as SAM + // return res + val scriptObject = obj.value + if (scriptObject !is Class<*>) + ResultWithDiagnostics.Failure(ScriptDiagnostic("expecting class in this implementation, got ${scriptObject?.javaClass}")) + else { + scriptObject.getConstructor().newInstance() + + ResultWithDiagnostics.Success(EvaluationResult(null, scriptEvaluationEnvironment)) + } + } + } + } catch (e: Throwable) { + ResultWithDiagnostics.Failure(e.asDiagnostics()) + } +} diff --git a/settings.gradle b/settings.gradle index be47408f663..0daf118ca56 100644 --- a/settings.gradle +++ b/settings.gradle @@ -151,6 +151,10 @@ include ":kotlin-build-common", ":kotlin-annotations-jvm", ":kotlin-annotations-android", ":kotlin-scripting-common", + ":kotlin-scripting-jvm", + ":kotlin-scripting-jvm-host", + ":examples:scripting-jvm-simple-script", + ":examples:scripting-jvm-maven-deps", ":pill:generate-all-tests", ":include:kotlin-compiler", @@ -245,6 +249,10 @@ project(':examples:kotlin-jsr223-daemon-local-eval-example').projectDir = "$root project(':kotlin-annotations-jvm').projectDir = "$rootDir/libraries/tools/kotlin-annotations-jvm" as File project(':kotlin-annotations-android').projectDir = "$rootDir/libraries/tools/kotlin-annotations-android" as File project(':kotlin-scripting-common').projectDir = "$rootDir/libraries/scripting/common" as File +project(':kotlin-scripting-jvm').projectDir = "$rootDir/libraries/scripting/jvm" as File +project(':kotlin-scripting-jvm-host').projectDir = "$rootDir/libraries/scripting/jvm-host" as File +project(':examples:scripting-jvm-simple-script').projectDir = "$rootDir/libraries/examples/scripting/jvm-simple-script" as File +project(':examples:scripting-jvm-maven-deps').projectDir = "$rootDir/libraries/examples/scripting/jvm-maven-deps" as File project(':pill:generate-all-tests').projectDir = "$rootDir/plugins/pill/generate-all-tests" as File // plugin markers: