Erlscripten (sic not Emscripten!) is a source to source transpiler capable of converting most Erlang codebases into semantically equivalent PureScript projects. PureScript is a strongly and statically typed functional language heavily inspired by Haskell which compiles down to JavaScript. Taking PureScript as an intermediary step, Erlscripten allows you to take your existing Erlang application and easily ship it out to JavaScript users — your Erlang code can now run safely in the browser - enabling code sharing between an Erlang backend and the frontend. It is highly interoperable with JavaScript - JavaScript can easily call the transpiled code and then make use of the results — you can easily map Erlang constructs and types to readily available JS constructs.
See it in action!
The Erlscripten project consists of several repositories:
- erlscripten – (recursive link) The main brain of the transpiler. Contains algorithms responsible for code translation, parse transform functionality and simple rebar project support.
- erlps-core – Implementation of the ERTS in PureScript and JavaScript. Contains main definitions of Erlang datatypes in PureScript, builtin functions and Erlang process emulator. Provides utilities for testing transpiled projects.
- erlps-stdlib – A PureScript project that consists of transpiled standard library of Erlang. Most of it is generated by Erlscripten itself, but some parts (especially NIFs) are handcrafted in JavaScript.
Here is a demo of Erlang standard library transpilation process (a.k.a. compatibility benchmark):
As you can see, a vast majority of the modules are transpiled successfully. Aside from casual QuickCheck tests we re-use the existing tests from Erlang stdlib and run them on the PureScript side. The problematic libraries that cause Erlscripten to struggle usually rely on not-yet-implemented builtins, NIFs and more advanced features of Erlang Run-Time System.
As a practical example you may want to check out the transpiled compiler of the Sophia smart contract language. Not only the project serves as an entirely working utility, but also runs a decent amount of transpiled and handwritten tests.
The examples are presented in the examples directory. Sample code snippet:
-module(factorial).
-export([factorial/1]).
factorial(N) ->
factorial(N, 1).
factorial(0, Acc) ->
Acc;
factorial(N, Acc) ->
factorial(N - 1, Acc * N).
Transpiles to:
erlps__factorial__1 :: ErlangFun
erlps__factorial__1 [n_0] =
let arg_2 = toErl 1
in erlps__factorial__2 [n_0, arg_2]
erlps__factorial__1 [arg_3] = EXC.function_clause unit
erlps__factorial__1 args =
EXC.badarity (ErlangFun 1 erlps__factorial__1) args
erlps__factorial__2 :: ErlangFun
erlps__factorial__2 [(ErlangInt num_0), acc_1]
| (ErlangInt num_0) == (toErl 0) =
acc_1
erlps__factorial__2 [n_0, acc_1] =
let rop_4 = toErl 1
in let arg_2 = BIF.erlang__op_minus [n_0, rop_4]
in let arg_5 = BIF.erlang__op_mult [acc_1, n_0]
in erlps__factorial__2 [arg_2, arg_5]
erlps__factorial__2 [arg_8, arg_9] = EXC.function_clause unit
erlps__factorial__2 args =
EXC.badarity (ErlangFun 2 erlps__factorial__2) args
Note: The generated code doesn't target to be readable, but rather to preserve the semantics of Erlang. This includes, but isn't limited to exceptions behavior, function arguments evaluation order and side effects. Some efforts, however, have been made to ease the process of debugging and reasoning about the produced PureScript.
- Majority of erlang expression
- Arbitrary arity functions
- Pattern matching
- Records (via tuples)
- Binaries
- Lambdas
- Tail recursion
- Exceptions
- Process dictionaries
- Code server, module loading
- Imports and exports
- Compatibility utilities
- Common errors (
function_clause
,case_clause
,badarity
, etc.)
- Erlang's standard library (most essential modules;
lists
,maps
,string
, etc.) - Erlang builtins (growing and growing!)
- Rebar project transpilation
- ETS (missing only
duplicate_bag
implementation)
- Bitstrings
- Leaking variable scopes
- Basic erlang process emulation
- NIFs
- Hot code reloading
- Distributed erlang
Support us at aeternity: ak_2WESwy76bMxSxP62XDE937Dmyu8wHyV4uF8KbobMNzQxh5a1sx