Does someone more knowledgeable with K2 plugins th...
# compiler
g
Does someone more knowledgeable with K2 plugins think it is possible to write a plugin to extract the lambdas from all the calls to a function like
remote
 
Copy code
package com.myexample

inline fun <R, P0> remote(crossinline func: (P0) -> R): RemoteFunction1<R, P0> {
    return RemoteFunction1(TODO("Generated by compiler at call site")) { it -> func(it) }
}

data class RemoteFunction1<R, P0>(
    val id: String,
    val func: (P0) -> R
)
  But only the calls to
remote
that are in
jvmMain
. Like in the example below
Copy code
fun main(){
    val myRemote = remote<_, Int> {
        it + 3
    }
}
  I want to conceptually extract:
Copy code
{
    it + 3
}
  And generate a corresponding virtual declaration in
jsMain
conceptually like:
Copy code
val myRemotes = mapOf<String, (Any?) -> Any?>(
    "ID generated by compiler representing call site" to {
        it + 3
    },
    // ...
)
  This is a very simplistic version of what I am trying to do (I need to handle closure scopes and some other annoyances but I'm sure I'm plenty comfortable with that) I'm just not sure if or how a cross source set plugin might work. (And if you're curious, the whole point of this is to be able to run code in the browser from a quick inline declaration on the server)
y
Initial thoughts: I think you only need an IR plugin here, not a FIR one. I think dealing with closure scopes is very easy in IR IIRC because it mentions them explicitly. I think there's also an IR way to check what platform you're compiling for. Are you trying to take jvmMain declarations and generate jsMain declarations based on them though? Not sure how possible that'll be. Keep in mind that those lambdas might include jvm-only functions
g
Essentially I want to treat any code within the lambda provided to
remote
as
commonMain
code (i.e. it could be compiled in
commonMain
and I want to throw an error at editor time if it can't). But the goal is to send an instruction to a browser (so Kotlin/JS) to run the lambda that was defined within the scope of
jvmMain
And yeah I'm not sure if this is possible either, I'm hoping someone could point me in the right direction
A complicated but potential approach could be two projects and two compiler plugins one plugin that extracts the FIR from the parent project and serializes it to a file and another plugin operating on a dependent project that consumes the serialized FIR and generates the declarations. But that's fairly complicated (honestly more complicated than I want) and probably has other downsides
y
Is there a reason that you don't want the code to just be written in
commonMain
? If you did that, you could simply do the transformation in IR, producing the special code in JS only.
g
Yeah it is very inconvenient and it is no longer a lambda at that point, just a named function somewhere, that is what the framework does right now. And when they are defined in the commonMain there is no need for a compiler plugin. I am making something like Phoenix LiveView or HTMX, but purely in kotlin. The JVM server owns all of the logic and the client is very very dumb, knowing nothing but the abstract elements it can render. All content for the web page is incrementally communicated over a web socket. When a user interacts with the UI the interaction is handled by the server and then a ui state diff is communicated to the client. The client does not "think" on its own. But when it comes to things like animations, canvas rendering, and interaction prediction (That last one fundamentally can't be done on the server) the locality of execution is important, for latency, bandwidth, or both. These remote functions are small things to run on the client, but still determined by the server. Like I always want the width and length of some resizable element to be the same. That could be done by the server, but latency would make it perform poorly
y
Hmmmm, so in other words you want to "ship off a function" to the client (but the functions are determined beforehand at compiletime, so you're shipping off just a name). Crazy idea would be to have some complicated DSL that's written in commonMain that is thus shipped off to both (so that your lambdas can stay "local") but the dsl makes it so that the lambdas run client-side (this is unnecessarily complicated though)
Actually, here's a much simpler idea: make an IR transformer, collect all the lambdas, serialize their IR, deserialize it into a custom JS compilation, and thus produce JS files as resources for the JVM server. Then you can serve those files easily. The key part here is that you run a second instance of the compiler yourself instead of somehow making JVM run first before JS