package erlang

  1. Overview
  2. Docs
Libraries to manipulate Erlang sources







erlang is a a set of libraries designed to facilitate manipulating Standard Erlang and Core Erlang sources.

It provides a lexer/parser, a concrete AST, and a printer for Standard Erlang in its current version.

Published: 02 Nov 2020


:candy: Caramel

What is Caramel?

Caramel is an experimental project, featuring primarily an Erlang backend to the OCaml compiler, that brings one of the most mature and expressive type-systems in the world to the BEAM.

In short, it lets you write some OCaml:

(* *)
let inc x = x + 1

and it will compile it to Erlang.

% math.erl
inc(X) -> erlang:'+'(X, 1).

Read more about the current and future goals in the roadmap.

Getting started

You can download the latest pre-release from the releases page. After unpacking it you should be able to add it to your PATH env and start playing around with the caramelc binary.

Like this:

# in this example I'm running linux with glibc
$ wget
$ tar xzf caramel-*
$ export PATH=$(pwd)/caramel/bin

Now we can do a quick test:

$ echo 'let hello () = "world"' >
$ caramelc compile
Compiling hello_world.erl       OK
$ erl
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:64:64] [ds:64:64:10] [async-threads:1] [hipe]

Eshell V11.0.3  (abort with ^G)
1> c(hello_world).
2> hello_world:hello().

To make use of the entire standard library you'll have to run erlc to compile it:

# after unzipping
$ erlc ./caramel/lib/caramel/stdlib/beam/*.erl
$ erl -pa ./caramel/lib/stdlib/beam
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:64:64] [ds:64:64:10] [async-threads:1] [hipe]

Eshell V11.0.3  (abort with ^G)
1> caramel_runtime:binary_concat(<<"hello, ">>, <<"world!">>).
<<"hello, world!">>


You can find several examples in ./examples, and in ./tests/compiler.

In the examples, you can run caramelc compile *.ml to get them all built in the right order.

Here's an OCaml module and the compiled Erlang module:

type msg = [ `Reset | `Add of int | `Hello of string ]

type state = string * int

let handle_message : state -> msg option -> state =
 fun state msg ->
  let x, y = state in
  match msg with
  | Some `Reset -> ("", 0)
  | Some (`Add z) -> (x, z)
  | Some (`Hello n) -> (n, y)
  | None -> state

let rec loop ~recv state =
  Io.format "current_state: ~p\n" [ state ];
  let msg = recv ~timeout:(Process.Bounded 5000) in
  let state2 = handle_message state msg in
  loop ~recv state2

let start x = Process.make (fun _self recv -> loop ~recv x)

let do_work () =
  let pid = start ("hi", 0) in
  Erlang.send pid (`Hello "joe")
% Source code generated with Caramel.


-type msg() :: reset
             | {add, integer()}
             | {hello, binary()}

-type state() :: {binary(), integer()}.

-spec handle_message(state(), option:t(msg())) -> state().
handle_message(State, Msg) ->
  {X, Y} = State,
  case Msg of
    {some, reset} -> {<<"">>, 0};
    {some, {add, Z}} -> {X, Z};
    {some, {hello, N}} -> {N, Y};
    none -> State

-spec loop(fun((process:after_time()) -> option:t(msg())), state()) -> ok.
loop(Recv, State) ->
  io:format(<<"current_state: ~p\n">>, [State | []]),
  Msg = Recv({bounded, 5000}),
  State2 = handle_message(State, Msg),
  loop(Recv, State2).

-spec start(state()) -> erlang:pid(msg()).
start(X) -> process:make(fun
  (_self, Recv) -> loop(Recv, X)

-spec do_work() -> ok.
do_work() ->
  Pid = start({<<"hi">>, 0}),
  erlang:send(Pid, {hello, <<"joe">>}).

Running on the Erlang shell we get this output:

examples/processes λ erl
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:64:64] [ds:64:64:10] [async-threads:1] [hipe]

Eshell V11.0.3  (abort with ^G)
1> c(holder_annotated).
2> holder_annotated:
do_work/0         handle_message/2  loop/2            module_info/0
module_info/1     start/1
2> holder_annotated:do_work().
current_state: {<<"hi">>,0}
current_state: {<<"joe">>,0}
current_state: {<<"joe">>,0}
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution

Dev Dependencies (1)

  1. odoc with-doc

Used by