How to transform Rust code to other language (reverse DSL)

Hi all! I has been thinking in try a project which I don't know where to start, I'm checking if doing it and there is some reasons I would like to give it a try at work.

The idea is write rust code, be able to use r-a and everything, and then that code transform it to other language, for practical things I'll say/choose R for now, but would be nice keep in mind to do it with any language.

Why?

  • Not all libs in R are or will be available in R
  • Some times, due to company things, we need a final language like R
  • Languages like R are not strong-typed, do this would really simplify and makes production code a lot nice!
  • Be able to know what a variable is released, means we can find a way to when rust release a variable also remove it in this other language, reducing a lot the memory usage.
  • There will be no issues with naming things, is usual in this langs just miss one word and you can't find the error unless there is a test
  • Particularly R has a lot of weird behaviors! we can skip them
  • Academic, be able to have some features like R, where ppl is more used to, and what to expect could do more easy introduce to Rust
  • Clarity, just picking a example, all R functions makes copy of all elements all the time, is good to know this, would force us to write .clone() and know what we are doing

Well, this is some of the cases... going to the issue, any has any idea how to do this?

I tried checked on this, I would like to avoid this:

r_let!(let a = 10);

I thought in use attribute macros, this allow use to check all lines, and do the conversions for each instruction, the issue I found in this was that how to write the final result to a file, seems the attribute macros do not have a guarantee order or execution, still if with cargo clean we can force it, still is fine, still no idea if this is the right thing.

I was thinking to implement something like a trait ToR which would transform each expression to R, some parts must be done out (like in a macro), and this would help to organize the code better, because I would need to have the R libs, in this case how are the signatures of the types and functions, have modules with each lib and how they are transformed is nice.

There is also the alternative to write a app that reads rust code and transform to R, but this could also be complex, I would not even know how to call ToR...

Ideas?

My ideal is be able to write something like (trivial example):

#[to_r, file = "foo.R"]
fn foo(a: f64, b: f64) -> r::sf::Point {
  let a = a*2;
  let b = b*a;
  r::sf::Point::new_xy(a, b)
}

which could lead to

foo <- function(a, b) {
  a <- a*2
  b <- b*a
  ret <- sf::st_point(c(a, b))
  a <- NULL
  b <- NULL
  ret
}

Thx!

What you want is effectively a compiler (or sometimes called "transpiler").
You want to parse and translate one language (Rust) to another. That not only requires converting the syntax (let a = a * 2 to a <- a*2), but also the semantics (what to do on drops, how to translate things more complicated than inline math, etc.)

You can do all that from scratch, though doing that on Rust is a huge undertaking.
You can also re-use parts of rustc. Here's a talk of someone doing that with a Rust to C translation: Corrosive C - Compiling Rust to C to target new platforms - Michał “FractalFir” Kostrubiec

3 Likes

Note however, that without control over one of the sides of the language you're forced to make a trade between fidelity (how precisely you reproduce the original behavior) and clarity (how much the output code can be read and modified). Without explicit effort, languages are just too different to swap out even basic operations for each other and expect it to work the same! Trivially, Rust has a large zoo of integer types, R (as I understand it) does not, so to reproduce even "x + y" in R accurately, you need to generate code like "u32_add(x, y)", or something equivalently noisy. That's the easy case!

It sounds like you might be after something like https://vapour.run/ - which creates a new language that is just "R with types" so they don't have this semantic mismatch and can simply transform it by removing the annotations.

Excluding situations like the browser – where producing JavaScript was a hard requirement before WASM, or occasionally where it's needed for performance due to the potentially high FFI cost of WASM – you generally want to try to share code between languages after compilation, either via FFI or perhaps IPC, this means you get exactly the right behavior and readable and modifiable code on both sides.

For example, (based on a quick search) you could make some Rust code available to your R code via FFI via CallExternal function - RDocumentation or rdyncall: Improved Foreign Function Interface (FFI) and Dynamic... in rdyncall: Improved Foreign Function Interface (FFI) and Dynamic Bindings to C Libraries (e.g. OpenGL)

In the end, though, if your limitation is that your work is requiring that you must write R code, then it doesn't matter what you do, you can't write Rust code or anything else, it's explicitly requiring that your source code is R. Bad things will happen if you try to skirt around that!

5 Likes

Hi! thx for all the answers!

@jer the talk is nice! is very similar to what I'm looking, I'm not able to find a simpler example than C, do you know any one?

@simonbuchan I get the langs are very different, I would need to do a lot of tricks to match them, and is not like we can match them entirely so it could even need some custom things, I would like to explore the option.

First time to know vapour! seems nice! I'm already proposing it where I'm working for some tests.
In this particular case, I think vapour do not match very well, because I want to take advantage of Rust features mainly.

I have used and have projects with extendr, a library that allow us to expose Rust code into R, seems different from what I'm looking, after some thinking, maybe a way to expose a Rust function that internally calls a R function like line by line, or expose some R things inside Rust seems interesting, is not the main question but can also help with one my main objectives.

I have the advantage of have some flexibility about "write R code", in some places they can be so restrictive that we can't even use external tools.
In my case is mostly of just have R code, and one of my reasons for this is make R ppl be able to use Rust with things that are more familiar, R have some nice functionalities that are only there, so think of this more like a step closer to Rust.
Other of my main reasons is just be able to make more clear R code.

Thx!