Skip to content

Integrate LRgrep error messages - #2072

Open
let-def wants to merge 7 commits into
ocaml:mainfrom
let-def:with-lrgrep
Open

Integrate LRgrep error messages#2072
let-def wants to merge 7 commits into
ocaml:mainfrom
let-def:with-lrgrep

Conversation

@let-def

@let-def let-def commented May 23, 2026

Copy link
Copy Markdown
Contributor

This PR integrates LRgrep to generate syntax error messages. This change improves the quality and consistency of error reporting while, hopefully, making the error-handling logic more maintainable. Currently, this is an additive change that complements the existing parser without modifying or removing any existing behavior.

Main changes:

  • Declarative error specification: Added src/ocaml/preprocess/parse_errors.lrgrep, which defines syntax error messages in a clear, declarative format.
  • Coverage reporting: The make lrgrep-coverage target generates coverage.md, a report listing grammatical constructs that currently lack error messages, along with actionable hints for adding coverage.
  • Runtime integration: Copied the LRgrep runtime into src/ocaml/preprocess/, following the same vendoring pattern used for MenhirLib.

The declarative approach should make error messages easier to write, review, and maintain. The coverage tool gives us visibility into error-reporting gaps and guides incremental improvements.
While this PR is a strict addition, the long-term goal is to gradually replace parser components with a version more tightly integrated with LRgrep. This will significantly simplify the preprocessing pipeline and reduce boilerplate in the error recovery and explanation code.

@voodoos

voodoos commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Thanks a lot @let-def !

As you probably noticed we merged the upgrade to 5.5 after you opened this PR.

Now we need to rebase it and I would like to use that as an occasion to learn about what it adds to the upgrade process.

I will start doing that today !

@voodoos

voodoos commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Du you think it would be useful to have a ci that diffs lr grep's coverage output ?

{ "Expected constructor or operator after `(`" }

| /constr_ident: LPAREN COLONCOLON . RPAREN
| /mk_longident(mod_ext_longident,__anonymous_42): LPAREN COLONCOLON . RPAREN

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@let-def What are these __anonymous_42 ? Is it some menhir internal ?

(I am using https://cambium.inria.fr/~fpottier/publis/bour-pottier-lrgrep-2026.pdf to try to decipher this file, but it's not mentioned there)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's indeed the names generated by menhir when lambda lifting. Not much I can do about that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(at the moment, but it would be nice to cleanup later!)

@voodoos voodoos Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can one know which anonymous is associated to which lambda ? For the upgrade it became invalid and I used the one suggested in the error message.

@voodoos

voodoos commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

@voodoos

voodoos commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

After getting rid of many errors when rebased on 5.5 I was finally able to run lrgrep...

But is it expected that it takes several minutes to complete ?

Some backtrace:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x0000000102c78970 lrgrep`caml_apply2 + 48
    frame #1: 0x0000000102cb38a0 lrgrep`camlKernel__Automata$fun_6076 + 224
    frame #2: 0x0000000102cfacc0 lrgrep`camlFix__Indexing$rev_iteri_1163 + 152
    frame #3: 0x0000000102cb36b0 lrgrep`camlKernel__Automata$fun_6028 + 264
    frame #4: 0x0000000102d1b9c8 lrgrep`camlStdlib__List$iter_373 + 88
    frame #5: 0x0000000102d1b9c8 lrgrep`camlStdlib__List$iter_373 + 88
    frame #6: 0x0000000102cee4d8 lrgrep`camlUtils__Misc$fixpoint_1535 + 120
    frame #7: 0x0000000102caed08 lrgrep`camlKernel__Automata$make_2496 + 3296
    frame #8: 0x0000000102c839c8 lrgrep`camlLrgrep_top$fun_4940 + 800
    frame #9: 0x0000000102d1b9c8 lrgrep`camlStdlib__List$iter_373 + 88
    frame #10: 0x0000000102c83650 lrgrep`camlLrgrep_top$do_compile_2717 + 1440
    frame #11: 0x0000000102c846b0 lrgrep`camlLrgrep_top$compile_command_2984 + 416
    frame #12: 0x0000000102cf21b4 lrgrep`camlUtils__Subarg$parse_argv_inner_944 + 852
    frame #13: 0x0000000102cf28f4 lrgrep`camlUtils__Subarg$parse_786 + 124
    frame #14: 0x0000000102c7f3ec lrgrep`camlLrgrep_top$Make_3162 + 5332
    frame #15: 0x0000000102c85a64 lrgrep`camlLrgrep_top$run_lrgrep_3163 + 116
    frame #16: 0x0000000102c78a28 lrgrep`camlDune__exe__Lrgrep$entry + 32
    frame #17: 0x0000000102c750c4 lrgrep`caml_program + 2356
    frame #18: 0x0000000102dbf4e4 lrgrep`caml_start_program + 132
    frame #19: 0x0000000102dbe8b8 lrgrep`caml_startup_common(argv=0x000000016d18a678, pooling=<unavailable>) at startup_nat.c:127:9 [opt]
    frame #20: 0x0000000102dbe91c lrgrep`caml_main [inlined] caml_startup_exn(argv=<unavailable>) at startup_nat.c:134:10 [opt]
    frame #21: 0x0000000102dbe914 lrgrep`caml_main [inlined] caml_startup(argv=<unavailable>) at startup_nat.c:139:15 [opt]
    frame #22: 0x0000000102dbe914 lrgrep`caml_main(argv=<unavailable>) at startup_nat.c:146:3 [opt]
    frame #23: 0x0000000102da7864 lrgrep`main(argc=<unavailable>, argv=<unavailable>) at main.c:37:3 [opt]
    frame #24: 0x000000019c5cab98 dyld`start + 6076

And another one a few seconds later:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
* frame #0: 0x0000000102d1b40c lrgrep`camlStdlib__List$map_340 + 52
  frame #1: 0x0000000102cb3720 lrgrep`camlKernel__Automata$fun_6028 + 376
  frame #2: 0x0000000102d1b9c8 lrgrep`camlStdlib__List$iter_373 + 88
  frame #3: 0x0000000102d1b9c8 lrgrep`camlStdlib__List$iter_373 + 88
  frame #4: 0x0000000102cee4d8 lrgrep`camlUtils__Misc$fixpoint_1535 + 120
  frame #5: 0x0000000102caed08 lrgrep`camlKernel__Automata$make_2496 + 3296
  frame #6: 0x0000000102c839c8 lrgrep`camlLrgrep_top$fun_4940 + 800
  frame #7: 0x0000000102d1b9c8 lrgrep`camlStdlib__List$iter_373 + 88
  frame #8: 0x0000000102c83650 lrgrep`camlLrgrep_top$do_compile_2717 + 1440
  frame #9: 0x0000000102c846b0 lrgrep`camlLrgrep_top$compile_command_2984 + 416
  frame #10: 0x0000000102cf21b4 lrgrep`camlUtils__Subarg$parse_argv_inner_944 + 852
  frame #11: 0x0000000102cf28f4 lrgrep`camlUtils__Subarg$parse_786 + 124
  frame #12: 0x0000000102c7f3ec lrgrep`camlLrgrep_top$Make_3162 + 5332
  frame #13: 0x0000000102c85a64 lrgrep`camlLrgrep_top$run_lrgrep_3163 + 116
  frame #14: 0x0000000102c78a28 lrgrep`camlDune__exe__Lrgrep$entry + 32
  frame #15: 0x0000000102c750c4 lrgrep`caml_program + 2356
  frame #16: 0x0000000102dbf4e4 lrgrep`caml_start_program + 132
  frame #17: 0x0000000102dbe8b8 lrgrep`caml_startup_common(argv=0x000000016d18a678, pooling=<unavailable>) at startup_nat.c:127:9 [opt]
  frame #18: 0x0000000102dbe91c lrgrep`caml_main [inlined] caml_startup_exn(argv=<unavailable>) at startup_nat.c:134:10 [opt]
  frame #19: 0x0000000102dbe914 lrgrep`caml_main [inlined] caml_startup(argv=<unavailable>) at startup_nat.c:139:15 [opt]
  frame #20: 0x0000000102dbe914 lrgrep`caml_main(argv=<unavailable>) at startup_nat.c:146:3 [opt]
  frame #21: 0x0000000102da7864 lrgrep`main(argc=<unavailable>, argv=<unavailable>) at main.c:37:3 [opt]
  frame #22: 0x000000019c5cab98 dyld`start + 6076
  ```

@voodoos

voodoos commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

I stopped it after 20 minutes, something is clearly wrong...

@voodoos

voodoos commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Pinning on lrgrep's main branch fixes the loop !

Still a few fixes to make however 😅

parse_errors.lrgrep:260.6: warning: No items match this filter
parse_errors.lrgrep:495.6: warning: No items match this filter
parse_errors.lrgrep:496.6: warning: No items match this filter
parse_errors.lrgrep:667.2: warning: No items match this filter
parse_errors.lrgrep:682.6: warning: No items match this filter
parse_errors.lrgrep:788.2: warning: No items match this filter
parse_errors.lrgrep:791.2: warning: No items match this filter
parse_errors.lrgrep:792.2: warning: No items match this filter
parse_errors.lrgrep:793.2: warning: No items match this filter
parse_errors.lrgrep:908.2: warning: No items match this filter
parse_errors.lrgrep:957.6: warning: No items match this filter
parse_errors.lrgrep:958.6: warning: No items match this filter
parse_errors.lrgrep:959.6: warning: No items match this filter
parse_errors.lrgrep:960.6: warning: No items match this filter
parse_errors.lrgrep:964.6: warning: No items match this filter
parse_errors.lrgrep:965.6: warning: No items match this filter
parse_errors.lrgrep:1295.6: warning: No items match this filter
parse_errors.lrgrep:1298.6: warning: No items match this filter
parse_errors.lrgrep:1301.6: warning: No items match this filter
parse_errors.lrgrep:1302.6: warning: No items match this filter
parse_errors.lrgrep:1304.6: warning: No items match this filter
parse_errors.lrgrep:1313.2: warning: No items match this filter
parse_errors.lrgrep:1314.2: warning: No items match this filter
parse_errors.lrgrep:1327.6: warning: No items match this filter
parse_errors.lrgrep:1389.6: warning: No items match this filter
parse_errors.lrgrep:1390.6: warning: No items match this filter
parse_errors.lrgrep:1391.6: warning: No items match this filter
parse_errors.lrgrep:1393.6: warning: No items match this filter
parse_errors.lrgrep:1394.6: warning: No items match this filter
parse_errors.lrgrep:1395.6: warning: No items match this filter
parse_errors.lrgrep:1399.2: warning: No items match this filter
parse_errors.lrgrep:1400.2: warning: No items match this filter
parse_errors.lrgrep:1401.2: warning: No items match this filter
parse_errors.lrgrep:1402.2: warning: No items match this filter
parse_errors.lrgrep:1411.6: warning: No items match this filter
parse_errors.lrgrep:1412.6: warning: No items match this filter
parse_errors.lrgrep:1415.2: warning: No items match this filter
parse_errors.lrgrep:1701.6: warning: No items match this filter
parse_errors.lrgrep:1704.2: warning: No items match this filter
parse_errors.lrgrep:1910.6: warning: No items match this filter
parse_errors.lrgrep:1911.6: warning: No items match this filter
parse_errors.lrgrep:1916.6: warning: No items match this filter
parse_errors.lrgrep:1917.6: warning: No items match this filter
parse_errors.lrgrep:2078.6: warning: No items match this filter
parse_errors.lrgrep:259.1: warning: clause is unreachable
parse_errors.lrgrep:495.1: warning: clause is unreachable
parse_errors.lrgrep:667.2: warning: clause is unreachable
parse_errors.lrgrep:682.1: warning: clause is unreachable
parse_errors.lrgrep:908.2: warning: clause is unreachable
parse_errors.lrgrep:957.2: warning: clause is unreachable
parse_errors.lrgrep:964.1: warning: expression is unreachable
parse_errors.lrgrep:965.1: warning: expression is unreachable
parse_errors.lrgrep:1295.1: warning: clause is unreachable
parse_errors.lrgrep:1298.1: warning: clause is unreachable
parse_errors.lrgrep:1301.1: warning: expression is unreachable
parse_errors.lrgrep:1302.1: warning: expression is unreachable
parse_errors.lrgrep:1304.1: warning: expression is unreachable
parse_errors.lrgrep:1327.1: warning: clause is unreachable
parse_errors.lrgrep:1389.2: warning: clause is unreachable
parse_errors.lrgrep:1399.2: warning: clause is unreachable
parse_errors.lrgrep:1411.1: warning: clause is unreachable
parse_errors.lrgrep:1701.1: warning: clause is unreachable
parse_errors.lrgrep:1910.1: warning: expression is unreachable
parse_errors.lrgrep:1911.1: warning: expression is unreachable
parse_errors.lrgrep:1916.1: warning: expression is unreachable
parse_errors.lrgrep:1917.1: warning: expression is unreachable
parse_errors.lrgrep:2077.1: warning: expression is unreachable
total transitions: 10718 (domain: 18793), non-default: 9158
bytecode size: 19635
lrgrep: warning: rule error_messages has only partial coverage (use --cover-report <file> to get more information)

@voodoos

voodoos commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Unrelated question @let-def, but is there anything that would block this from being merged upstream ? Does it rely on the recovery ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants