Using Kotlin compiler for a Transpiler

#1

I am developing a transpiler for kotlin to java. I know how to generate an AST using the kotlin compiler but for future work I would like to handle kotlin’s type inference.

My concept for the transpiling process looks like this

  1. Generate AST of Kotlin code
  2. Resolve type inference etc.
  3. Map kotlin AST to intermediate model
  4. Transform intermediate model to java code

Given this small example:

var text = "text"

My problem is to resolve the type of text. As far as I know the class org.jetbrains.kotlin.resolve.TypeResolver provides the features I need. Therefore I think I would need a org.jetbrains.kotlin.resolve.lazy.ResolveSession. But my main problem is how to get one or is there already a feature which solves this problem in the kotlin compiler? For the TypeResolver#resolveType function I need a LexicalScope and a BindingTrace but unfortunately I do not know to provide them.
Maybe I need to analyze the ast first, like the KotlinToJVMBytecodeCompiler does. But I don’t know how to use the AnalysisResult and it’s slices.

#2

Unless you need to hack the front-end for some reason, it’s really easier to start from the intermediate representation (IR) generated by the new back-end infrastructure. It contains all the information required in a semantic tree.
You can take a look into, for example, into JS_IR back-end for some inspiration (which is, in fact, a full-blown Kotlin to JS transpiler).

1 Like
#3

First of all thank you!
I’ve looked into the Kotlin2JVM compiler and as far as I’ve understand the code, an AST (a kotlin psi) is generated. Then it’s analyzed and the BindingContext is created. The binding context contains semantic information of the AST, e.g. the Descriptors etc. Based on the AST + BindingContext the JVM code is generated and it’s output is the GenerationState. In a final step the class files are generated from the GenerationState.
You have mentioned the IR. AFAIK the IR is a “combination” of the AST and the BindingContext, am I right? Therefore you only need the IR and the AST and BindingContext are contained in the IR? So I would generate the java files from the IR.
Sadly I might need to hack the “analysis”, because I might not have all dependencies as class files at runtime :confused: The resulting java code will be analyzed by a static code analysis. Therefore the code must not be runable. So I might need to create some stubs for classes and functions and create a generic type, which indicates that the type inference is not solvable.
Do you have any recommendations of (English) books about compiler and transpiler?
Finally thank you for your time and help!

#4

If you have to be able to handle code that may be not compiling (e.g., because some dependencies are not resolved), then you might need to work with PSI and BindingContext. However, the task itself is much more complex. If working with arbitrary non-compiling code is not really a requirement for you, it’s just much easier and safer to set up proper KotlinCoreEnvironment. See how Kotlin2JVM compiler handles CLASSPATH.
NB there’re some tricks inside Kotlin2JVM compiler that allow handling unresolved classes at least somewhat gracefully, but their extent is mostly limited to deserializing Kotlin metadata, so I’d not really rely on that in a transpiler context.

Regarding books on compilers - Dragonbook is undying classics. Then, there’re some a bit more modern books, such as, for example, Engineering: A Compiler by Keith Cooper and Linda Torczon. Working with Kotlin front-end will require some understanding of how type inference works in OO languages; IIRC, Advanced Topics in Types and Programming Languages by Benjamin C. Pierce does describe HM(X).
I don’t know any really good books on transpilers (usually that’s just a compiler book in disguise). There’re some youtube videios by Ira D. Baxter on legacy code transfromations that touch some transpiler-specific issues.

1 Like
#5

I just “muted” all unresolved references errors in the TracingStrategyImpl and it seems to work :slight_smile: Thank you so much!
Does a tool/way exist to visualize an Kotlin AST? I will work (a lot) with them and I want to get a feeling how they are constructed/derived from the Kotlin code.