What will be required to transpile OCaml to Lua?

I dream with a world where I can use ocaml/reasonml for everything, even if it is not a good idea.
Given that is already possible to transpile to Javascript, the next big player in languages that are everywhere is Lua.
Thankfully Lua and Javascript are also very similar, which should allow certain synergy between the existing Javascript transpilers and a potential Lua one.
What is the required machinery for such a project? I guess (from reading the bucklescript docs) that a compiler backed is what is needed, but I wanted to know if there is some other alternative. A ppx can do such a thing?

Obviously this is a huge project, and just because I’m asking doesn’t meant I think I am able to accomplish it, but I am very interested in knowing how much of a challenge it is.

2 Likes

Obviously I forgot to mention that I will have to write bindings for the target Lua version builtin functions (in my case luajit) and for any library that I want to use (in my case, vim stdlib), but that is obvious and the easy part.

convert ocaml to js with jsoo, and then use some tools to compile js to lua, sounds like a hassle, but it should work

I wonder what can be the use case of such a transpiler.

I think the base principles of js_of_ocaml would be relevant, they are described in this 2014 paper which still seems to be a mostly accurate reference.

Since Lua is a bytecode-based language, it would feel more principled to me to compile OCaml to Lua bytecode, though.

1 Like

To use Ocaml instead of Lua whenever possible :smile:
For example:

  • my vim configuration
  • vim plugins
  • game plugins/mods
  • Embedded systems that have a Lua interpreter
  • When there is a nice Lua library but no Ocaml one

Thanks for the link to the papers of js_of_ocaml, I think their philosophy will be easier to apply than trying to repurpose reason or rescript compilers for this task.

Not sure how nice that will play with places where you want to interact with third party dependecies, or builtin methods of your scope (ej, a game engine).

I thought about using rescript or reason to convert it to typescript, and then there is a good typescript to lua compiler. However, those are too many layers of indirection, and I can not be sure of what the end result will be. I may be wrong. I think that, since this is simpler than any of the alternatives it’s worth taking a look to see how it goes.

Lua libraries and Lua runtimes with built-in functions are built around Lua’s C FFI. To be compatible with such tools you would need to provide the same API (mostly manipulation of stacks containing Lua values and some global Lua state). This compatibility requirement is the reason why an alternative Lua backend like Luau cannot be used as a drop-in replacement for Lua (see this discussion).

One alternative solution for you might be to use C code as the bridge between OCaml and Lua, since both have a well-behaved FFI.

Lua’s bytecode is unspecified, might change between releases. PUC Lua and LuaJIT have different bytecode too.

That’s true.

(OCaml bytecode is not specified either, and that never stopped js_of_ocaml from taking bytecode as input; but I’ll admit that OCaml bytecode is very stable and exists in only one version.)

For the Neovim-specific use case, you may want to take a look at vcaml, which lets you write OCaml programs that interact with Neovim over msgpack RPC. Do note though that while the library as-is should provide you with the functionality you need, it is under active development so the API may change (improve) in significant ways between releases.

1 Like

That is an awesome resource that I was not aware of.
Does it allow to configure vim configurations and keybindings? I wonder how type safe it is compared to raw Lua

I don’t want to sidetrack this thread about OCaml to Lua transpilation, but I’m happy to discuss VCaml further and answer any questions about it offline - you can find me on either the OCaml Discord or the Neovim IRC.

That will be awesome. What is your username on discord?

Doesn’t necessarily help much, but a while ago I wrote a proof-of-concept ML-style language (using OCaml, of course) that transpiled to Lua - GitHub - merle-lang/luml: Luml is a type-inferred ML-style language that cross-compiles to Lua (I was mostly thinking about targeting game engines… I did enough to implement Tetris and then gave up on it).

The module that emits Lua source code was pretty simple: luml/compile.ml at master · merle-lang/luml · GitHub - I did think about trying to target bytecode but it seemed tricky due to different Lua versions, I think.

2 Likes

That is insanely cool! How is that not listed in the document of languages that compile to Lua? Even if it is abandoned, that list is full of those. You even have tests.
Is there any cheatsheet were all the feature languages are showcased?
Why you stopped developing it? Lack of interest?

A few years ago I gave this task as an exercise to a student in the university.

The list of supported features is very sparse and a project is abandoned.

That looks basically what I wanted to do, but already done.
Do you mind explaining why the development have stopped? Was it not worth it? Did it reach maturity?
I see there are some updates to the readme, but the structure doesn’t seem obvious to me. For example, there are test folders that look like transpilation examples, but there are not ml files for all the lua files. And there seems to be some STDL attempt, but seems incomplete… basically I’m not sure anyone can understand it without some context

Thanks for the kind words. Mostly I was thinking of targeting (Core) Erlang, as I dream of an ML-style language on the BEAM for easy concurrency. Then came along Gleam, which pretty much does that, although not exactly to my taste. So I flitted around a bit and lost interest. I even had a (very partial) LLVM backend at one point. I did implement some nice features, such as row-polymorphism on records (Ă  la Elm) and it had a built in syntax for nested record updates which basically gave you pseudo-lenses for free at the syntax level. Other than that it was pretty much like a mix of OCaml, SML and Elm.

I do feel like reviving it (although I have a very senior role these days and don’t get to write code so much) because I love the idea of an ML-style language that’s useful for scripting.

I believe Haxe can target Lua? It’s also implemented in OCaml and although the syntax is quite different, it’s very ML in its featureset.

Yes, I took a look at Haxe, and really liked it. It seems like an interesting investment knowing how many things it can target. However, I found some stuff I didn’t liked, like strict null checking being opt-in, which means that a lot of libraries and stuff will not care about safety.
Also the syntax put me off a bit with all that OO gibberish.
For example:

class Main {
  static public function eval(e:Expr):Int {
    return switch e {
      case CstI(x): x;
      case Prim("+", e1, e2): eval(e1) + eval(e2) ;
      case Prim("-", e1, e2): eval(e1) - eval(e2) ;
      case Prim("*", e1, e2): eval(e1) * eval(e2) ;
      case Prim(_) : throw "Unknown primitive";
    }
  }

Why the return, why call it switch? why all those braces :smile: I guess you can get used to, but if the compiler is not having my back enough (maybe it does) it doesn’t add enough value

Well, I wanted this to be done. A a bachelor candidate student was not very motivated, so he wanted to do something to get a grade above F.

Basic support of algebraic data types should be there. Some files without corresponding .ml are probably for runtime support of currying and things like that.
You shouldn’t expect to have a good support of lists/array, stdio and formatted string.
Basic functions, recursion and control structures should work. Algebraic data types are encoded into dictionaries and should work.

In general, it would be great to have a proper integration of upstream compilers with typed-tree to source transpilation. Maybe in a form of (abandoned) compiler plugin.