Skip to content

Commit

Permalink
compiler: forbit let rec bindings within function body
Browse files Browse the repository at this point in the history
Close #13
  • Loading branch information
leostera committed Oct 23, 2020
1 parent 2345e78 commit 7595b97
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 34 deletions.
9 changes: 9 additions & 0 deletions src/compiler/ocaml_to_erlang/error.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ let ppf = Format.err_formatter
let file_a_bug =
{| If you think this is a bug, please file an issue here: https://github.com/AbstractMachinesLab/caramel/issues/new |}

let unsupported_let_rec_inside_of_function_body () =
Format.fprintf ppf
{|We have found a let rec binding within a function.

This is currently not supported.
\n
|};
exit 1

let unsupported_let_shadowing name =
Format.fprintf ppf
{|We have found that the variable name %s is being shadowed.
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/ocaml_to_erlang/fun.ml
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ and mk_expression exp ~var_names ~modules ~functions ~module_name =
in
let branches = if_true :: if_false in
Erlang.Ast.Expr_case (expr, branches)
| Texp_let (_, vbs, expr) ->
| Texp_let (Recursive, _, _) ->
Error.unsupported_let_rec_inside_of_function_body ()
| Texp_let (Nonrecursive, vbs, expr) ->
(* NOTE: consider flattening let-ins ?
let rec flatten e acc =
match e with
Expand Down
25 changes: 0 additions & 25 deletions tests/compiler/expressions.t/let_bindings.ml
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,3 @@ let let_nested f g h =
in
f a

(* FIXME: Erlang does not support let rec bindings, and we're forced to use a
combinator instead.
Right now it believes that the name is supposed to be a module level
function, which compiles fine but crashes at runtime.
So this:
let rec f x = f (x + 1) in
f 0
could look like:
let_rec() ->
RecF = fun(G) -> fun (X) -> (G(G))(X+1) end end,
F = RecF(RecF),
F(0).
alternatively we coudl wrap this in a support library too
F = caramel:letrec1(fun (F, X) -> F(X + 1) end)
*)
let let_rec () =
let rec f x = f (x + 1) in
f 0
25 changes: 25 additions & 0 deletions tests/compiler/expressions.t/let_rec.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
(* FIXME: Erlang does not support let rec bindings, and we're forced to use a
combinator instead.
Right now it believes that the name is supposed to be a module level
function, which compiles fine but crashes at runtime.
So this:
let rec f x = f (x + 1) in
f 0
could look like:
let_rec() ->
RecF = fun(G) -> fun (X) -> (G(G))(X+1) end end,
F = RecF(RecF),
F(0).
alternatively we coudl wrap this in a support library too
F = caramel:letrec1(fun (F, X) -> F(X + 1) end)
*)
let let_rec () =
let rec f x = f (x + 1) in
f 0
19 changes: 11 additions & 8 deletions tests/compiler/expressions.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
binding_on_match.ml
funref.ml
let_bindings.ml
let_rec.ml
let_shadowing.ml
list.ml
literals.ml
Expand Down Expand Up @@ -175,7 +176,6 @@
-export([let_many/0]).
-export([let_nested/3]).
-export([let_one/0]).
-export([let_rec/0]).

-spec let_one() -> integer().
let_one() ->
Expand Down Expand Up @@ -210,13 +210,6 @@
end(),
F(A).

-spec let_rec() -> any().
let_rec() ->
F = fun
(X) -> f(erlang:'+'(X, 1))
end,
F(0).


$ caramelc compile list.ml
File "list.ml", line 7, characters 9-21:
Expand Down Expand Up @@ -568,6 +561,7 @@
$ cat let_shadowing.erl
cat: let_shadowing.erl: No such file or directory
[1]

$ caramelc compile names_primes.ml
Compiling names_primes.erl OK
$ cat names_primes.erl
Expand All @@ -584,3 +578,12 @@
X_prime_prime.


$ caramelc compile let_rec.ml
We have found a let rec binding within a function.

This is currently not supported.
\n
[1]
$ cat let_rec.erl
cat: let_rec.erl: No such file or directory
[1]

0 comments on commit 7595b97

Please sign in to comment.