Skip to content

Commit

Permalink
compiler: forbid function redefinitions within ocaml module
Browse files Browse the repository at this point in the history
Close #12
  • Loading branch information
leostera committed Oct 23, 2020
1 parent 6b1c589 commit fb74cdd
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 58 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 redefining_function ~fn_name ~module_name =
Format.fprintf ppf
{|We have found 2 definitions of the function: %s in module %s, and this is unfortuantely not supported.
\n
|}
(Atom.to_string fn_name)
(Atom.to_string module_name);
exit 1

let referenced_undeclared_function name =
Format.fprintf ppf "Referencing undeclared function: %s" (Atom.to_string name);
Format.fprintf ppf "\n\n%s" file_a_bug;
Expand Down
17 changes: 10 additions & 7 deletions src/compiler/ocaml_to_erlang/fun.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ let is_nested_module ~modules name =
(fun Erlang.Ast.{ module_name = mn; _ } -> Atom.equal mn name)
modules

let find_function_arity_by_name ~functions name =
let find_function_by_name ~functions name =
List.find_opt
(fun Erlang.Ast.{ fd_name; _ } -> Atom.equal fd_name name)
functions
Expand Down Expand Up @@ -190,7 +190,7 @@ and mk_expression exp ~var_names ~modules ~functions ~module_name =
| _ ->
let name = Names.atom_of_longident txt in
let arity =
match find_function_arity_by_name ~functions name with
match find_function_by_name ~functions name with
| Some Erlang.Ast.{ fd_arity; _ } -> fd_arity
| None -> 0
in
Expand Down Expand Up @@ -365,11 +365,14 @@ and mk_expression exp ~var_names ~modules ~functions ~module_name =

let mk_value vb ~modules ~functions ~module_name ~typedtree =
match (vb.vb_pat.pat_desc, vb.vb_expr.exp_desc) with
| Tpat_var (id, _), Texp_function { cases; _ } ->
let id = id |> Names.atom_of_ident in
mk_function ~module_name ~modules ~functions
~spec:(Typespecs.Fun.find_spec ~typedtree id)
~var_names:[] id cases
| Tpat_var (id, _), Texp_function { cases; _ } -> (
let fn_name = id |> Names.atom_of_ident in
match find_function_by_name ~functions fn_name with
| Some _ -> Error.redefining_function ~fn_name ~module_name
| None ->
mk_function ~module_name ~modules ~functions
~spec:(Typespecs.Fun.find_spec ~typedtree fn_name)
~var_names:[] fn_name cases )
| _ -> Error.unsupported_top_level_module_value ()

(** Build the actual functions of an Erlang module
Expand Down
3 changes: 3 additions & 0 deletions tests/compiler/functions.t/redefine.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
let f () = 1

let f () = 1
134 changes: 83 additions & 51 deletions tests/compiler/functions.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,14 @@
partial_functions.ml
qualified_calls.ml
qualified_calls_helper.ml
redefine.ml
sequencing.ml
uncurry.ml
uncurry.mli
$ caramelc compile *.ml *.mli
File "partial_functions.ml", line 1, characters 9-21:
1 | let head (x :: _) = x
^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
File "partial_functions.ml", line 3, characters 9-23:
3 | let tail (_ :: xs) = xs
^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
File "partial_functions.ml", line 5, characters 11-20:
5 | let one_el [ x ] = x
^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(_::_::_|[])
File "partial_functions.ml", line 7, characters 9-26:
7 | let at_2 (_ :: x :: _) = x
^^^^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(_::[]|[])
File "partial_functions.ml", line 9, characters 9-31:
9 | let at_3 (_ :: _ :: x :: _) = x
^^^^^^^^^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(_::_::[]|_::[]|[])
File "multiple_clauses.ml", line 1, characters 22-34:
1 | let iff_using_headers true f _ = f
^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
false
Compiling uncurry.erl OK
Compiling sequencing.erl OK
Compiling qualified_calls_helper__nested.erl OK
Compiling qualified_calls_helper.erl OK
Compiling qualified_calls__nested.erl OK
Compiling qualified_calls.erl OK
Compiling partial_functions.erl OK
Compiling multiple_clauses.erl OK
Compiling labeled_arguments.erl OK
Compiling ignored_arguments.erl OK
Compiling hello_joe.erl OK

$ caramelc compile basic.ml
Compiling basic.erl OK
$ echo $?
0
$ cat *.erl
$ cat basic.erl
% Source code generated with Caramel.
-module(basic).

Expand All @@ -79,6 +32,10 @@
ignore() -> ok.



$ caramelc compile hello_joe.ml
Compiling hello_joe.erl OK
$ cat hello_joe.erl
% Source code generated with Caramel.
-module(hello_joe).

Expand All @@ -90,6 +47,10 @@
io:format(<<"~p">>, [Text | []]).



$ caramelc compile ignored_arguments.ml
Compiling ignored_arguments.erl OK
$ cat ignored_arguments.erl
% Source code generated with Caramel.
-module(ignored_arguments).

Expand All @@ -111,6 +72,10 @@
snd({_, B}) -> B.



$ caramelc compile labeled_arguments.ml
Compiling labeled_arguments.erl OK
$ cat labeled_arguments.erl
% Source code generated with Caramel.
-module(labeled_arguments).

Expand All @@ -127,6 +92,16 @@
erlang:'=:='(S1, S2).



$ caramelc compile multiple_clauses.ml
File "multiple_clauses.ml", line 1, characters 22-34:
1 | let iff_using_headers true f _ = f
^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
false
Compiling multiple_clauses.erl OK
$ cat multiple_clauses.erl
% Source code generated with Caramel.
-module(multiple_clauses).

Expand Down Expand Up @@ -157,6 +132,40 @@
end.



$ caramelc compile partial_functions.ml
File "partial_functions.ml", line 1, characters 9-21:
1 | let head (x :: _) = x
^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
File "partial_functions.ml", line 3, characters 9-23:
3 | let tail (_ :: xs) = xs
^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
File "partial_functions.ml", line 5, characters 11-20:
5 | let one_el [ x ] = x
^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(_::_::_|[])
File "partial_functions.ml", line 7, characters 9-26:
7 | let at_2 (_ :: x :: _) = x
^^^^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(_::[]|[])
File "partial_functions.ml", line 9, characters 9-31:
9 | let at_3 (_ :: _ :: x :: _) = x
^^^^^^^^^^^^^^^^^^^^^^
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(_::_::[]|_::[]|[])
Compiling partial_functions.erl OK
$ cat partial_functions.erl
% Source code generated with Caramel.
-module(partial_functions).

Expand All @@ -182,6 +191,13 @@
at_3([_ | [_ | [X | _]]]) -> X.



$ caramelc compile qualified_calls.ml qualified_calls_helper.ml
Compiling qualified_calls_helper__nested.erl OK
Compiling qualified_calls_helper.erl OK
Compiling qualified_calls__nested.erl OK
Compiling qualified_calls.erl OK
$ cat qualified_calls*.erl
% Source code generated with Caramel.
-module(qualified_calls).

Expand Down Expand Up @@ -242,6 +258,10 @@
f(_x) -> ok.



$ caramelc compile sequencing.ml
Compiling sequencing.erl OK
$ cat sequencing.erl
% Source code generated with Caramel.
-module(sequencing).

Expand All @@ -257,6 +277,10 @@
io:format(<<"*micdrop*">>, []).



$ caramelc compile uncurry.ml uncurry.mli
Compiling uncurry.erl OK
$ cat uncurry.erl
% Source code generated with Caramel.
-module(uncurry).
-export_type([defer/1]).
Expand Down Expand Up @@ -284,3 +308,11 @@
add_really_slow(X, ok, Y, ok) -> erlang:'+'(X, Y).



$ caramelc compile redefine.ml
We have found 2 definitions of the function: f in module redefine, and this is unfortuantely not supported.
\n
[1]
$ cat redefine.erl
cat: redefine.erl: No such file or directory
[1]

0 comments on commit fb74cdd

Please sign in to comment.