From 94d944bd401413c90ff2907573e9e142c90980b4 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Tue, 26 May 2026 10:39:06 +0200 Subject: [PATCH 1/2] Add regression test for lexer errors in doc code blocks Exercises six Lexer.Error variants triggered from inside {@ocaml[...]} blocks. The expected .err files capture the current behaviour: the catch-all branch at lib/Fmt_ast.ml stringifies the exception as "invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _)", which is unreadable. The next commit replaces these with human-readable messages, and this test pins the change. --- test/passing/gen/dune.inc | 18 ++++++++ .../refs.ahrefs/doc_lexer_errors.mld.err | 18 ++++++++ .../refs.ahrefs/doc_lexer_errors.mld.ref | 41 +++++++++++++++++++ .../refs.default/doc_lexer_errors.mld.err | 18 ++++++++ .../refs.default/doc_lexer_errors.mld.ref | 41 +++++++++++++++++++ .../refs.janestreet/doc_lexer_errors.mld.err | 18 ++++++++ .../refs.janestreet/doc_lexer_errors.mld.ref | 41 +++++++++++++++++++ .../refs.ocamlformat/doc_lexer_errors.mld.err | 18 ++++++++ .../refs.ocamlformat/doc_lexer_errors.mld.ref | 41 +++++++++++++++++++ test/passing/tests/doc_lexer_errors.mld | 41 +++++++++++++++++++ test/passing/tests/doc_lexer_errors.mld.opts | 1 + 11 files changed, 296 insertions(+) create mode 100644 test/passing/refs.ahrefs/doc_lexer_errors.mld.err create mode 100644 test/passing/refs.ahrefs/doc_lexer_errors.mld.ref create mode 100644 test/passing/refs.default/doc_lexer_errors.mld.err create mode 100644 test/passing/refs.default/doc_lexer_errors.mld.ref create mode 100644 test/passing/refs.janestreet/doc_lexer_errors.mld.err create mode 100644 test/passing/refs.janestreet/doc_lexer_errors.mld.ref create mode 100644 test/passing/refs.ocamlformat/doc_lexer_errors.mld.err create mode 100644 test/passing/refs.ocamlformat/doc_lexer_errors.mld.ref create mode 100644 test/passing/tests/doc_lexer_errors.mld create mode 100644 test/passing/tests/doc_lexer_errors.mld.opts diff --git a/test/passing/gen/dune.inc b/test/passing/gen/dune.inc index 8d217c33e9..c3ca97c62f 100644 --- a/test/passing/gen/dune.inc +++ b/test/passing/gen/dune.inc @@ -1694,6 +1694,24 @@ (package ocamlformat) (action (diff doc_comments_padding.ml.err doc_comments_padding.ml.stderr))) +(rule + (deps .ocamlformat) + (package ocamlformat) + (action + (with-stdout-to doc_lexer_errors.mld.stdout + (with-stderr-to doc_lexer_errors.mld.stderr + (run %{bin:ocamlformat} --name doc_lexer_errors.mld --margin-check --parse-toplevel-phrases %{dep:../tests/doc_lexer_errors.mld}))))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff doc_lexer_errors.mld.ref doc_lexer_errors.mld.stdout))) + +(rule + (alias runtest) + (package ocamlformat) + (action (diff doc_lexer_errors.mld.err doc_lexer_errors.mld.stderr))) + (rule (deps .ocamlformat) (package ocamlformat) diff --git a/test/passing/refs.ahrefs/doc_lexer_errors.mld.err b/test/passing/refs.ahrefs/doc_lexer_errors.mld.err new file mode 100644 index 0000000000..d23c72a66f --- /dev/null +++ b/test/passing/refs.ahrefs/doc_lexer_errors.mld.err @@ -0,0 +1,18 @@ +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) diff --git a/test/passing/refs.ahrefs/doc_lexer_errors.mld.ref b/test/passing/refs.ahrefs/doc_lexer_errors.mld.ref new file mode 100644 index 0000000000..8cebb0f230 --- /dev/null +++ b/test/passing/refs.ahrefs/doc_lexer_errors.mld.ref @@ -0,0 +1,41 @@ +Regression test for readable lexer error messages in OCaml code blocks. + +Each block below triggers a different Lexer.Error variant; without the fix, all +of them would report the cryptic "invalid code block: +Ocamlformat_parser_extended.Lexer.Error" form. + +Empty character literal: + +{@ocaml[ + let _ = '' +]} + +Unterminated string: + +{@ocaml[ + let _ = "abc +]} + +Unterminated comment: + +{@ocaml[ + let _ = (* abc +]} + +Invalid literal: + +{@ocaml[ + let _ = 0xz +]} + +Capitalized label: + +{@ocaml[ + let _ = f ~Foo:1 +]} + +Keyword used as label: + +{@ocaml[ + let _ = f ~let:1 +]} diff --git a/test/passing/refs.default/doc_lexer_errors.mld.err b/test/passing/refs.default/doc_lexer_errors.mld.err new file mode 100644 index 0000000000..d23c72a66f --- /dev/null +++ b/test/passing/refs.default/doc_lexer_errors.mld.err @@ -0,0 +1,18 @@ +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) diff --git a/test/passing/refs.default/doc_lexer_errors.mld.ref b/test/passing/refs.default/doc_lexer_errors.mld.ref new file mode 100644 index 0000000000..8cebb0f230 --- /dev/null +++ b/test/passing/refs.default/doc_lexer_errors.mld.ref @@ -0,0 +1,41 @@ +Regression test for readable lexer error messages in OCaml code blocks. + +Each block below triggers a different Lexer.Error variant; without the fix, all +of them would report the cryptic "invalid code block: +Ocamlformat_parser_extended.Lexer.Error" form. + +Empty character literal: + +{@ocaml[ + let _ = '' +]} + +Unterminated string: + +{@ocaml[ + let _ = "abc +]} + +Unterminated comment: + +{@ocaml[ + let _ = (* abc +]} + +Invalid literal: + +{@ocaml[ + let _ = 0xz +]} + +Capitalized label: + +{@ocaml[ + let _ = f ~Foo:1 +]} + +Keyword used as label: + +{@ocaml[ + let _ = f ~let:1 +]} diff --git a/test/passing/refs.janestreet/doc_lexer_errors.mld.err b/test/passing/refs.janestreet/doc_lexer_errors.mld.err new file mode 100644 index 0000000000..d23c72a66f --- /dev/null +++ b/test/passing/refs.janestreet/doc_lexer_errors.mld.err @@ -0,0 +1,18 @@ +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) diff --git a/test/passing/refs.janestreet/doc_lexer_errors.mld.ref b/test/passing/refs.janestreet/doc_lexer_errors.mld.ref new file mode 100644 index 0000000000..70204d29f0 --- /dev/null +++ b/test/passing/refs.janestreet/doc_lexer_errors.mld.ref @@ -0,0 +1,41 @@ +Regression test for readable lexer error messages in OCaml code blocks. + +Each block below triggers a different Lexer.Error variant; without the +fix, all of them would report the cryptic +"invalid code block: Ocamlformat_parser_extended.Lexer.Error" form. + +Empty character literal: + +{@ocaml[ + let _ = '' +]} + +Unterminated string: + +{@ocaml[ + let _ = "abc +]} + +Unterminated comment: + +{@ocaml[ + let _ = (* abc +]} + +Invalid literal: + +{@ocaml[ + let _ = 0xz +]} + +Capitalized label: + +{@ocaml[ + let _ = f ~Foo:1 +]} + +Keyword used as label: + +{@ocaml[ + let _ = f ~let:1 +]} diff --git a/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err b/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err new file mode 100644 index 0000000000..d23c72a66f --- /dev/null +++ b/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err @@ -0,0 +1,18 @@ +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +Warning: Invalid documentation comment: +File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: +invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) diff --git a/test/passing/refs.ocamlformat/doc_lexer_errors.mld.ref b/test/passing/refs.ocamlformat/doc_lexer_errors.mld.ref new file mode 100644 index 0000000000..8cebb0f230 --- /dev/null +++ b/test/passing/refs.ocamlformat/doc_lexer_errors.mld.ref @@ -0,0 +1,41 @@ +Regression test for readable lexer error messages in OCaml code blocks. + +Each block below triggers a different Lexer.Error variant; without the fix, all +of them would report the cryptic "invalid code block: +Ocamlformat_parser_extended.Lexer.Error" form. + +Empty character literal: + +{@ocaml[ + let _ = '' +]} + +Unterminated string: + +{@ocaml[ + let _ = "abc +]} + +Unterminated comment: + +{@ocaml[ + let _ = (* abc +]} + +Invalid literal: + +{@ocaml[ + let _ = 0xz +]} + +Capitalized label: + +{@ocaml[ + let _ = f ~Foo:1 +]} + +Keyword used as label: + +{@ocaml[ + let _ = f ~let:1 +]} diff --git a/test/passing/tests/doc_lexer_errors.mld b/test/passing/tests/doc_lexer_errors.mld new file mode 100644 index 0000000000..70204d29f0 --- /dev/null +++ b/test/passing/tests/doc_lexer_errors.mld @@ -0,0 +1,41 @@ +Regression test for readable lexer error messages in OCaml code blocks. + +Each block below triggers a different Lexer.Error variant; without the +fix, all of them would report the cryptic +"invalid code block: Ocamlformat_parser_extended.Lexer.Error" form. + +Empty character literal: + +{@ocaml[ + let _ = '' +]} + +Unterminated string: + +{@ocaml[ + let _ = "abc +]} + +Unterminated comment: + +{@ocaml[ + let _ = (* abc +]} + +Invalid literal: + +{@ocaml[ + let _ = 0xz +]} + +Capitalized label: + +{@ocaml[ + let _ = f ~Foo:1 +]} + +Keyword used as label: + +{@ocaml[ + let _ = f ~let:1 +]} diff --git a/test/passing/tests/doc_lexer_errors.mld.opts b/test/passing/tests/doc_lexer_errors.mld.opts new file mode 100644 index 0000000000..8c317dccc0 --- /dev/null +++ b/test/passing/tests/doc_lexer_errors.mld.opts @@ -0,0 +1 @@ +--parse-toplevel-phrases From 0b8ec2039cc1b26d95e6b7c23b88d9a8b509d0e7 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Tue, 26 May 2026 10:52:44 +0200 Subject: [PATCH 2/2] Print readable error messages in doc code blocks When parsing fails inside a `{@ocaml[...]}` block, the catch-all branch formatted the exception with `Exn.pp`, which for `Lexer.Error` produced the raw constructor pattern `Ocamlformat_parser_extended.Lexer.Error(_, _)`. `Lexer.Error` (and most other compiler-libs exceptions) register a printer via `Location.register_error_of_exn`, but that table is separate from the `Printexc` table `Exn.pp` consults, so the printer was never used. Route the catch-all through `Location.error_of_exn` instead: if a printer is registered, format its `main` message; otherwise fall back to `Exn.pp`. This handles `Lexer.Error` and any other registered exception (e.g. parser internals) without per-variant enumeration. The .err diff against the previous commit shows the before/after for the six variants the regression test exercises. --- CHANGES.md | 4 ++++ lib/Fmt_ast.ml | 9 ++++++++- lib/dune | 3 +++ test/passing/refs.ahrefs/doc_lexer_errors.mld.err | 12 ++++++------ test/passing/refs.default/doc_lexer_errors.mld.err | 12 ++++++------ .../passing/refs.janestreet/doc_lexer_errors.mld.err | 12 ++++++------ .../refs.ocamlformat/doc_lexer_errors.mld.err | 12 ++++++------ 7 files changed, 39 insertions(+), 25 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 797002d038..107929cca2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,10 @@ profile. This started with version 0.26.0. ### Fixed +- Print readable messages for errors raised when parsing OCaml code blocks + in documentation comments, instead of the raw exception representation + `Ocamlformat_parser_extended.Lexer.Error(_, _)` (#PR, @hhugo) + - Fix instability on long `if-then-else` with `if-then-else=fit-or-vertical` (#2797, @MisterDA) diff --git a/lib/Fmt_ast.ml b/lib/Fmt_ast.ml index 62ecceced4..a1d97cf32a 100644 --- a/lib/Fmt_ast.ml +++ b/lib/Fmt_ast.ml @@ -5155,7 +5155,14 @@ let fmt_code ~debug = Error (`Msg (Format.asprintf "not expecting: %s" x)) | exception Syntaxerr.Error (Other _) when warn -> Error (`Msg (Format.asprintf "invalid toplevel or OCaml syntax")) - | exception e when warn -> Error (`Msg (Format.asprintf "%a" Exn.pp e)) + | exception e when warn -> + let msg = + match Location.error_of_exn e with + | Some (`Ok report) -> + Format.asprintf "%a" Format_doc.Doc.format report.main.txt + | _ -> Format.asprintf "%a" Exn.pp e + in + Error (`Msg msg) | exception _ -> Error (`Msg "") in fmt_code diff --git a/lib/dune b/lib/dune index 1281db301d..5509ff4a68 100644 --- a/lib/dune +++ b/lib/dune @@ -23,6 +23,8 @@ -open Ocamlformat_parser_extended -open + Ocamlformat_parser_shims + -open Ocamlformat_stdlib -open Ocamlformat_format)) @@ -35,6 +37,7 @@ ocamlformat_ocaml_common ocamlformat_odoc_parser ocamlformat_parser_extended + ocamlformat_parser_shims ocamlformat_parser_standard ocamlformat_stdlib ocp-indent.lib diff --git a/test/passing/refs.ahrefs/doc_lexer_errors.mld.err b/test/passing/refs.ahrefs/doc_lexer_errors.mld.err index d23c72a66f..9b6759a24c 100644 --- a/test/passing/refs.ahrefs/doc_lexer_errors.mld.err +++ b/test/passing/refs.ahrefs/doc_lexer_errors.mld.err @@ -1,18 +1,18 @@ Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +invalid code block: Illegal empty character literal '' Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +invalid code block: String literal not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Comment not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Invalid literal 0xz Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Foo cannot be used as label name, it must start with a lowercase letter Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: let is a keyword, it cannot be used as label name diff --git a/test/passing/refs.default/doc_lexer_errors.mld.err b/test/passing/refs.default/doc_lexer_errors.mld.err index d23c72a66f..9b6759a24c 100644 --- a/test/passing/refs.default/doc_lexer_errors.mld.err +++ b/test/passing/refs.default/doc_lexer_errors.mld.err @@ -1,18 +1,18 @@ Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +invalid code block: Illegal empty character literal '' Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +invalid code block: String literal not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Comment not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Invalid literal 0xz Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Foo cannot be used as label name, it must start with a lowercase letter Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: let is a keyword, it cannot be used as label name diff --git a/test/passing/refs.janestreet/doc_lexer_errors.mld.err b/test/passing/refs.janestreet/doc_lexer_errors.mld.err index d23c72a66f..9b6759a24c 100644 --- a/test/passing/refs.janestreet/doc_lexer_errors.mld.err +++ b/test/passing/refs.janestreet/doc_lexer_errors.mld.err @@ -1,18 +1,18 @@ Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +invalid code block: Illegal empty character literal '' Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +invalid code block: String literal not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Comment not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Invalid literal 0xz Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Foo cannot be used as label name, it must start with a lowercase letter Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: let is a keyword, it cannot be used as label name diff --git a/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err b/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err index d23c72a66f..9b6759a24c 100644 --- a/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err +++ b/test/passing/refs.ocamlformat/doc_lexer_errors.mld.err @@ -1,18 +1,18 @@ Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 9, character 8 to line 11, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(1, _) +invalid code block: Illegal empty character literal '' Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 15, character 8 to line 17, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(0, _) +invalid code block: String literal not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 21, character 8 to line 23, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Comment not terminated Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 27, character 8 to line 29, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Invalid literal 0xz Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 33, character 8 to line 35, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: Foo cannot be used as label name, it must start with a lowercase letter Warning: Invalid documentation comment: File "doc_lexer_errors.mld", line 39, character 8 to line 41, character 0: -invalid code block: Ocamlformat_parser_extended.Lexer.Error(_, _) +invalid code block: let is a keyword, it cannot be used as label name