Skip to content

Commit 24d9237

Browse files
committed
feat(menhir): allow expanding (modules ..) field
Signed-off-by: Antonio Nuno Monteiro <anmonteiro@gmail.com>
1 parent 6fab87e commit 24d9237

File tree

12 files changed

+229
-140
lines changed

12 files changed

+229
-140
lines changed

doc/changes/added/13105.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
- Allow expansion of special forms like `(:include ..)` and `%{read-lines:..}`
2-
in the `modules` specification for the `ocamllex` and `ocamlyacc` stanzas.
3-
(#13105, #13135, @anmonteiro)
2+
in the `modules` specification for the `ocamllex`, `ocamlyacc` and `menhir`
3+
stanzas. (#13105, #13135, #13157, @anmonteiro)
44

src/dune_rules/dir_contents.ml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ end = struct
160160
Path.Build.set_extension mlg_file ~ext:".ml" |> Path.Build.basename)
161161
| Rocq_stanza.Extraction.T s ->
162162
Memo.return (Rocq_stanza.Extraction.ml_target_fnames s)
163-
| Menhir_stanza.T menhir -> Memo.return (Menhir_stanza.targets menhir)
164163
| Rule_conf.T rule ->
165164
Simple_rules.user_rule sctx rule ~dir ~expander
166165
>>| (function

src/dune_rules/gen_rules.ml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@ let gen_rules_for_stanzas sctx dir_contents cctxs expander ~dune_file ~dir:ctx_d
243243
| false -> Memo.return ()
244244
| true ->
245245
let* ml_sources = Dir_contents.ocaml dir_contents in
246+
let { Ml_sources.Parser_generators.deps = _; targets } =
247+
Ml_sources.Parser_generators.modules ml_sources ~for_:(Menhir m.loc)
248+
in
249+
let menhir_module_names =
250+
Module_trie.to_list_map targets ~f:Module.Source.name
251+
in
246252
let base_path =
247253
match Ml_sources.include_subdirs ml_sources with
248254
| Include Unqualified | No -> []
@@ -254,8 +260,7 @@ let gen_rules_for_stanzas sctx dir_contents cctxs expander ~dune_file ~dir:ctx_d
254260
|> Path.Local.explode
255261
|> List.map ~f:Module_name.of_string
256262
in
257-
Menhir_rules.module_names m
258-
|> Memo.List.find_map ~f:(fun name ->
263+
Memo.List.find_map menhir_module_names ~f:(fun name ->
259264
let path = Nonempty_list.(base_path @ [ name ]) in
260265
Ml_sources.find_origin ml_sources ~libs:(Scope.libs scope) path)
261266
>>| Option.bind ~f:(fun loc -> Loc.Map.find cctxs (Ml_sources.Origin.loc loc))
@@ -266,7 +271,10 @@ let gen_rules_for_stanzas sctx dir_contents cctxs expander ~dune_file ~dir:ctx_d
266271
(* This happens often when passing a [-p ...] option that hides a
267272
library *)
268273
let file_targets =
269-
Menhir_stanza.targets m |> List.map ~f:(Path.Build.relative ctx_dir)
274+
Module_trie.to_list_map targets ~f:(fun m ->
275+
List.map (Module.Source.files m) ~f:(fun m ->
276+
Module.File.path m |> Path.as_in_build_dir_exn))
277+
|> List.concat
270278
in
271279
Super_context.add_rule
272280
sctx

src/dune_rules/menhir/menhir_rules.ml

Lines changed: 66 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,11 @@ module Run (P : PARAMS) = struct
9797
corresponding source file, and [targets m] is the list of targets that
9898
Menhir must build. *)
9999

100-
let source m = Path.relative (Path.build dir) (m ^ ".mly")
101-
102100
let targets m ~cmly =
103101
let base = [ m ^ ".ml"; m ^ ".mli" ] in
104102
List.map ~f:(Path.Build.relative dir) (if cmly then (m ^ ".cmly") :: base else base)
105103
;;
106104

107-
let sources ms = List.map ~f:source ms
108-
109105
(* The following definitions control where the mock [.ml] file and the
110106
inferred [.mli] file are created and how they are named. *)
111107

@@ -187,49 +183,64 @@ module Run (P : PARAMS) = struct
187183
(* The current concrete name for [base] clauses is [merge_into], but I would
188184
like to change it in the future. *)
189185

190-
let stanzas : stanza list =
191-
match stanza.merge_into with
192-
| None ->
193-
List.map
194-
~f:(fun m -> { stanza with modules = [ m ]; merge_into = Some m })
195-
stanza.modules
196-
| Some _ -> [ stanza ]
186+
let stanzas : (stanza * Path.Set.t) list Memo.Lazy.t =
187+
Memo.lazy_ (fun () ->
188+
let open Memo.O in
189+
let+ { Ml_sources.Parser_generators.deps; targets = _ } =
190+
let sctx = Compilation_context.super_context cctx in
191+
Dir_contents.get sctx ~dir
192+
>>= Dir_contents.ocaml
193+
>>| Ml_sources.Parser_generators.modules ~for_:(Menhir stanza.loc)
194+
in
195+
match stanza.merge_into with
196+
| None ->
197+
Path.Set.fold deps ~init:[] ~f:(fun p acc ->
198+
let merge_into = Filename.remove_extension (Path.basename p) in
199+
({ stanza with merge_into = Some merge_into }, Path.Set.singleton p) :: acc)
200+
| Some _ -> [ stanza, deps ])
197201
;;
198202

199203
(* ------------------------------------------------------------------------ *)
200204

201205
(* The [--infer-*] commands should not be passed by the user; we take care of
202206
using these commands appropriately. Fail if they are present. *)
203207

204-
let () =
205-
List.iter stanzas ~f:(fun (stanza : stanza) ->
206-
Ordered_set_lang.Unexpanded.fold_strings stanza.flags ~init:() ~f:(fun _pos sw () ->
207-
match String_with_vars.text_only sw with
208-
| None -> ()
209-
| Some "--explain" ->
210-
if stanza.menhir_syntax >= Dune_lang.Menhir.explain_since
211-
then
212-
User_error.raise
213-
~loc:(String_with_vars.loc sw)
214-
[ Pp.textf
215-
"The Menhir '.conflicts' file is generated by default, so '--explain' \
216-
should not be explicitly added to the list of Menhir flags."
217-
]
218-
| Some text ->
219-
if
220-
List.mem
221-
~equal:String.equal
222-
[ "--depend"
223-
; "--raw-depend"
224-
; "--infer"
225-
; "--infer-write-query"
226-
; "--infer-read-reply"
227-
]
228-
text
229-
then
230-
User_error.raise
231-
~loc:(String_with_vars.loc sw)
232-
[ Pp.textf "The flag %s must not be used in a menhir stanza." text ]))
208+
let check =
209+
Memo.lazy_ (fun () ->
210+
let open Memo.O in
211+
Memo.Lazy.force stanzas
212+
>>| List.iter ~f:(fun ((stanza, _) : stanza * Path.Set.t) ->
213+
Ordered_set_lang.Unexpanded.fold_strings
214+
stanza.flags
215+
~init:()
216+
~f:(fun _pos sw () ->
217+
match String_with_vars.text_only sw with
218+
| None -> ()
219+
| Some "--explain" ->
220+
if stanza.menhir_syntax >= Dune_lang.Menhir.explain_since
221+
then
222+
User_error.raise
223+
~loc:(String_with_vars.loc sw)
224+
[ Pp.textf
225+
"The Menhir '.conflicts' file is generated by default, so \
226+
'--explain' should not be explicitly added to the list of Menhir \
227+
flags."
228+
]
229+
| Some text ->
230+
if
231+
List.mem
232+
~equal:String.equal
233+
[ "--depend"
234+
; "--raw-depend"
235+
; "--infer"
236+
; "--infer-write-query"
237+
; "--infer-read-reply"
238+
]
239+
text
240+
then
241+
User_error.raise
242+
~loc:(String_with_vars.loc sw)
243+
[ Pp.textf "The flag %s must not be used in a menhir stanza." text ])))
233244
;;
234245

235246
(* ------------------------------------------------------------------------ *)
@@ -238,14 +249,15 @@ module Run (P : PARAMS) = struct
238249
is the three-step process where Menhir is invoked twice and OCaml type
239250
inference is performed in between. *)
240251

241-
let process3 base ~cmly (stanza : stanza) : unit Memo.t =
252+
let process3 base ~cmly ((stanza, deps) : stanza * Path.Set.t) : unit Memo.t =
242253
let open Memo.O in
243254
let* expanded_flags = expand_flags stanza.flags in
244255
(* 1. A first invocation of Menhir creates a mock [.ml] file. *)
256+
let source_deps = Path.Set.to_list deps in
245257
let* () =
246258
menhir
247259
[ Command.Args.dyn expanded_flags
248-
; Deps (sources stanza.modules)
260+
; Deps source_deps
249261
; A "--base"
250262
; Path (Path.relative (Path.build dir) base)
251263
; A "--infer-write-query"
@@ -296,7 +308,7 @@ module Run (P : PARAMS) = struct
296308
menhir
297309
[ Command.Args.dyn expanded_flags
298310
; S explain_flags
299-
; Deps (sources stanza.modules)
311+
; Deps source_deps
300312
; A "--base"
301313
; Path (Path.relative (Path.build dir) base)
302314
; A "--infer-read-reply"
@@ -311,7 +323,7 @@ module Run (P : PARAMS) = struct
311323
(* [process3 stanza] converts a Menhir stanza into a set of build rules. This
312324
is a simpler one-step process where Menhir is invoked directly. *)
313325

314-
let process1 base ~cmly (stanza : stanza) : unit Memo.t =
326+
let process1 base ~cmly ((stanza, deps) : stanza * Path.Set.t) : unit Memo.t =
315327
let open Memo.O in
316328
let* expanded_flags = expand_flags stanza.flags
317329
and* explain_flags = explain_flags base stanza
@@ -323,7 +335,7 @@ module Run (P : PARAMS) = struct
323335
menhir
324336
[ Command.Args.dyn expanded_flags
325337
; S explain_flags
326-
; Deps (sources stanza.modules)
338+
; Deps (Path.Set.to_list deps)
327339
; A "--base"
328340
; Path (Path.relative (Path.build dir) base)
329341
; Hidden_targets (targets base ~cmly)
@@ -339,7 +351,7 @@ module Run (P : PARAMS) = struct
339351
(* Because Menhir processes [--only-tokens] before the [--infer-*] commands,
340352
when [--only-tokens] is present, no [--infer-*] command should be used. *)
341353

342-
let process (stanza : stanza) : unit Memo.t =
354+
let process ((stanza, sources) : stanza * Path.Set.t) : unit Memo.t =
343355
let base = Option.value_exn stanza.merge_into in
344356
let ocaml_type_inference_disabled, cmly =
345357
Ordered_set_lang.Unexpanded.fold_strings
@@ -355,24 +367,23 @@ module Run (P : PARAMS) = struct
355367
| Some _ | None -> acc))
356368
in
357369
if ocaml_type_inference_disabled || not stanza.infer
358-
then process1 base stanza ~cmly
359-
else process3 base stanza ~cmly
370+
then process1 base (stanza, sources) ~cmly
371+
else process3 base (stanza, sources) ~cmly
360372
;;
361373

362374
(* ------------------------------------------------------------------------ *)
363-
let gen_rules () = Memo.sequential_iter ~f:process stanzas
375+
let gen_rules () =
376+
let open Memo.O in
377+
let* () = Memo.Lazy.force check
378+
and* stanzas = Memo.Lazy.force stanzas in
379+
Memo.sequential_iter stanzas ~f:process
380+
;;
364381
end
365382

366383
(* -------------------------------------------------------------------------- *)
367384

368385
(* The final glue. *)
369386

370-
let module_names (stanza : Menhir_stanza.t) : Module_name.t list =
371-
List.map (Menhir_stanza.modules stanza) ~f:(fun s ->
372-
(* TODO the loc can improved here *)
373-
Module_name.of_string_allow_invalid (stanza.loc, s))
374-
;;
375-
376387
let gen_rules ~dir ~module_path cctx stanza =
377388
let module R =
378389
Run (struct

src/dune_rules/menhir/menhir_rules.mli

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
open Import
44

5-
(** Return the list of modules that are generated by this stanza. *)
6-
val module_names : Menhir_stanza.t -> Module_name.t list
7-
85
(** Generate the rules for a [(menhir ...)] stanza. *)
96
val gen_rules
107
: dir:Path.Build.t

src/dune_rules/menhir/menhir_stanza.ml

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open Dune_lang.Decoder
77
type t =
88
{ merge_into : string option
99
; flags : Ordered_set_lang.Unexpanded.t
10-
; modules : string list
10+
; modules : Ordered_set_lang.Unexpanded.t
1111
; mode : Rule_mode.t
1212
; loc : Loc.t
1313
; infer : bool
@@ -20,7 +20,10 @@ let decode =
2020
fields
2121
(let+ merge_into = field_o "merge_into" string
2222
and+ flags = Ordered_set_lang.Unexpanded.field "flags"
23-
and+ modules = field "modules" (repeat string)
23+
and+ modules =
24+
Ordered_set_lang.Unexpanded.field
25+
"modules"
26+
~since_expanded:Parser_generators.since_expanded
2427
and+ mode = Rule_mode_decoder.field
2528
and+ infer = field_o_b "infer" ~check:(Dune_lang.Syntax.since syntax (2, 0))
2629
and+ menhir_syntax = Dune_lang.Syntax.get_exn syntax
@@ -50,14 +53,3 @@ let () =
5053
syntax
5154
(return [ "menhir", decode_stanza decode ])
5255
;;
53-
54-
let modules (stanza : t) : string list =
55-
match stanza.merge_into with
56-
| Some m -> [ m ]
57-
| None -> stanza.modules
58-
;;
59-
60-
let targets (stanza : t) : string list =
61-
let f m = [ m ^ ".ml"; m ^ ".mli" ] in
62-
List.concat_map (modules stanza) ~f
63-
;;

src/dune_rules/menhir/menhir_stanza.mli

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ val syntax : Syntax.t
55
type t =
66
{ merge_into : string option
77
; flags : Ordered_set_lang.Unexpanded.t
8-
; modules : string list
8+
; modules : Ordered_set_lang.Unexpanded.t
99
; mode : Rule_mode.t
1010
; loc : Loc.t
1111
; infer : bool
@@ -14,11 +14,4 @@ type t =
1414
; menhir_syntax : Syntax.Version.t
1515
}
1616

17-
val modules : t -> string list
18-
19-
(** Return the list of targets that are generated by this stanza. This list of
20-
targets is used by the code that computes the list of modules in the
21-
directory. *)
22-
val targets : t -> string list
23-
2417
include Stanza.S with type t := t

0 commit comments

Comments
 (0)