Fix all small and medium-sized issues after review
This commit is contained in:
+1
-1
@@ -38,6 +38,6 @@ data class CompilerMessageLocation private constructor(
|
||||
): CompilerMessageLocation =
|
||||
if (path == null) NO_LOCATION else CompilerMessageLocation(path, line, column, lineContent)
|
||||
|
||||
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +73,13 @@ fun tryConstructScriptClass(scriptClass: Class<*>, scriptArgs: List<String>): An
|
||||
}
|
||||
|
||||
try {
|
||||
return scriptClass.getConstructor(Array<String>::class.java).newInstance(*arrayOf<Any>(scriptArgs.toTypedArray()))
|
||||
return scriptClass.getConstructor(Array<String>::class.java).newInstance(scriptArgs.toTypedArray())
|
||||
}
|
||||
catch (e: java.lang.NoSuchMethodException) {
|
||||
catch (e: NoSuchMethodException) {
|
||||
for (ctor in scriptClass.kotlin.constructors) {
|
||||
val (ctorArgs, scriptArgsLeft) = ctor.parameters.fold(Pair(emptyList<Any>(), scriptArgs), ::foldingFunc)
|
||||
if (ctorArgs.size <= ctor.parameters.size && (scriptArgsLeft == null || scriptArgsLeft.isEmpty())) {
|
||||
val argsMap = ctorArgs.zip(ctor.parameters) { a, p -> Pair(p, a) }.toMap()
|
||||
val argsMap = ctor.parameters.zip(ctorArgs).toMap()
|
||||
try {
|
||||
return ctor.callBy(argsMap)
|
||||
}
|
||||
|
||||
+8
-11
@@ -25,8 +25,7 @@ import kotlin.concurrent.write
|
||||
|
||||
open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClassloader: ClassLoader?, val scriptArgs: Array<Any?>? = null, val scriptArgsTypes: Array<Class<*>>? = null) : ReplCompiledEvaluator {
|
||||
|
||||
private var classLoader: org.jetbrains.kotlin.cli.common.repl.ReplClassLoader =
|
||||
org.jetbrains.kotlin.cli.common.repl.ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
|
||||
private var classLoader: org.jetbrains.kotlin.cli.common.repl.ReplClassLoader = makeReplClassLoader(baseClassloader, baseClasspath)
|
||||
private val classLoaderLock = ReentrantReadWriteLock()
|
||||
|
||||
private class ClassWithInstance(val klass: Class<*>, val instance: Any)
|
||||
@@ -42,7 +41,7 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
classLoaderLock.read {
|
||||
if (newClasspath.isNotEmpty()) {
|
||||
classLoaderLock.write {
|
||||
classLoader = org.jetbrains.kotlin.cli.common.repl.ReplClassLoader(URLClassLoader(newClasspath.map { it.toURI().toURL() }.toTypedArray(), classLoader))
|
||||
classLoader = makeReplClassLoader(classLoader, newClasspath)
|
||||
}
|
||||
}
|
||||
compiledClasses.filter { it.path.endsWith(".class") }
|
||||
@@ -55,14 +54,9 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
|
||||
val constructorParams: Array<Class<*>> =
|
||||
(compiledLoadedClassesHistory.map { it.second.klass } +
|
||||
(scriptArgs?.asIterable()
|
||||
?.mapIndexed { i, it ->
|
||||
if (i < (scriptArgsTypes?.size ?: 0)) scriptArgsTypes!![i] else it?.javaClass ?: Any::class.java
|
||||
}
|
||||
?: emptyList()
|
||||
)
|
||||
(scriptArgs?.mapIndexed { i, it -> scriptArgsTypes?.getOrNull(i) ?: it?.javaClass ?: Any::class.java } ?: emptyList())
|
||||
).toTypedArray()
|
||||
val constructorArgs: Array<Any?> = (compiledLoadedClassesHistory.map { it.second.instance } + (scriptArgs?.asIterable() ?: emptyList())).toTypedArray()
|
||||
val constructorArgs: Array<Any?> = (compiledLoadedClassesHistory.map { it.second.instance } + scriptArgs.orEmpty()).toTypedArray()
|
||||
|
||||
val scriptInstanceConstructor = scriptClass.getConstructor(*constructorParams)
|
||||
val scriptInstance =
|
||||
@@ -85,4 +79,7 @@ open class GenericReplCompiledEvaluator(baseClasspath: Iterable<File>, baseClass
|
||||
companion object {
|
||||
private val SCRIPT_RESULT_FIELD_NAME = "\$\$result"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeReplClassLoader(baseClassloader: ClassLoader?, baseClasspath: Iterable<File>) =
|
||||
ReplClassLoader(URLClassLoader(baseClasspath.map { it.toURI().toURL() }.toTypedArray(), baseClassloader))
|
||||
@@ -23,7 +23,7 @@ import java.util.*
|
||||
|
||||
data class ReplCodeLine(val no: Int, val code: String) : Serializable {
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ data class CompiledClassData(val path: String, val bytes: ByteArray) : Serializa
|
||||
override fun equals(other: Any?): Boolean = (other as? CompiledClassData)?.let { path == it.path && Arrays.equals(bytes, it.bytes) } ?: false
|
||||
override fun hashCode(): Int = path.hashCode() + Arrays.hashCode(bytes)
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ sealed class ReplCheckResult : Serializable {
|
||||
override fun toString(): String = "Error(message = \"$message\""
|
||||
}
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ sealed class ReplCompileResult : Serializable {
|
||||
override fun toString(): String = "Error(message = \"$message\""
|
||||
}
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,10 +68,10 @@ sealed class ReplEvalResult : Serializable {
|
||||
sealed class Error(val message: String) : ReplEvalResult() {
|
||||
class Runtime(message: String) : Error(message)
|
||||
class CompileTime(message: String, val location: CompilerMessageLocation = CompilerMessageLocation.NO_LOCATION) : Error(message)
|
||||
override fun toString(): String = "${this.javaClass.kotlin.simpleName}Error(message = \"$message\""
|
||||
override fun toString(): String = "${this::class.simpleName}Error(message = \"$message\""
|
||||
}
|
||||
companion object {
|
||||
private val serialVersionUID: Long = 8228357578L // just a random number, should be changed when serialized data is changed
|
||||
private val serialVersionUID: Long = 8228357578L
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
@@ -74,28 +73,27 @@ open class GenericReplChecker(
|
||||
|
||||
fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
|
||||
|
||||
@Synchronized
|
||||
override fun check(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplCheckResult {
|
||||
synchronized(this) {
|
||||
val virtualFile =
|
||||
LightVirtualFile("line${codeLine.no}${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, codeLine.code).apply {
|
||||
charset = CharsetToolkit.UTF8_CHARSET
|
||||
}
|
||||
val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
||||
?: error("Script file not analyzed at line ${codeLine.no}: ${codeLine.code}")
|
||||
val virtualFile =
|
||||
LightVirtualFile("line${codeLine.no}${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, codeLine.code).apply {
|
||||
charset = CharsetToolkit.UTF8_CHARSET
|
||||
}
|
||||
val psiFile: KtFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile?
|
||||
?: error("Script file not analyzed at line ${codeLine.no}: ${codeLine.code}")
|
||||
|
||||
val errorHolder = createDiagnosticHolder()
|
||||
val errorHolder = createDiagnosticHolder()
|
||||
|
||||
val syntaxErrorReport = AnalyzerWithCompilerReport.Companion.reportSyntaxErrors(psiFile, errorHolder)
|
||||
val syntaxErrorReport = AnalyzerWithCompilerReport.Companion.reportSyntaxErrors(psiFile, errorHolder)
|
||||
|
||||
if (!syntaxErrorReport.isHasErrors) {
|
||||
lineState = LineState(codeLine, psiFile, errorHolder)
|
||||
}
|
||||
if (!syntaxErrorReport.isHasErrors) {
|
||||
lineState = LineState(codeLine, psiFile, errorHolder)
|
||||
}
|
||||
|
||||
return when {
|
||||
syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof -> ReplCheckResult.Incomplete
|
||||
syntaxErrorReport.isHasErrors -> ReplCheckResult.Error(errorHolder.renderedDiagnostics)
|
||||
else -> ReplCheckResult.Ok
|
||||
}
|
||||
return when {
|
||||
syntaxErrorReport.isHasErrors && syntaxErrorReport.isAllErrorsAtEof -> ReplCheckResult.Incomplete
|
||||
syntaxErrorReport.isHasErrors -> ReplCheckResult.Error(errorHolder.renderedDiagnostics)
|
||||
else -> ReplCheckResult.Ok
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,61 +111,59 @@ open class GenericReplCompiler(
|
||||
|
||||
private val descriptorsHistory = arrayListOf<Pair<ReplCodeLine, ScriptDescriptor>>()
|
||||
|
||||
@Synchronized
|
||||
override fun compile(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplCompileResult {
|
||||
synchronized(this) {
|
||||
|
||||
checkAndUpdateReplHistoryCollection(descriptorsHistory, history)?.let {
|
||||
return@compile ReplCompileResult.HistoryMismatch(it)
|
||||
}
|
||||
|
||||
val (psiFile, errorHolder) = run {
|
||||
if (lineState == null || lineState!!.codeLine != codeLine) {
|
||||
val res = check(codeLine, history)
|
||||
when (res) {
|
||||
ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete
|
||||
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location)
|
||||
ReplCheckResult.Ok -> {} // continue
|
||||
}
|
||||
}
|
||||
Pair(lineState!!.psiFile, lineState!!.errorHolder)
|
||||
}
|
||||
|
||||
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, environment.project, lastDependencies)
|
||||
if (lastDependencies != newDependencies) {
|
||||
lastDependencies = newDependencies
|
||||
}
|
||||
|
||||
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, codeLine.no)
|
||||
AnalyzerWithCompilerReport.Companion.reportDiagnostics(analysisResult.diagnostics, errorHolder, false)
|
||||
val scriptDescriptor = when (analysisResult) {
|
||||
is CliReplAnalyzerEngine.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(errorHolder.renderedDiagnostics)
|
||||
is CliReplAnalyzerEngine.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||
else -> error("Unexpected result ${analysisResult.javaClass}")
|
||||
}
|
||||
|
||||
val state = GenerationState(
|
||||
psiFile.project,
|
||||
ClassBuilderFactories.binaries(false),
|
||||
analyzerEngine.module,
|
||||
analyzerEngine.trace.bindingContext,
|
||||
listOf(psiFile),
|
||||
compilerConfiguration
|
||||
)
|
||||
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
|
||||
state.replSpecific.earlierScriptsForReplInterpreter = descriptorsHistory.map { it.second }
|
||||
state.beforeCompile()
|
||||
KotlinCodegenFacade.generatePackage(
|
||||
state,
|
||||
psiFile.script!!.getContainingKtFile().packageFqName,
|
||||
setOf(psiFile.script!!.getContainingKtFile()),
|
||||
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION)
|
||||
|
||||
descriptorsHistory.add(codeLine to scriptDescriptor)
|
||||
|
||||
return ReplCompileResult.CompiledClasses(state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
|
||||
state.replSpecific.hasResult,
|
||||
newDependencies?.let { environment.updateClasspath(it.classpath.map(::JvmClasspathRoot)) } ?: emptyList())
|
||||
checkAndUpdateReplHistoryCollection(descriptorsHistory, history)?.let {
|
||||
return@compile ReplCompileResult.HistoryMismatch(it)
|
||||
}
|
||||
|
||||
val (psiFile, errorHolder) = run {
|
||||
if (lineState == null || lineState!!.codeLine != codeLine) {
|
||||
val res = check(codeLine, history)
|
||||
when (res) {
|
||||
ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete
|
||||
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location)
|
||||
ReplCheckResult.Ok -> {} // continue
|
||||
}
|
||||
}
|
||||
Pair(lineState!!.psiFile, lineState!!.errorHolder)
|
||||
}
|
||||
|
||||
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, environment.project, lastDependencies)
|
||||
if (lastDependencies != newDependencies) {
|
||||
lastDependencies = newDependencies
|
||||
}
|
||||
|
||||
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, codeLine.no)
|
||||
AnalyzerWithCompilerReport.Companion.reportDiagnostics(analysisResult.diagnostics, errorHolder, false)
|
||||
val scriptDescriptor = when (analysisResult) {
|
||||
is CliReplAnalyzerEngine.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(errorHolder.renderedDiagnostics)
|
||||
is CliReplAnalyzerEngine.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
|
||||
else -> error("Unexpected result ${analysisResult.javaClass}")
|
||||
}
|
||||
|
||||
val state = GenerationState(
|
||||
psiFile.project,
|
||||
ClassBuilderFactories.binaries(false),
|
||||
analyzerEngine.module,
|
||||
analyzerEngine.trace.bindingContext,
|
||||
listOf(psiFile),
|
||||
compilerConfiguration
|
||||
)
|
||||
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
|
||||
state.replSpecific.earlierScriptsForReplInterpreter = descriptorsHistory.map { it.second }
|
||||
state.beforeCompile()
|
||||
KotlinCodegenFacade.generatePackage(
|
||||
state,
|
||||
psiFile.script!!.getContainingKtFile().packageFqName,
|
||||
setOf(psiFile.script!!.getContainingKtFile()),
|
||||
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION)
|
||||
|
||||
descriptorsHistory.add(codeLine to scriptDescriptor)
|
||||
|
||||
return ReplCompileResult.CompiledClasses(state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
|
||||
state.replSpecific.hasResult,
|
||||
newDependencies?.let { environment.updateClasspath(it.classpath.map(::JvmClasspathRoot)) } ?: emptyList())
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -188,9 +184,9 @@ open class GenericRepl(
|
||||
|
||||
private val compiledEvaluator = GenericReplCompiledEvaluator(compilerConfiguration.jvmClasspathRoots, baseClassloader, scriptArgs, scriptArgsTypes)
|
||||
|
||||
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult = synchronized(this) {
|
||||
return compileAndEval(this, compiledEvaluator, codeLine, history)
|
||||
}
|
||||
@Synchronized
|
||||
override fun eval(codeLine: ReplCodeLine, history: Iterable<ReplCodeLine>): ReplEvalResult =
|
||||
compileAndEval(this, compiledEvaluator, codeLine, history)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user