Add (mli-to-ml ...) as a hack for mli only modules

This commit is contained in:
Jérémie Dimino 2017-05-28 04:25:02 +01:00
parent c6cc8204bf
commit f1ebc0ed7d
4 changed files with 54 additions and 1 deletions

View File

@ -336,7 +336,37 @@ Extra flags can be passed to menhir using the ``flags`` flag:
(menhir
((flags (<option1> <option2> ...))
(modules (<parser1> <parser2> ...))))
ml_of_mli, re_of_rei
--------------------
``(ml_of_mli (<names>))`` produces rules that generate ``.ml`` files
from ``.mli`` files, using a hack based on recursive
modules. ``re_of_rei`` is the equivalent fot reason files.
More precisely, given a stanza ``(ml_of_mli (foo))`` the following
``.ml`` file is generated:
.. code:: ocaml
[@@@warning "-a"]
module rec Foo : sig
(* contents of foo.mli *)
end = Foo
If you have a ``.mli`` file containing only type declarations, this
allows you to automatically produce the corresponding
implementation.
Note that if the ``.mli`` file does contain a value declaration, the
compilation of the generated ``.ml`` file will fail with an error
about recursive module. In particular declaring an exception or
extension constructor implicitely declares a value. The error won't be
precide because the compiler doesn't support checking that a mli file
doesn't contain value declaration. See ``this ticket
<https://github.com/janestreet/jbuilder/issues/9>``__ for a discussion
about these issues.
alias
-----

View File

@ -737,6 +737,22 @@ module Do = struct
{ loc = Sexp.Ast.loc sexp
; action = Action.Unexpanded.t sexp
}
let ml_of_mli names =
List.map names ~f:(fun (loc, name) ->
let strf fmt = Printf.ksprintf (String_with_vars.of_string ~loc) fmt in
let m = String.capitalize_ascii name in
{ loc
; action =
Redirect
(Stdout,
strf "%s.ml" name,
Progn
[ Echo (strf "[@@@warning \"-a\"]\nmodule rec %s : sig\n" m)
; Cat (strf "%s.mli" name)
; Echo (strf "\nend = %s\ninclude %s\n" m m)
])
})
end
module Menhir = struct
@ -921,6 +937,8 @@ module Stanza = struct
(fun pat vals sexps ->
let sexps = Foreach.expand pat vals sexps in
List.concat_map sexps ~f:(v1 pkgs))
; cstr "ml_of_mli" (list (located string) @> nil)
(fun x -> List.map (Do.ml_of_mli x) ~f:(fun x -> Do x))
(* Just for validation and error messages *)
; cstr "jbuild_version" (Jbuild_version.t @> nil) (fun _ -> [])
]

View File

@ -190,6 +190,9 @@ module Of_sexp = struct
type 'a t = ast -> 'a
let located f sexp =
(Ast.loc sexp, f sexp)
let of_sexp_error sexp str = raise (Loc.Error (Ast.loc sexp, str))
let of_sexp_errorf sexp fmt = ksprintf (of_sexp_error sexp) fmt

View File

@ -66,6 +66,8 @@ module Of_sexp : sig
val of_sexp_error : Ast.t -> string -> _
val of_sexp_errorf : Ast.t -> ('a, unit, string, 'b) format4 -> 'a
val located : 'a t -> (Loc.t * 'a) t
(* Record parsing monad *)
type 'a record_parser
val return : 'a -> 'a record_parser