Would it be possible to write a compiler plugin th...
# compiler
m
Would it be possible to write a compiler plugin that can convert inline XML to Kotlin? Like JSX and TSX.
Copy code
val umbrella = <svg xmlns="<http://www.w3.org/2000/svg>" viewBox="0 0 40 40"><path d="M21.172,2.4V0H18.828V2.4C8.063,2.933,0,10.857,0,21.172V23.06l1.694-.839a11.586,11.586,0,0,1,4.243-1.049c1.512,0,3.3,1.445,3.86,2l.829.819.826-.819c.561-.556,2.348-2,3.86-2a6.366,6.366,0,0,1,3.516,1.689V36.484a3.516,3.516,0,0,0,7.031,0V34.141H23.516v2.344a1.172,1.172,0,1,1-2.344,0V22.861a6.366,6.366,0,0,1,3.516-1.689c1.512,0,3.3,1.445,3.86,2l.829.819.826-.819c.561-.556,2.426-2,3.938-2a10.963,10.963,0,0,1,4.165,1.049l1.695.84V21.172C40,10.857,31.937,2.933,21.172,2.4Z"/></svg>
That could be converted into
kotlinx-html
or React code.
d
I'm not sure about if this possible with existing tools and APIs (current compiler API, arrow-meta, KSP), but we are keeping in mind that case in design of compiler API for FIR
m
Thank you @dmitriy.novozhilov. Looking forward for some compiler API in the future. For me it would be very helpful for inlining resources, e.g. SVGs.
d
Hm, I just understand that I wrongly understand your example. I thought it's a separate
.xml
file, but it is actually raw xml inside kotlin code. What is your usecase for such feature? If it is kotlin code, why don't write proper code instead of xml?
m
Because I don’t want to spend days and days converting files from SVG to Kotlin and from Kotlin to SVG. Anytime an SVG file changes I would have to manually convert it to Kotlin code. I could write a compiler plugin though that generates
kt
files based on
svg
files located in a Kotlin source directory, true 🤔 Which leads me to another question: Can I create actual Kotlin source files with a compiler plugin that become part of the same build? Similar to what KAPT would do.
e
I think KSP allows you to do that
☝️ 1
It's pretty much like KAPT but faster
Instead of analyzing Kotlin files you'd check for diffs in SVG files
m
I’ll have a look if I can do that reliably with KSP, thanks.
d
You can just write a function that parses specific SVG and produces some object If you want an actual code for that you can use next scheme, shich not involves any tools at all: 1. Let's say that your main code lays in module
a
2. You create module
a.generator
(or something) which contains your
svg
files and code which converts that files to
.kt
files with source code inside
a
module 3. Module
a.generator
contains some
:generate
task which runs this generation 4. You configure your build so
a:build
task depends on
:a.generator:generate
This is very simple solution which works well if your
.svg
files are not changed too much often
We use this scheme in several part of compiler to generate some compiler structures (like classes for FIR tree or tests)
m
@dmitriy.novozhilov thanks. But that requires end-users to create additional modules, right? I already have 6 modules in my Kotlin Web project. That would mean 6 additional modules just to add icons? I’d prefer to have them part of the same source set.
The idea is: 1. drop
.svg
files into your source set 2. add compiler plugin 3. your build automatically contains generated code (just like with KAPT) for these SVG files
Generating actual code is important. It’s super annoying that you can’t inspect, debug, or copy & modify code created for
KSerializer
for example.
d
Actually my scheme works and without separate module, I suggest to create it only because it's good if generator don't depends on sources which it produces You can implement generator once and then just update
build.gradle.kts
for all modules which need such thing
I may agree, that with compiler plugin it may be more easy, but I'm just not sure that it can be easy to write such plugin right now
m
Well the generator only depends on SVG files so it would/could always run before any KT file is even parsed - even if it’s a compiler plugin. Or would that still cause issues? Do I actually need a compiler plugin? I actually only need the code-generating part of the compiler, don’t I?
d
Well the generator only depends on SVG files so it would/could always run before any KT file is even parsed - even if it’s a compiler plugin.
Basically yes, you can implement generator using only stdlib (it's just sometimes useful to have some types available in generator to simplify it's code)
I actually only need the code-generating part of the compiler
What is code generation part? You can just produces some
.kt
sources and give them to compiler, so it make all dirty job
m
@dmitriy.novozhilov let’s take
kotlin-react
as an example. 1. Parse SVG file. 2. Generate kotlin-react code for that SVG file, e.g .
val fooIcon = reactElement { svg { attrs["viewport"] = "…"; etc } }
3. Compiler picks up these files when building. Now it’s basically an SVG -> KT transformation before the actual Kotlin build. I just need a way to create Kotlin code. I could use kotlinpoet but if the Kotlin compiler has a good API for plugins to construct Kotlin code then that would be preferred.
d
Got it. No, compiler itself doesn't have any tools for source code generation (and I'm not sure that compiler API will use source generation, maybe it will be PSI or FIR or IR or something else)
kotlin-poet
is very nice as I know. Also
arrow-meta
provides some tools for source generation. In compiler team we are usually implement new ad-hock solutions, because it may be faster to quickly write something for specific generation problem instead of using
kotlin-poet
which covers all the cases, but requires some time to get into it
m
I see. Thank you for all the info 🙏 Do you happen to know how the J2K converter generates Kotlin code?
d
Do you happen to know how the J2K converter generates Kotlin code?
Not well, I just know that it's a java PSI to kotlin PSI conversion You can ivestigate it's code if you want: https://github.com/JetBrains/kotlin/blob/master/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt
👍 1
m
So in the end it probably simple writes PSI as Kotlin code?
d
Yes, somewhere it is. But I don't know, is it part of kotlin or IDEA, so I can't point to service which do it
m
Alright, thanks for the info. I have a good overview now to dig deeper 🙂
h
For the given use case it would be very straight forward to use gradle and implement a gradle Plugin, thats what i do, very satisfied so far. Then a source set you want to generate your source into and kotlin poet... Build task can depend on the generation task, ide can use gradle for build, so it's automatically done and you don't have invalid references. I think you had this idea already.
2
👍 2
j
the usecase doesn't sound like a whole paradigm shift worthy of a compiler level augment; not when you can get a job done in sed and bash in a few hours.
m
Neither runs easily on Windows. I could also do absolutely everything in Java, JS or PHP and don't need Kotlin at all. That's not a useful argument. And not the point.