Hi all, I am looking for an equivalent of `IrGener...
# compiler
d
Hi all, I am looking for an equivalent of
IrGenerationExtension
but at the level of the FIR (i.e. after semantic resolution but before the lowerings). I know that FIR is still in active development but maybe there are already something that I can use. Thanks a lot to you all for any help you can provide me.
r
Hi @Didier Villevalois, we are in active development of a FIR plugin here https://github.com/arrow-kt/arrow-inject
I think the kind of extension you are looking for is
FirDeclarationGenerationExtension
👍 1
Feel free to grab any code or asks us any questions. To my understanding there is just a few of us venturing into FIR at the moment and we are happy to share whatever we have learned so far.
❤️ 2
d
Thanks @raulraja and @mcpiroman! Exactly the kind of information I needed to go forward. 🙂
👍 1
d
Why do you want to do it on frontend? For me it looks like pure backend plugin
d
Thanks @dmitriy.novozhilov. So maybe I am missing something completely here. I would want to generate code that works on all backends, so I thought generating FIR nodes would be easier. Also, I can't see any backpointers from the IR tree to the FIR tree?
(Sorry if my questions are dumb, I just recently delved into the compiler's code and I'm far from understanding some of the basic stuff...)
d
IrGenerationExtension works right after psi2ir/fir2ir and before backend So plugins with this extension works for all ir backend
d
I see, thanks a lot. Indeed that should do it. Now, is there a way to recover the original FIR nodes (before lowerings of for loops and if statements) from the IR nodes?
d
No, there isn't Why do you need them?
r
I’m doing something similar, not for FIR expressions but the declarations can be looked up in the backend with an Id Signature. Creates signature from FiR Declaration: https://github.com/arrow-kt/arrow-inject/blob/7fbf33fe968408d173b87874fb4b1541449f[…]/kotlin/arrow/inject/compiler/plugin/fir/FirProofIdSignature.kt Uses signature to lookup IrDeclaration https://github.com/arrow-kt/arrow-inject/blob/7fbf33fe968408d173b87874fb4b1541449f[…]tlin/arrow/inject/compiler/plugin/ir/ProofsIrAbstractCodegen.kt
@Didier Villevalois do you have a small example of the code transformation you want to happen?
d
@dmitriy.novozhilov, @raulraja, first, suppose I have a library that defines some custom Kotlin AST classes that mirrors the official Kotlin AST. In theses AST classes, I have a
KtExpression
node. In this library, is also defined a top-level function:
Copy code
fun <T> quote(t: T): KtExpression = TODO("This should have been rewritten by our compiler plugin!")
Say i would have some user code like this:
Copy code
import mylib.*

val someExpression = quote(1 + 1);
This would be rewritten by:
Copy code
import mylib.*

val someExpression = KtBinaryExpression(
  KtIntegerLiteralExpression(1),
  BinaryOperator.PLUS,
  KtIntegerLiteralExpression(1),
);
Please, forgive me, the AST classes are completely fictitious for now. I hope my intent is more clear.
d
And what user will do with this KtExpressions? What's the main purpose of your library? I'm asking, because maybe there is some other approach will better suite to you
d
My goal is to generate code from that.
d
So in snippet above you want to generate code for 1+1?
d
No, sorry, my goal is to use those reified ASTs to generate code derived from them. I would be using pattern matching and pattern substitution, similarly to what I did in JLaTo (https://github.com/ptitjes/jlato, https://jlato.readthedocs.io/en/latest/usage/getting-started.html#abstract-syntax-tree-manipulation). The interest for me is to have reified ASTs and from them, derive generated code outside the compiler (both Kotlin code and in some other languages).
I don't think it is a crazy idea, is it?
@dmitriy.novozhilov Obviously, the
1+1
example was just to give a tiny example. I hope you understood what I meant. Is this more clear?
d
I checked abilities of jlato, and can give comments on each one from the list:
Parsing of Java source files up to Java 1.8 version (that runs with Java 1.6+)
You can just depend on parser from
kotlin-compiler-embeddable
and call it programatically
An immutable abstract syntax tree with fluent mutators
PSI and LighterAST are immutable by default in compiler. AFAIK there are some mutation API for PSI in Arrow-meta
Lexical preservation of whitespaces and comments
PSI supports it by default
Formatting of new (and already formatted) abstract syntax trees with formatting settings
PSI and IDEA supports it
[Experimental] Matching/Filtering/Searching of abstract syntax trees with patterns
Check Arrow-meta
[Experimental] Quasi-quotes of Java snippets to ease the building of new abstract syntax trees
Same
Semantic analysis of abstract syntax trees
If you want to just observe results of compilation at some stage, then there are some different APIs for that •
AnalysisHandlerExtension
for K1 frontend •
IrGenerationExtension
for IR backends • KSP (Kotlin Symbol Processing) for frontend-independent view • For K2 (FIR) frontend there is no such API yet, but we are considering on adding it
A add-on mechanism to enable syntactic and semantic extensions
There are already some extensions in Kotlin compiler, and I'm not sure about some other extension points. You can check one of threads above, where I gave links to documentation of existing FIR extensions. K1 and IR extensions are well described in some community articles
Coming back to your original example with `val someExpression = quote(1 + 1)`: If it's ok to you that
someExpression
will have
KtExpression
type on frontend, then you can easily implement it on backed: just call parser for argument, build PSI for it, and create constructors call basing of PSI you get. If you want to change type of
someExpression
based on results of parsing of specific args, then it can not be reached by existing FIR API, because it flaws its design principles