Skip to content

Commit

Permalink
Experimental | Optimize & Fix (独立实现KTS的JSR223)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFloodDragon committed Jul 15, 2024
1 parent d6cd747 commit 1212d85
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@ import cn.fd.ratziel.script.impl.SimpleScriptEnvironment
*/
open class ScriptedAction(
/**
* 脚本动作块
* 可执行脚本
*/
val script: EvaluableScript,
) : ItemAction {

override fun execute(context: ArgumentContext) {
// 环境
val env = context.popOr(ScriptEnvironment::class.java, SimpleScriptEnvironment())
// 评估
script.evaluate(ScriptTypes.KETHER.executor, env)
val environment = context.popOr(ScriptEnvironment::class.java, SimpleScriptEnvironment(context))
script.evaluate(ScriptTypes.KETHER.executor, environment)
}

}
1 change: 1 addition & 0 deletions project/module-script/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dependencies {
compileOnly(kotlin("scripting-jvm"))
compileOnly(kotlin("scripting-jvm-host"))
compileOnly(kotlin("scripting-compiler"))
compileOnly(kotlin("compiler"))
// Kether: Taboolib
compileTaboo("module-kether")
// JavaScript: Nashorn Engine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@
value = "!org.jetbrains.kotlin:kotlin-scripting-compiler-impl:" + CoreEnv.KOTLIN_VERSION,
transitive = false
),
@RuntimeDependency(
value = "!org.jetbrains.kotlin:kotlin-scripting-jsr223-unshaded:" + CoreEnv.KOTLIN_VERSION,
transitive = false
),
@RuntimeDependency(
value = "!org.jetbrains.intellij.deps:trove4j:1.0.20200330",
test = "!gnu.trove.TObjectHashingStrategy",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cn.fd.ratziel.script.api;

import cn.fd.ratziel.function.argument.ArgumentContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -34,4 +35,15 @@ default void set(@NotNull String key, @Nullable Object value) {
getBindings().put(key, value);
}

/**
* 获取脚本参数上下文
*/
@NotNull
ArgumentContext getContext();

/**
* 设置脚本参数上下文
*/
void setContext(@NotNull ArgumentContext context);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cn.fd.ratziel.script.impl;

import cn.fd.ratziel.function.argument.ArgumentContext;
import cn.fd.ratziel.function.argument.SimpleArgumentContext;
import cn.fd.ratziel.script.api.ScriptEnvironment;
import org.jetbrains.annotations.NotNull;

Expand All @@ -19,10 +21,20 @@ public SimpleScriptEnvironment() {
}

public SimpleScriptEnvironment(@NotNull Bindings bindings) {
this(bindings, new SimpleArgumentContext());
}

public SimpleScriptEnvironment(@NotNull ArgumentContext context) {
this(new SimpleBindings(), context);
}

public SimpleScriptEnvironment(@NotNull Bindings bindings, @NotNull ArgumentContext context) {
this.bindings = bindings;
this.context = context;
}

private Bindings bindings;
private ArgumentContext context;

@Override
public @NotNull Bindings getBindings() {
Expand All @@ -34,4 +46,14 @@ public void setBindings(@NotNull Bindings bindings) {
this.bindings = bindings;
}

@Override
public @NotNull ArgumentContext getContext() {
return context;
}

@Override
public void setContext(@NotNull ArgumentContext context) {
this.context = context;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ object ScriptBlockBuilder {

fun build(section: Any): ScriptBlock {
when (section) {
// Block
is String -> return Block(SimpleScript(section))
// BasicBlock
is String -> return BasicBlock(section)
// ListBlock
is Iterable<*> -> return ListBlock(section.mapNotNull { l -> l?.let { build(it) } })
is Map<*, *> -> {
Expand Down Expand Up @@ -54,21 +54,51 @@ object ScriptBlockBuilder {

interface ScriptBlock : EvaluableScript

data class Block(val content: ScriptContent) : ScriptBlock {
override fun evaluate(executor: ScriptExecutor, env: ScriptEnvironment): Any? = executor.evaluate(content, env)
data class BasicBlock(val script: ScriptContent) : ScriptBlock {
constructor(content: String) : this(SimpleScript(content))

override fun evaluate(executor: ScriptExecutor, env: ScriptEnvironment): Any? =
if (script is EvaluableScript) script.evaluate(executor, env) else executor.evaluate(script, env)
}

data class PrimitiveBlock(val value: Any?) : ScriptBlock {
override fun evaluate(executor: ScriptExecutor, env: ScriptEnvironment) = value
}

data class ListBlock(val list: Iterable<ScriptBlock>) : ScriptBlock {
val handled = buildList {
var combined = mutableListOf<String>()
fun combine() {
if (combined.isEmpty()) return
// 将脚本列表通过换行符合并成单个脚本字符串
val lined = combined.joinToString("\n")
// 清空
combined = mutableListOf()
// 然后添加基础代码块
add(BasicBlock(lined))
}
for (block in list) {
if (block is BasicBlock) {
combined.add(block.script.content)
} else {
// 非基础代码块检查合并一次
combine()
// 加入代码块
add(block)
}
}
// 尾处理: 检查合并一次
combine()
}.toTypedArray()

override fun evaluate(executor: ScriptExecutor, env: ScriptEnvironment): Any? {
var result: Any? = null
for (raw in list) {
result = raw.evaluate(executor, env)
val iterator = handled.iterator()
while (iterator.hasNext()) {
val result = iterator.next().evaluate(executor, env)
// 在没有下一个元素(最后一个脚本执行完后), 返回结果
if (!iterator.hasNext()) return result
}
return result
return null
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@ import javax.script.ScriptEngineManager
object JavaScriptExecutor : CompilableScriptExecutor {

override fun compile(script: String?): CompiledScript {
return (engine as Compilable).compile(script)
return (newEngine() as Compilable).compile(script)
}

override fun evaluate(script: ScriptContent, environment: ScriptEnvironment): Any? {
return engine.eval(script.content, environment.bindings)
return newEngine().eval(script.content, environment.bindings)
}

val engine: ScriptEngine by lazy {
fun newEngine(): ScriptEngine =
ScriptEngineManager(this::class.java.classLoader).getEngineByName("js")
?: throw NullPointerException("Cannot find ScriptEngine for JavaScriptExecutor")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@ import javax.script.ScriptEngineManager
object JexlExecutor : CompilableScriptExecutor {

override fun compile(script: String?): CompiledScript {
return (engine as Compilable).compile(script)
return (newEngine() as Compilable).compile(script)
}

override fun evaluate(script: ScriptContent, environment: ScriptEnvironment): Any? {
return engine.eval(script.content, environment.bindings)
return newEngine().eval(script.content, environment.bindings)
}

val engine: ScriptEngine by lazy {
fun newEngine(): ScriptEngine =
ScriptEngineManager(this::class.java.classLoader).getEngineByName("Jexl")
?: throw NullPointerException("Cannot find ScriptEngine for JexlExecutor")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ import javax.script.ScriptEngineManager
*/
object KotlinScriptExecutor : CompilableScriptExecutor {

override fun compile(script: String?): CompiledScript {
return (engine as Compilable).compile(script)
override fun compile(script: String): CompiledScript {
return (newEngine() as Compilable).compile(script)
}

override fun evaluate(script: ScriptContent, environment: ScriptEnvironment): Any? {
return engine.eval(script.content, environment.bindings)
return newEngine().eval(script.content, environment.bindings)
}

val engine: ScriptEngine by lazy {
fun newEngine(): ScriptEngine =
ScriptEngineManager(this::class.java.classLoader).getEngineByName("kotlin")
?: throw NullPointerException("Cannot find ScriptEngine for KotlinScriptExecutor")
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cn.fd.ratziel.script.internal.jsr223

import cn.fd.ratziel.script.kts.KotlinScriptConfiguration
import org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineFactoryBase
import org.jetbrains.kotlin.cli.common.repl.ScriptArgsWithTypes
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngine
import kotlin.script.experimental.jvmhost.jsr223.KotlinJsr223ScriptEngineImpl

/**
* KotlinJsr223DefaultScriptEngineFactory
*
* @author TheFloodDragon
* @since 2024/7/15 19:02
*/
@Suppress("unused")
class KotlinJsr223DefaultScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {

override fun getScriptEngine(): ScriptEngine =
KotlinJsr223ScriptEngineImpl(
this,
KotlinScriptConfiguration.compilation,
KotlinScriptConfiguration.evaluation,
) { ScriptArgsWithTypes(arrayOf(it.getBindings(ScriptContext.ENGINE_SCOPE).orEmpty()), arrayOf(Bindings::class)) }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cn.fd.ratziel.script.kts

import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.JvmDependencyFromClassLoader
import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvm.jvmTarget
import kotlin.script.experimental.jvmhost.jsr223.configureProvidedPropertiesFromJsr223Context
import kotlin.script.experimental.jvmhost.jsr223.importAllBindings
import kotlin.script.experimental.jvmhost.jsr223.jsr223

/**
* KotlinScriptConfiguration
*
* @author TheFloodDragon
* @since 2024/7/15 19:11
*/
object KotlinScriptConfiguration {

/**
* [ScriptCompilationConfiguration]
*/
val compilation = ScriptCompilationConfiguration {
refineConfiguration {
beforeCompiling(::configureProvidedPropertiesFromJsr223Context)
}
jvm {
dependencies(JvmDependencyFromClassLoader { this::class.java.classLoader })
jvmTarget(System.getProperty("java.specification.version") ?: "1.8")
}
jsr223 {
importAllBindings(true)
}
ide {
acceptedLocations(ScriptAcceptedLocation.Everywhere)
}
}

/**
* [ScriptEvaluationConfiguration]
*/
val evaluation = ScriptEvaluationConfiguration {
refineConfigurationBeforeEvaluate(::configureProvidedPropertiesFromJsr223Context)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cn.fd.ratziel.script.internal.jsr223.KotlinJsr223DefaultScriptEngineFactory

0 comments on commit 1212d85

Please sign in to comment.