So something I’ve been working on in my random little bit of free since last year was an ocaml to elixir transpiler. However, it’s dead. It works via a compiler plugin and for some reason OCaml is removing compiler plugins in the next major version update, so the current code-base is basically dead. It will need to be rewritten as a standalone compiler using OCaml’s compiler-lib
, so that will take some time to figure out and then actually ‘do’.
Has anyone started a standalone compiler for an ocaml to elixir converter so I don’t duplicate effort or anything?
On my now-dead version it worked pretty well and handled a lot of constructs. I never got around to doing auto-uncurrying but it’s not hard to do (OCaml makes it really easy, probably would take an hour to do and test), but overall I think the code was pretty readable that it output.
Given this OCaml file I typed up right quick:
╰─➤ cat test/test_file.ml
let _ = 42
let a = 42
let b c d =
let `Blah (e, f) = `Blah (c + d, 1) in
let `Blorp g = `Blorp (e + f) in
g + e
let c 21 = 42
let d a b = a +. b +. 6.28
let e b = if b then 1 else 2
let log b s = if b then print_endline s
let test () =
let 42 = a in
let 7 = b 1 2 in
let 42 = c 21 in
let 9.28 = d 1.0 2.0 in
let 1 = e true in
let () = log true "this is logged" in
()
Then compiling it with the elixir_of_ocaml
plugin:
╰─➤ time ocamlopt -plugin ../elixir_of_ocaml.native.cmxs test_file.ml
File "test_file.ml", line 10, characters 6-13:
10 | let c 21 = 42
^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
0
File "test_file.ml", line 19, characters 6-8:
19 | let 42 = a in
^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
0
File "test_file.ml", line 20, characters 6-7:
20 | let 7 = b 1 2 in
^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
0
File "test_file.ml", line 21, characters 6-8:
21 | let 42 = c 21 in
^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
0
File "test_file.ml", line 22, characters 6-10:
22 | let 9.28 = d 1.0 2.0 in
^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
0.
File "test_file.ml", line 23, characters 6-7:
23 | let 1 = e true in
^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
0
defmodule TestFile do
_ = 42
def a, do: 42
def b(c) do
fn(d) ->
{:Blah, {e, f}} = {:Blah, {Kernel.+(c, d), 1}}
{:Blorp, g} = {:Blorp, Kernel.+(e, f)}
Kernel.+(g, e)
end
end
def c(21) do
42
end
def d(a) do
fn(b) ->
Kernel.+(Kernel.+(a, b), 6.28)
end
end
def e(b) do
if b do
1
else
2
end
end
def log(b) do
fn(s) ->
if b do
IO.puts(s)
end
end
end
def test({}) do
42 = a
7 = b(1, 2)
42 = c(21)
9.28 = d(1.0, 2.0)
1 = e(true)
log(true, "this is logged")
{}
end
end
ocamlopt -plugin ../elixir_of_ocaml.native.cmxs test_file.ml 0.01s user 0.00s system 76% cpu 0.016 total
I just have it dump it to stdout
, makes it easy to have a mix task take it in, format it with elixir’s formatter, then dump it out for example. And as you can see with ocaml lexing it, typing it, couple of miner optimization passes, and the to-elixir conversion and all, this file took ~0.016 seconds from a completely cold run. Technically I could get a custom driver a little faster so that will be a nice thing of the rewrite. I really should write that uncurry pass even if this code is dead… >.>