Is there some way to just pass an entire object `o...
# scripting
f
Is there some way to just pass an entire object
obj
as a "Binding", like wrapping the entire
.kts
Script I want to evaluate in a
with  (obj){ }
block?
The Jupyter Kotlin Kernel easily allows this, and in my scenario I want to dump a Kotlin Notebook to a
.kts
Script. The underlying Kotlin kernel is being passed a certain object as an implicitReceiver, and now I want to run this
.kts
Script with the same kind of object as an implicitReceiver so it works without changes
i
It is possible with the script customization (the
implicitReceiver
you mentioned above is a part of this customization, and the jupyter kernel uses exactly this API), but you'll need to add your own script definition and run your scripts with your definition accordingly, so it will not work with a default
.kts
files. You can have a look at the sample implementation here - https://github.com/Kotlin/kotlin-script-examples/tree/master/jvm/simple-main-kts
f
I am not sure what you mean by "will not work with a default
.kts
file"
but your answer does sound reassuring overall, will look into this
i
Well, to run a script you need a scripting host that knows how to handle compilation and evaluation of it. If you're running the script only inside your own host, you can setup it as you like. But as soon as you need to use some external infrastructure, like IntelliJ support or using
kotlinc
or
kotlin
cli tools as hosts, the problem arises - how to distinguish between different types of scripts (or scripts with different customizations). This is done by default with the filename extension, and recommended schema is to use double extension, e.g.
.main.kts
. In this schema the "default .kts" script is a basic script without any specific customization, and these hosts and IntelliJ will handle it accordingly, so you cannot add e.g an implicit receiver to this script and run it with the
kotlinc
. On the other hand, if you'll write a proper definition jar, e.g. as in the example I linked above, and will give your script a dedicated filename extension, you can run it via
kotlinc
and even get some basic IntelliJ support.
f
Ah, I am running this as part of another application and my current code is just:
Copy code
val engine = ScriptEngineManager(this.javaClass.classLoader).getEngineByExtension("kts")
val script = sourceFile.getFile(false).readText(Charsets.UTF_8)
val x = engine.eval(script)
So, if I understand correctly, I basically implement another script engine that I would then "acquire" (for lack of a better term) via
ScriptEngineManager(this.javaClass.classLoader).getEngineByExtension(".mynewextension")
The proper IntelliJ support would be kinda tempting though
FWIW: This is all happening as part of a Java Application that embeds a Kotlin kernel which is a feature I had to implement support for in the first place, so maybe I am doing something fairly unusual.
i
Yes, you can do it via JSR-223 as well, although unless you need to stick to JSR-223, I would not recommend it, it will be easier to implement a much simpler host. You may browse the repo I linked, it contains some samples too. Or tests for the
simple-main-kts
one.
f
I have no need for JSR-223
i
May be using JSR-223 from java is easier, depends on the details. But currently scripting API doesn't contain a good toolkit for implementing custom JSR-223 kernels, so you'll need to get your hands dirty a bit. But it's possible.
f
I already managed to get the dev environment for the application to support Kotlin enough for my needs, so I can write my plugin (that is supposed to provide runtime support for
.kts
scripts) in Kotlin
ah, the
evalFile
Method from the tests seems fairly close to what I was looking for
Does a definition like:
Copy code
@Suppress("unused")
@KotlinScript(
    fileExtension = "ghidra.kts",
    compilationConfiguration = SimpleMainKtsScriptDefinition::class,
    evaluationConfiguration = MainKtsEvaluationConfiguration::class
)
abstract class SimpleMainKtsScript(val args: Array<String>)
work if I want to pass a specific object as an implicitReceiver to the compilationConfiguration?
i
I'm not sure I understand the question, but you need to provide your own configuration and put implicit receiver there. I.e. copy the
SimpleMainKtsScriptDefinition
class and add
implicitReceiver
to the configuration. You'll need your copy of the evaluation configuration too, since you'll need to provide the implicit receiver on the evaluation.
f
yeah, I think I understand roughly what is happening in the class, but I really need to read up more on the Kotlin builder pattern, that still confuses me a lot
The Kotlin Koans seemed good for that, so I will look into that when I have proper time for that
thanks a lot for your answers and the pointer to the repo and that specific example!
👍 1