Context
I want to write a simple script to consume some s-expressions output by dune
and do something with them.
Input looks like this:
((executables
((names (main))
(requires
(2e58431e757317d4157ed69cdbce2cb0 c480a7c584d174c22d86dbdb79515d7d))
(modules
(((name Main)
(impl (_build/default/src/bin/main.ml))
(intf ())
(cmt (_build/default/src/bin/.main.eobjs/byte/dune__exe__Main.cmt))
(cmti ())
(module_deps ((for_intf ()) (for_impl ()))))))
(include_dirs (_build/default/src/bin/.main.eobjs/byte))))
...)
And I’d like to get the “name” and list of modules and their dependencies for each “executables” of the toplevel list.
Question
Are there opam packages that offer small combinator libraries to write such code? I looked at the Sexplib documentation and I’m not under the impression that there is something there. (I think that it’s a rather basic question and it’s weird that the documentation does not answer it, but oh well.)
What I found
Within Sexplib, there is:
- a Conv module that provides some
foo_of_sexp
conversions that could conceivably be used for this, but are more meant for one-to-one mapping to OCaml types. (Note: here I consider that the s-expression I get is random, and may not fit an OCaml type.) - a Grammar module that looks like a much-more-engineered version of what I would naively look for, and probably overkill for what I’m looking for. (Also, an example or two in the documentation would help, but oh well.)
- a Path module that looks like it may contain nice ways to do selector-based data lookup in s-expressions but is in fact aimed at something else (substitutions)
Home-grown example
I spent an hour writing something specific yesterday, writing combinators at the same time, and it looks like this. I’m not saying this is good (I’m sure it will look different next time I write it again), but it gives a rough idea of the sort of combinators I would have expected to find a library for.
let read_entries entries =
let entries = list entries in
let* (name, entry) =
begin
let+ exec = select_all ["executables"] entries in
(select_single ["names"] exec |> list_of atom |> single,
exec)
end @ begin
let+ lib = select_all ["library"] entries in
(select_single ["name"] item |> atom,
lib)
end
in
let+ module_ = select_single ["modules"] item |> list_of list in
let name = select_single ["name"] module_ |> atom in
let impl = select_single ["impl"] module_ |> list |> single |> atom in
let deps =
let deps = select_single ["module_deps"] module_ |> list in
(select_single ["for_intf"] deps |> list_of atom)
@
(select_single ["for_impl"] deps |> list_of atom)
in
(item_name, name, impl, deps)
JSON
This looks like a problem common to other data forms, for example Json data. Curiously enough, I don’t remember looking for such a library to write with Json data in the past: I guess the fact that it is just slightly more structured (with explicit representation of lists and dictionaries) makes it easy to just use List.assoc
directly.