jbangdev / jbang

Unleash the power of Java - JBang Lets Students, Educators and Professional Developers create, edit and run self-contained source-only Java programs with unprecedented ease.
https://jbang.dev
MIT License
1.39k stars 156 forks source link

Idea about Kotlin kts support #1117

Open linux-china opened 2 years ago

linux-china commented 2 years ago

Add Kotlin script(kts) support for jbang because logic to run kts is different with kt source file.

//KOTLIN 1.5.32

println("Hello, Kotlin Script!")
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import kotlin.script.experimental.jvm.RunnerKt;
import kotlin.script.templates.standard.ScriptTemplateWithArgs;
import org.jetbrains.annotations.NotNull;

@Metadata(mv = {1, 6, 0}, k = 1, xi = 52, d1 = {"\000\022\n\002\030\002\n\002\030\002\n\000\n\002\020\021\n\002\020\016\030\0002\0020\001B\016\022\f\020\002\032\b\022\004\022\0020\0040\003"}, d2 = {"LHello;", "Lkotlin/script/templates/standard/ScriptTemplateWithArgs;", "args", "", ""})
public final class Hello extends ScriptTemplateWithArgs {
  public Hello(@NotNull String[] args) {
    super(args);
    System.out.println("good");
  }

  public static final void main(@NotNull String[] args) {
    Intrinsics.checkNotNullParameter(args, "args");
    RunnerKt.runCompiledScript(Hello.class, args);
  }
}
public class CompiledKtsRunner {
    public static void main(String[] args) throws Exception {
        String ktsName = System.getProperty("kts");
        Class<?> clazz = CompiledKtsRunner.class.getClassLoader().loadClass(ktsName);
        clazz.getDeclaredConstructor(String[].class).newInstance(new Object[]{args});
    }
}
public class KtsSource extends ScriptSource { 
    ....
    @Override
    public List<String> getRuntimeOptions() {
        String fileName = getResourceRef().getFile().getName();
        fileName = fileName.substring(0, fileName.lastIndexOf('.'));
        String ktClass = fileName.substring(0, 1).toUpperCase() + fileName.substring(1);
        return Arrays.asList("-Dkts=" + ktClass);
    }

    @Override
    public List<String> getAllDependencies() {
        final List<String> allDependencies = super.getAllDependencies();
        allDependencies.add("com.example.jbang:kts-runner:1.0.0");
        return allDependencies;
    }

    @Override
    public String getMainClass() {
        return "com.example.jbang.CompiledKtsRunner";
    }

     @Override
    public Predicate<ClassInfo> getMainFinder() {
        return pubClass -> false;
    }

}
maxandersen commented 2 years ago

shouldn't we be able to treat .kst like we treat .jsh ? skips compile and pass it to jshell/kotlin directly ?

linux-china commented 2 years ago

@maxandersen I think main reason is about performance. It's very slow to execute Kotlin script by kotlin CLI, and compare as following:

kotlin hello.kts  6.50s user 0.47s system 198% cpu 3.522 total
java -Dkts=Hello -classpath  com.example.jbang.CompiledKtsRunner  0.11s user 0.04s system 33% cpu 0.436 total

This is the main reason that kscript adopts compile/jar solution, and not to use kotlin cli to execute script.