diff --git a/src/dune_rules/menhir/menhir_rules.ml b/src/dune_rules/menhir/menhir_rules.ml index 16b12c2a484a..258cfb76686f 100644 --- a/src/dune_rules/menhir/menhir_rules.ml +++ b/src/dune_rules/menhir/menhir_rules.ml @@ -75,8 +75,9 @@ module Run (P : PARAMS) = struct let source m = Path.relative (Path.build dir) (m ^ ".mly") - let targets m ~cmly = + let targets m ~cmly ~conflicts = let base = [ m ^ ".ml"; m ^ ".mli" ] in + let base = if conflicts then (m ^ ".conflicts") :: base else base in List.map ~f:(Path.Build.relative dir) (if cmly then (m ^ ".cmly") :: base else base) ;; @@ -185,7 +186,7 @@ module Run (P : PARAMS) = struct is the three-step process where Menhir is invoked twice and OCaml type inference is performed in between. *) - let process3 base ~cmly (stanza : stanza) : unit Memo.t = + let process3 base ~cmly ~conflicts (stanza : stanza) : unit Memo.t = let open Memo.O in let expanded_flags = expand_flags stanza.flags in (* 1. A first invocation of Menhir creates a mock [.ml] file. *) @@ -234,7 +235,7 @@ module Run (P : PARAMS) = struct ; Path (Path.relative (Path.build dir) base) ; A "--infer-read-reply" ; Dep (Path.build (inferred_mli base)) - ; Hidden_targets (targets base ~cmly) + ; Hidden_targets (targets base ~cmly ~conflicts) ] >>= rule ;; @@ -244,7 +245,7 @@ module Run (P : PARAMS) = struct (* [process3 stanza] converts a Menhir stanza into a set of build rules. This is a simpler one-step process where Menhir is invoked directly. *) - let process1 base ~cmly (stanza : stanza) : unit Memo.t = + let process1 base ~cmly ~conflicts (stanza : stanza) : unit Memo.t = let open Memo.O in let expanded_flags = expand_flags stanza.flags in menhir @@ -252,7 +253,7 @@ module Run (P : PARAMS) = struct ; Deps (sources stanza.modules) ; A "--base" ; Path (Path.relative (Path.build dir) base) - ; Hidden_targets (targets base ~cmly) + ; Hidden_targets (targets base ~cmly ~conflicts) ] >>= rule ;; @@ -263,26 +264,32 @@ module Run (P : PARAMS) = struct either [process3] or [process1], as appropriate. *) (* Because Menhir processes [--only-tokens] before the [--infer-*] commands, - when [--only-tokens] is present, no [--infer-*] command should be used. *) + when [--only-tokens] is present, no [--infer-*] command should be used. + When Menhir is called with [--only-tokens], it does not generate a [.conflicts] + file even the [--explain] flag is passed. Otherwise, a (possibly empty) + [.conflicts] file is always generated (if Menhir succeeds in creating a + [.ml/.mli] file). + *) let process (stanza : stanza) : unit Memo.t = let base = Option.value_exn stanza.merge_into in - let ocaml_type_inference_disabled, cmly = + let ocaml_type_inference_disabled, cmly, conflicts = Ordered_set_lang.Unexpanded.fold_strings stanza.flags - ~init:(false, false) - ~f:(fun pos sw ((only_tokens, cmly) as acc) -> + ~init:(false, false, false) + ~f:(fun pos sw ((only_tokens, cmly, conflicts) as acc) -> match pos with | Neg -> acc | Pos -> (match String_with_vars.text_only sw with - | Some "--only-tokens" -> true, cmly - | Some "--cmly" -> only_tokens, true + | Some "--only-tokens" -> true, cmly, false + | Some "--cmly" -> only_tokens, true, conflicts + | Some "--explain" -> only_tokens, cmly, not only_tokens | Some _ | None -> acc)) in if ocaml_type_inference_disabled || not stanza.infer - then process1 base stanza ~cmly - else process3 base stanza ~cmly + then process1 base stanza ~cmly ~conflicts + else process3 base stanza ~cmly ~conflicts ;; (* ------------------------------------------------------------------------ *)