Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add (explain) field to (menhir) stanza #9512

Merged
merged 20 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/stanzas/menhir.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ Menhir supports writing the grammar and automation to the ``.cmly`` file.
Therefore, if this is flag is passed to Menhir, Dune will know to introduce a
``.cmly`` target for the module.

- ``(explain <bool>)`` is used to control the generation of the ``.conflicts``
file explaining conflicts found while generating the parser. This option is
available since version 2.2 of the Menhir extension. This file is generated by
default starting at version 3.13 of the Dune language.

.. _menhir-git: https://gitlab.inria.fr/fpottier/menhir
17 changes: 17 additions & 0 deletions src/dune_rules/menhir/menhir_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ module Run (P : PARAMS) = struct
Super_context.add_rule sctx ~dir ~mode ~loc:stanza.loc
;;

let explain_flags base explain =
let open Memo.O in
let* expander = expander in
let+ explain = Expander.eval_blang expander explain in
if explain
then
[ Command.Args.A "--explain"
; Hidden_targets [ Path.Build.relative dir (base ^ ".conflicts") ]
]
else []
;;

let expand_flags flags =
let standard =
Action_builder.of_memo @@ Super_context.env_node sctx ~dir >>= Env_node.menhir_flags
Expand Down Expand Up @@ -225,9 +237,11 @@ module Run (P : PARAMS) = struct
let* () =
Module_compilation.ocamlc_i ~deps cctx mock_module ~output:(inferred_mli base)
in
let* explain_flags = explain_flags base stanza.explain in
(* 3. A second invocation of Menhir reads the inferred [.mli] file. *)
menhir
[ Command.Args.dyn expanded_flags
; S explain_flags
; Deps (sources stanza.modules)
; A "--base"
; Path (Path.relative (Path.build dir) base)
Expand All @@ -244,9 +258,12 @@ module Run (P : PARAMS) = struct
is a simpler one-step process where Menhir is invoked directly. *)

let process1 base ~cmly (stanza : stanza) : unit Memo.t =
let open Memo.O in
let expanded_flags = expand_flags stanza.flags in
let* explain_flags = explain_flags base stanza.explain in
menhir
[ Command.Args.dyn expanded_flags
; S explain_flags
; Deps (sources stanza.modules)
; A "--base"
; Path (Path.relative (Path.build dir) base)
Expand Down
14 changes: 12 additions & 2 deletions src/dune_rules/menhir/menhir_stanza.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ let syntax =
; (1, 1), `Since (1, 4)
; (2, 0), `Since (1, 4)
; (2, 1), `Since (2, 2)
; (2, 2), `Since (3, 13)
]
;;

Expand All @@ -21,6 +22,7 @@ type t =
; loc : Loc.t
; infer : bool
; enabled_if : Blang.t
; explain : Blang.t
}

let decode =
Expand All @@ -32,13 +34,21 @@ let decode =
and+ infer = field_o_b "infer" ~check:(Dune_lang.Syntax.since syntax (2, 0))
and+ menhir_syntax = Dune_lang.Syntax.get_exn syntax
and+ enabled_if = Enabled_if.decode ~allowed_vars:Any ~since:(Some (1, 4)) ()
and+ loc = loc in
and+ loc = loc
and+ explain =
field_o "explain" (Dune_lang.Syntax.since syntax (2, 2) >>> Blang.decode)
in
let infer =
match infer with
| Some infer -> infer
| None -> menhir_syntax >= (2, 0)
in
{ merge_into; flags; modules; mode; loc; infer; enabled_if })
let explain =
match explain with
| None -> if menhir_syntax >= (2, 2) then Blang.true_ else Blang.false_
| Some explain -> explain
in
{ merge_into; flags; modules; mode; loc; infer; enabled_if; explain })
;;

include Stanza.Make (struct
Expand Down
1 change: 1 addition & 0 deletions src/dune_rules/menhir/menhir_stanza.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type t =
; loc : Loc.t
; infer : bool
; enabled_if : Blang.t
; explain : Blang.t
}

val modules : t -> string list
Expand Down
177 changes: 177 additions & 0 deletions test/blackbox-tests/test-cases/menhir/explain.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
Support (explain) field in (menhir) stanza to produce .conflicts file:

$ cat >parser.mly <<EOF
> %token START
> %start <int> start
> %%
> start: START | START { 42 }
> EOF

$ cat >dune <<EOF
> (menhir (modules parser) (explain true))
> (library (name lib))
> EOF

First we check the version guards:

$ cat >dune-project <<EOF
> (lang dune 3.12)
> (using menhir 2.1)
> EOF

$ dune build
File "dune", line 1, characters 25-39:
1 | (menhir (modules parser) (explain true))
^^^^^^^^^^^^^^
Error: 'explain' is only available since version 2.2 of the menhir extension.
Please update your dune-project file to have (using menhir 2.2).
[1]

$ cat >dune-project <<EOF
> (lang dune 3.12)
> (using menhir 2.2)
> EOF

$ dune build
File "dune-project", line 2, characters 14-17:
2 | (using menhir 2.2)
^^^
Error: Version 2.2 of the menhir extension is not supported until version
3.13 of the dune language.
Supported versions of this extension in version 3.12 of the dune language:
- 1.0 to 1.1
- 2.0 to 2.1
[1]

$ cat >dune-project <<EOF
> (lang dune 3.13)
> (using menhir 2.2)
> EOF

$ dune build
Warning: one state has reduce/reduce conflicts.
Warning: one reduce/reduce conflict was arbitrarily resolved.
File "parser.mly", line 4, characters 15-20:
Warning: production start -> START is never reduced.
Warning: in total, 1 production is never reduced.

Let's check that the conflicts file has been generated successfully:

$ cat _build/default/parser.conflicts

** Conflict (reduce/reduce) in state 1.
** Token involved: #
** This state is reached from start after reading:

START

** The derivations that appear below have the following common factor:
** (The question mark symbol (?) represents the spot where the derivations begin to differ.)

start // lookahead token is inherited
(?)

** In state 1, looking ahead at #, reducing production
** start -> START
** is permitted because of the following sub-derivation:

START .

** In state 1, looking ahead at #, reducing production
** start -> START
** is permitted because of the following sub-derivation:

START .








Let's check we can also pass `(explain false)`:

$ cat >dune <<EOF
> (menhir (modules parser) (explain false))
> (library (name lib))
> EOF

$ dune build
Warning: one state has reduce/reduce conflicts.
Warning: one reduce/reduce conflict was arbitrarily resolved.
File "parser.mly", line 4, characters 15-20:
Warning: production start -> START is never reduced.
Warning: in total, 1 production is never reduced.

$ ! test -f _build/default/parser.conflicts

Let's check that it is generated by default if we omit the (explain) field:

$ cat >dune <<EOF
> (menhir (modules parser))
> (library (name lib))
> EOF

$ dune build
Warning: one state has reduce/reduce conflicts.
Warning: one reduce/reduce conflict was arbitrarily resolved.
File "parser.mly", line 4, characters 15-20:
Warning: production start -> START is never reduced.
Warning: in total, 1 production is never reduced.

$ cat _build/default/parser.conflicts

** Conflict (reduce/reduce) in state 1.
** Token involved: #
** This state is reached from start after reading:

START

** The derivations that appear below have the following common factor:
** (The question mark symbol (?) represents the spot where the derivations begin to differ.)

start // lookahead token is inherited
(?)

** In state 1, looking ahead at #, reducing production
** start -> START
** is permitted because of the following sub-derivation:

START .

** In state 1, looking ahead at #, reducing production
** start -> START
** is permitted because of the following sub-derivation:

START .




... but only if the Dune version is recent enough:

$ cat >dune-project <<EOF
> (lang dune 3.13)
> (using menhir 2.1)
> EOF

$ dune build

$ ! test -f _build/default/parser.conflicts

Let's check that the argument to (explain) can be a blang:

$ cat >dune-project <<EOF
> (lang dune 3.13)
> (using menhir 2.2)
> EOF

$ cat >dune <<EOF
> (menhir (modules parser) (explain (= true false)))
> (library (name lib))
> EOF

$ dune build

$ ! test -f _build/default/parser.conflicts