Implement direct bindings to script properties mapping in the JSR-223 implementation
fix infrastructure and codegen parts
This commit is contained in:
@@ -143,7 +143,7 @@ class ScriptCodegen private constructor(
|
|||||||
iv.invokespecial("java/lang/Object", "<init>", "()V", false)
|
iv.invokespecial("java/lang/Object", "<init>", "()V", false)
|
||||||
} else {
|
} else {
|
||||||
val ctorDesc = superclass.unsubstitutedPrimaryConstructor
|
val ctorDesc = superclass.unsubstitutedPrimaryConstructor
|
||||||
?: throw RuntimeException("Primary constructor not found for script template " + superclass.toString())
|
?: throw RuntimeException("Primary constructor not found for script template " + superclass.toString())
|
||||||
|
|
||||||
iv.load(0, classType)
|
iv.load(0, classType)
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ class ScriptCodegen private constructor(
|
|||||||
for (superclassParam in ctorDesc.valueParameters) {
|
for (superclassParam in ctorDesc.valueParameters) {
|
||||||
val valueParam = valueParameters.first { it.name == superclassParam.name }
|
val valueParam = valueParameters.first { it.name == superclassParam.name }
|
||||||
val paramType = typeMapper.mapType(valueParam.type)
|
val paramType = typeMapper.mapType(valueParam.type)
|
||||||
iv.load(valueParam!!.index + scriptContext.ctorValueParametersStart + 1, paramType)
|
val idx = frameMap.enter(valueParam, paramType)
|
||||||
frameMap.enterTemp(paramType)
|
iv.load(idx, paramType)
|
||||||
}
|
}
|
||||||
|
|
||||||
val ctorMethod = typeMapper.mapToCallableMethod(ctorDesc, false)
|
val ctorMethod = typeMapper.mapToCallableMethod(ctorDesc, false)
|
||||||
@@ -166,14 +166,14 @@ class ScriptCodegen private constructor(
|
|||||||
iv.load(0, classType)
|
iv.load(0, classType)
|
||||||
|
|
||||||
scriptDescriptor.implicitReceivers.forEachIndexed { receiverIndex, receiver ->
|
scriptDescriptor.implicitReceivers.forEachIndexed { receiverIndex, receiver ->
|
||||||
val receiversParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE))
|
val receiversParamIndex = frameMap.enter(receiver, AsmUtil.getArrayType(OBJECT_TYPE))
|
||||||
val name = scriptContext.getImplicitReceiverName(receiverIndex)
|
val name = scriptContext.getImplicitReceiverName(receiverIndex)
|
||||||
genFieldFromParam(typeMapper.mapClass(receiver), receiversParamIndex, name)
|
genFieldFromParam(typeMapper.mapClass(receiver), receiversParamIndex, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptDescriptor.scriptProvidedProperties.forEachIndexed { envVarIndex, envVar ->
|
scriptDescriptor.scriptProvidedProperties.forEachIndexed { envVarIndex, envVar ->
|
||||||
val fieldClassType = typeMapper.mapType(envVar)
|
val fieldClassType = typeMapper.mapType(envVar)
|
||||||
val envVarParamIndex = frameMap.enterTemp(fieldClassType)
|
val envVarParamIndex = frameMap.enter(envVar, fieldClassType)
|
||||||
val name = scriptContext.getProvidedPropertyName(envVarIndex)
|
val name = scriptContext.getProvidedPropertyName(envVarIndex)
|
||||||
genFieldFromParam(fieldClassType, envVarParamIndex, name)
|
genFieldFromParam(fieldClassType, envVarParamIndex, name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,10 +67,8 @@ class ScriptContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ctorValueParametersStart = if (earlierScripts.isNotEmpty()) 1 else 0
|
|
||||||
|
|
||||||
private val ctorImplicitReceiversParametersStart =
|
private val ctorImplicitReceiversParametersStart =
|
||||||
ctorValueParametersStart + (scriptDescriptor.getSuperClassNotAny()?.unsubstitutedPrimaryConstructor?.valueParameters?.size ?: 0)
|
(scriptDescriptor.getSuperClassNotAny()?.unsubstitutedPrimaryConstructor?.valueParameters?.size ?: 0)
|
||||||
|
|
||||||
private val ctorProvidedPropertiesParametersStart =
|
private val ctorProvidedPropertiesParametersStart =
|
||||||
ctorImplicitReceiversParametersStart + scriptDescriptor.implicitReceivers.size
|
ctorImplicitReceiversParametersStart + scriptDescriptor.implicitReceivers.size
|
||||||
|
|||||||
+55
@@ -179,6 +179,61 @@ obj
|
|||||||
Assert.assertEquals(111, result2)
|
Assert.assertEquals(111, result2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEvalWithContextDirect() {
|
||||||
|
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
|
||||||
|
|
||||||
|
engine.put("z", 33)
|
||||||
|
|
||||||
|
engine.eval("val x = 10 + z")
|
||||||
|
|
||||||
|
val result = engine.eval("x + 20")
|
||||||
|
Assert.assertEquals(63, result)
|
||||||
|
|
||||||
|
// in the current implementation the history is shared between contexts, so "x" could also be used in this line,
|
||||||
|
// but this behaviour probably will not be preserved in the future, since contexts may become completely isolated
|
||||||
|
val result2 = engine.eval("11 + boundValue", engine.createBindings().apply {
|
||||||
|
put("boundValue", 100)
|
||||||
|
})
|
||||||
|
Assert.assertEquals(111, result2)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEvalWithContextNamesWithSymbols() {
|
||||||
|
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
|
||||||
|
|
||||||
|
engine.put("\u263a", 2)
|
||||||
|
engine.put("a.b", 3)
|
||||||
|
engine.put("c:d", 5)
|
||||||
|
engine.put("e;f", 7)
|
||||||
|
engine.put("g\$h", 11)
|
||||||
|
engine.put("i<j", 13)
|
||||||
|
engine.put("k>l", 17)
|
||||||
|
engine.put("m[n", 19)
|
||||||
|
engine.put("o]p", 23)
|
||||||
|
engine.put("q/r", 29)
|
||||||
|
engine.put("s\\t", 31)
|
||||||
|
engine.put("u v", 37)
|
||||||
|
engine.put(" ", 41)
|
||||||
|
engine.put(" ", 43)
|
||||||
|
|
||||||
|
Assert.assertEquals(4, engine.eval("`\u263a` * 2"))
|
||||||
|
Assert.assertEquals(5, engine.eval("2 + `a\\,b`"))
|
||||||
|
Assert.assertEquals(2, engine.eval("`a\\,b` - 1"))
|
||||||
|
Assert.assertEquals(6, engine.eval("1 + `c\\!d`"))
|
||||||
|
Assert.assertEquals(7, engine.eval("`e\\?f`"))
|
||||||
|
Assert.assertEquals(11, engine.eval("`g\\%h`"))
|
||||||
|
Assert.assertEquals(13, engine.eval("`i\\^j`"))
|
||||||
|
Assert.assertEquals(17, engine.eval("`k\\_l`"))
|
||||||
|
Assert.assertEquals(19, engine.eval("`m\\{n`"))
|
||||||
|
Assert.assertEquals(23, engine.eval("`o\\}p`"))
|
||||||
|
Assert.assertEquals(29, engine.eval("`q\\|r`"))
|
||||||
|
Assert.assertEquals(31, engine.eval("`s\\-t`"))
|
||||||
|
Assert.assertEquals(37, engine.eval("`u v`"))
|
||||||
|
Assert.assertEquals(41, engine.eval("`_`"))
|
||||||
|
Assert.assertEquals(43, engine.eval("`____`"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSimpleEvalInEval() {
|
fun testSimpleEvalInEval() {
|
||||||
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
|
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
|
||||||
|
|||||||
+68
-1
@@ -8,12 +8,20 @@ package kotlin.script.experimental.jsr223
|
|||||||
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY
|
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY
|
||||||
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_STATE_BINDINGS_KEY
|
import org.jetbrains.kotlin.cli.common.repl.KOTLIN_SCRIPT_STATE_BINDINGS_KEY
|
||||||
import javax.script.Bindings
|
import javax.script.Bindings
|
||||||
|
import javax.script.ScriptContext
|
||||||
import javax.script.ScriptEngine
|
import javax.script.ScriptEngine
|
||||||
import kotlin.script.experimental.annotations.KotlinScript
|
import kotlin.script.experimental.annotations.KotlinScript
|
||||||
|
import kotlin.script.experimental.api.*
|
||||||
|
import kotlin.script.experimental.jvmhost.jsr223.getScriptContext
|
||||||
|
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
|
||||||
|
import kotlin.script.experimental.jvmhost.jsr223.jsr223
|
||||||
import kotlin.script.templates.standard.ScriptTemplateWithBindings
|
import kotlin.script.templates.standard.ScriptTemplateWithBindings
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@KotlinScript
|
@KotlinScript(
|
||||||
|
compilationConfiguration = KotlinJsr223DefaultScriptCompilationConfiguration::class,
|
||||||
|
evaluationConfiguration = KotlinJsr223DefaultScriptEvaluationConfiguration::class
|
||||||
|
)
|
||||||
abstract class KotlinJsr223DefaultScript(val jsr223Bindings: Bindings) : ScriptTemplateWithBindings(jsr223Bindings) {
|
abstract class KotlinJsr223DefaultScript(val jsr223Bindings: Bindings) : ScriptTemplateWithBindings(jsr223Bindings) {
|
||||||
|
|
||||||
private val myEngine: ScriptEngine? get() = bindings[KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY]?.let { it as? ScriptEngine }
|
private val myEngine: ScriptEngine? get() = bindings[KOTLIN_SCRIPT_ENGINE_BINDINGS_KEY]?.let { it as? ScriptEngine }
|
||||||
@@ -47,3 +55,62 @@ abstract class KotlinJsr223DefaultScript(val jsr223Bindings: Bindings) : ScriptT
|
|||||||
|
|
||||||
fun createBindings(): Bindings = withMyEngine { it.createBindings() }
|
fun createBindings(): Bindings = withMyEngine { it.createBindings() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object KotlinJsr223DefaultScriptCompilationConfiguration : ScriptCompilationConfiguration(
|
||||||
|
{
|
||||||
|
refineConfiguration {
|
||||||
|
beforeCompiling { context ->
|
||||||
|
val jsr223context = context.compilationConfiguration[ScriptCompilationConfiguration.jsr223.getScriptContext]?.invoke()
|
||||||
|
if (jsr223context != null && context.compilationConfiguration[ScriptCompilationConfiguration.jsr223.importAllBindings] == true) {
|
||||||
|
val updatedProperties =
|
||||||
|
context.compilationConfiguration[ScriptCompilationConfiguration.providedProperties]?.toMutableMap() ?: hashMapOf()
|
||||||
|
val allBindings = (jsr223context.getBindings(ScriptContext.GLOBAL_SCOPE).toMutableMap() ?: hashMapOf()).apply {
|
||||||
|
val engineBindings = jsr223context.getBindings(ScriptContext.ENGINE_SCOPE)
|
||||||
|
if (engineBindings != null)
|
||||||
|
putAll(engineBindings)
|
||||||
|
}
|
||||||
|
for ((k, v) in allBindings) {
|
||||||
|
// only adding bindings that are not already defined
|
||||||
|
if (!updatedProperties.containsKey(k)) {
|
||||||
|
// TODO: add only valid names
|
||||||
|
// TODO: find out how it's implemented in other jsr223 engines for typed languages, since this approach prevent certain usage scenarios, e.g. assigning back value of a "sibling" type
|
||||||
|
updatedProperties[k] = KotlinType(v::class)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScriptCompilationConfiguration(context.compilationConfiguration) {
|
||||||
|
providedProperties(updatedProperties)
|
||||||
|
}.asSuccess()
|
||||||
|
} else context.compilationConfiguration.asSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsr223 {
|
||||||
|
importAllBindings(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
object KotlinJsr223DefaultScriptEvaluationConfiguration : ScriptEvaluationConfiguration(
|
||||||
|
{
|
||||||
|
refineConfigurationBeforeEvaluate { context ->
|
||||||
|
val jsr223context = context.evaluationConfiguration[ScriptEvaluationConfiguration.jsr223.getScriptContext]?.invoke()
|
||||||
|
val knownProperties = context.compiledScript.compilationConfiguration[ScriptCompilationConfiguration.providedProperties]
|
||||||
|
if (jsr223context != null && knownProperties != null && knownProperties.isNotEmpty()) {
|
||||||
|
val updatedProperties =
|
||||||
|
context.evaluationConfiguration[ScriptEvaluationConfiguration.providedProperties]?.toMutableMap() ?: hashMapOf()
|
||||||
|
val engineBindings = jsr223context.getBindings(ScriptContext.ENGINE_SCOPE)
|
||||||
|
val globalBindings = jsr223context.getBindings(ScriptContext.GLOBAL_SCOPE)
|
||||||
|
for (prop in knownProperties) {
|
||||||
|
val v = when {
|
||||||
|
engineBindings?.containsKey(prop.key) == true -> engineBindings[prop.key]
|
||||||
|
globalBindings?.containsKey(prop.key) == true -> globalBindings[prop.key]
|
||||||
|
else -> return@refineConfigurationBeforeEvaluate ResultWithDiagnostics.Failure("Property ${prop.key} is not found in the bindings".asErrorDiagnostics())
|
||||||
|
}
|
||||||
|
updatedProperties[prop.key] = v
|
||||||
|
}
|
||||||
|
ScriptEvaluationConfiguration(context.evaluationConfiguration) {
|
||||||
|
providedProperties(updatedProperties)
|
||||||
|
}.asSuccess()
|
||||||
|
} else context.evaluationConfiguration.asSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.jsr223
|
||||||
|
|
||||||
|
import javax.script.ScriptContext
|
||||||
|
import kotlin.script.experimental.api.*
|
||||||
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
|
import kotlin.script.experimental.host.ScriptingHostConfigurationKeys
|
||||||
|
import kotlin.script.experimental.util.PropertiesCollection
|
||||||
|
|
||||||
|
interface Jsr223HostConfigurationKeys
|
||||||
|
|
||||||
|
open class Jsr223HostConfigurationBuilder : PropertiesCollection.Builder(),
|
||||||
|
Jsr223HostConfigurationKeys {
|
||||||
|
companion object : Jsr223HostConfigurationBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
val ScriptingHostConfigurationKeys.jsr223 get() = Jsr223HostConfigurationBuilder()
|
||||||
|
|
||||||
|
val Jsr223HostConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>()
|
||||||
|
|
||||||
|
|
||||||
|
interface Jsr223CompilationConfigurationKeys
|
||||||
|
|
||||||
|
open class Jsr223CompilationConfigurationBuilder : PropertiesCollection.Builder(),
|
||||||
|
Jsr223CompilationConfigurationKeys {
|
||||||
|
companion object : Jsr223CompilationConfigurationBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
val ScriptCompilationConfigurationKeys.jsr223 get() = Jsr223CompilationConfigurationBuilder()
|
||||||
|
|
||||||
|
val Jsr223CompilationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?> {
|
||||||
|
get(ScriptCompilationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Jsr223CompilationConfigurationKeys.importAllBindings by PropertiesCollection.key<Boolean>(false)
|
||||||
|
|
||||||
|
interface Jsr223EvaluationConfigurationKeys
|
||||||
|
|
||||||
|
open class Jsr223EvaluationConfigurationBuilder : PropertiesCollection.Builder(),
|
||||||
|
Jsr223EvaluationConfigurationKeys {
|
||||||
|
companion object : Jsr223EvaluationConfigurationBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
val ScriptEvaluationConfigurationKeys.jsr223 get() = Jsr223EvaluationConfigurationBuilder()
|
||||||
|
|
||||||
|
val Jsr223EvaluationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?> {
|
||||||
|
get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+37
-2
@@ -12,7 +12,10 @@ import javax.script.ScriptContext
|
|||||||
import javax.script.ScriptEngineFactory
|
import javax.script.ScriptEngineFactory
|
||||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||||
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
|
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
|
||||||
|
import kotlin.script.experimental.api.hostConfiguration
|
||||||
|
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvm.baseClassLoader
|
import kotlin.script.experimental.jvm.baseClassLoader
|
||||||
|
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||||
import kotlin.script.experimental.jvm.jvm
|
import kotlin.script.experimental.jvm.jvm
|
||||||
import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler
|
import kotlin.script.experimental.jvmhost.repl.JvmReplCompiler
|
||||||
import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator
|
import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluator
|
||||||
@@ -22,13 +25,35 @@ import kotlin.script.experimental.jvmhost.repl.JvmReplEvaluatorState
|
|||||||
|
|
||||||
class KotlinJsr223ScriptEngineImpl(
|
class KotlinJsr223ScriptEngineImpl(
|
||||||
factory: ScriptEngineFactory,
|
factory: ScriptEngineFactory,
|
||||||
val compilationConfiguration: ScriptCompilationConfiguration,
|
baseCompilationConfiguration: ScriptCompilationConfiguration,
|
||||||
val evaluationConfiguration: ScriptEvaluationConfiguration
|
baseEvaluationConfiguration: ScriptEvaluationConfiguration
|
||||||
) : KotlinJsr223JvmScriptEngineBase(factory), KotlinJsr223InvocableScriptEngine {
|
) : KotlinJsr223JvmScriptEngineBase(factory), KotlinJsr223InvocableScriptEngine {
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var lastScriptContext: ScriptContext? = null
|
||||||
|
|
||||||
|
val jsr223HostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) {
|
||||||
|
jsr223 {
|
||||||
|
getScriptContext { lastScriptContext ?: getContext() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val compilationConfiguration by lazy {
|
||||||
|
ScriptCompilationConfiguration(baseCompilationConfiguration) {
|
||||||
|
hostConfiguration(jsr223HostConfiguration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val evaluationConfiguration by lazy {
|
||||||
|
ScriptEvaluationConfiguration(baseEvaluationConfiguration) {
|
||||||
|
hostConfiguration(jsr223HostConfiguration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val replCompiler: ReplCompiler by lazy {
|
override val replCompiler: ReplCompiler by lazy {
|
||||||
JvmReplCompiler(compilationConfiguration)
|
JvmReplCompiler(compilationConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val localEvaluator by lazy {
|
private val localEvaluator by lazy {
|
||||||
GenericReplCompilingEvaluatorBase(replCompiler, JvmReplEvaluator(evaluationConfiguration))
|
GenericReplCompilingEvaluatorBase(replCompiler, JvmReplEvaluator(evaluationConfiguration))
|
||||||
}
|
}
|
||||||
@@ -50,5 +75,15 @@ class KotlinJsr223ScriptEngineImpl(
|
|||||||
|
|
||||||
override val baseClassLoader: ClassLoader
|
override val baseClassLoader: ClassLoader
|
||||||
get() = evaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]!!
|
get() = evaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]!!
|
||||||
|
|
||||||
|
override fun compileAndEval(script: String, context: ScriptContext): Any? {
|
||||||
|
// TODO: find a way to pass context to evaluation directly and avoid this hack
|
||||||
|
lastScriptContext = context
|
||||||
|
return try {
|
||||||
|
super.compileAndEval(script, context)
|
||||||
|
} finally {
|
||||||
|
lastScriptContext = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -71,7 +71,11 @@ class JvmReplEvaluator(
|
|||||||
}
|
}
|
||||||
else -> throw IllegalStateException("Expecting value with script instance, got $retVal")
|
else -> throw IllegalStateException("Expecting value with script instance, got $retVal")
|
||||||
}
|
}
|
||||||
else -> ReplEvalResult.Error.Runtime(res.reports.joinToString("\n") { it.message + (it.exception?.let { e -> ": $e" } ?: "") })
|
else ->
|
||||||
|
ReplEvalResult.Error.Runtime(
|
||||||
|
res.reports.joinToString("\n") { it.message + (it.exception?.let { e -> ": $e" } ?: "") },
|
||||||
|
res.reports.find { it.exception != null }?.exception as? Exception
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.util
|
||||||
|
|
||||||
|
fun String.toValidJvmIdentifier(): String =
|
||||||
|
if (isBlank()) "_".repeat(length)
|
||||||
|
else buildString(length) {
|
||||||
|
for (ch in this@toValidJvmIdentifier) {
|
||||||
|
// encoding is taken from https://blogs.oracle.com/jrose/symbolic-freedom-in-the-vm
|
||||||
|
when (ch) {
|
||||||
|
'/' -> append("\\|")
|
||||||
|
'.' -> append("\\,")
|
||||||
|
';' -> append("\\?")
|
||||||
|
'$' -> append("\\%")
|
||||||
|
'<' -> append("\\^")
|
||||||
|
'>' -> append("\\_")
|
||||||
|
'[' -> append("\\{")
|
||||||
|
']' -> append("\\}")
|
||||||
|
':' -> append("\\!")
|
||||||
|
'\\' -> append("\\-")
|
||||||
|
else -> append(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user