Hello,
over the last few months, I've developed a small library called LazyLR (runtime
grammar parsers) and because it requires Java 25, I use the markdown
doc-comments introduced by JEP 467.
The overall experience is great, it's better than the traditional doc-comments
that mix documentation and HTML tags.
Here is my field trip report:
Pro:
- /// really shine to write one line doc for private methods, the visual
overhead is minimal compared to /** ... */
- /// does not requires escaping, even /// inside a /// is correctly
recognized
- Markdown is a better format than HTML for the documentation (especially
lists and tables)
- A blank line in markdown is really a blank line, unlike in HTML, so the the
doc comments are closer to the rendered javadoc (What you see is closer to what
you get)
- Code snippets using three backticks (```java) are easier to use than <pre>
(no <, no escaping needed)
Cons:
- If you have 100 lines of /// and one of then is a //, the javadoc will skip
all the lines before the '//' without a warning.
It should be great if javadoc could emit a warning in that case.
- Inline backtick `, are hard to read so it's easy to miss the ending
backtick,
Again, here, I think I would like a warning if there is no end backtick at
the end of the line
regards,
Rémi
Here is a full example:
https://github.com/forax/lazylr/blob/master/src/main/java/com/github/forax/lazylr/package-info.java
/// # Lazy LR — A Lightweight Runtime LR(1) Parser Library
///
/// This package provides all the building blocks to define a context-free
grammar,
/// tokenize raw text, and parse token streams into structured results at
runtime,
/// without a separate code-generation step.
///
/// ## Core Concepts
///
/// A [com.github.forax.lazylr.Grammar] is a validated set of
/// [com.github.forax.lazylr.Production] rules plus a
/// start [com.github.forax.lazylr.NonTerminal].
/// Productions are built from two kinds of [com.github.forax.lazylr.Symbol]s:
/// [com.github.forax.lazylr.Terminal] (a concrete token, e.g. `"+"` or `"num"`)
/// and [com.github.forax.lazylr.NonTerminal] (an abstract construct, e.g.
`"E"`).
///
/// [com.github.forax.lazylr.MetaGrammar] lets you describe tokens, precedence,
/// and productions in a compact text instead of building Java objects
programmaticaly:
///
/// ```java
/// var mg = MetaGrammar.load("""
/// tokens {
/// num: /[0-9]+/
/// /[ ]+/
/// }
/// precedence {
/// left: '+'
/// left: '*'
/// right: '^'
/// }
/// grammar {
/// E: num
/// E: E '+' E
/// E: E '*' E
/// E: E '^' E %prec '^'
/// }
/// """);
/// ```
///
/// The text has three optional sections:
/// - **`tokens`**: named terminals (`name: /regex/`) and unnamed
/// skip patterns (`/regex/`).
/// - **`precedence`**: `left:` or `right:` lines, lowest first,
/// multiple terminals per line share the same level.
/// - **`grammar`**: BNF-style rules; quoted literals like `'+'` are
/// auto-registered as terminals.
/// Lines with no right-hand side are epsilon productions,
/// `%prec TOKEN` overrides a production's default precedence.
///
/// ## Typical Usage
///
/// ```java
/// // 1. Load the grammar
/// MetaGrammar mg = MetaGrammar.load(grammarText);
///
/// // 2. Optionally verify for conflicts
/// mg.verify();
///
/// // 3. Parse and evaluate
/// String inputText = ...
/// var result = mg.parse(inputText, new MyVisitor());
/// ```
///
/// ## Key Classes
/// [com.github.forax.lazylr.LALRVerifier] performs a full offline LALR(1)
/// analysis and can print the complete state automaton with conflict markers.
/// This is the class used by [com.github.forax.lazylr.MetaGrammar#verify()].
///
/// [com.github.forax.lazylr.Lexer] converts a `CharSequence` into
/// a lazy `Iterator<Terminal>` using a longest-match rule, ties
/// broken by declaration order.
///
/// [com.github.forax.lazylr.Parser] implements a lazy LR(1) algorithm:
/// states are computed on demand.
/// Shift/reduce conflicts are resolved via a
[com.github.forax.lazylr.Precedence] map;
/// unresolved conflicts cause a [com.github.forax.lazylr.ParsingException]
/// during parsing.
/// A call to
[com.github.forax.lazylr.MetaGrammar#parse(java.lang.CharSequence,
com.github.forax.lazylr.Visitor)()]
/// creates a lexer and a parser.
///
/// [com.github.forax.lazylr.Visitor] maps terminal and productions to
typechecked methods.
/// When a terminal is shifted, the corresponding terminal method is called.
/// When a production is reduced, the production method is called with the
values
/// of the symbols of the production in left-to-right order.
///
[com.github.forax.lazylr.Visitor#reflect(java.lang.invoke.MethodHandles.Lookup,
com.github.forax.lazylr.Visitor)]
/// creates an evaluator from a visitor using reflection.
///
/// [com.github.forax.lazylr.Evaluator] maps parse events to a result
/// of type `T`: `evaluate(Terminal)` is called on every shift,
/// `evaluate(Production, List<T>)` on every reduction.
/// For event-driven use without a result, prefer
[com.github.forax.lazylr.ParserListener].
///
/// ## Thread Safety
/// All classes are immutable and thread-safe except
[com.github.forax.lazylr.Parser],
/// which is stateful and bound to the thread that uses it.
///
/// [com.github.forax.lazylr.MetaGrammar] is thread-safe and can be shared
globally.
///
/// For concurrent workloads, you can share a
[com.github.forax.lazylr.ParserFactory]
/// and call [com.github.forax.lazylr.ParserFactory#createParser()]
/// once per thread.
///
/// @see com.github.forax.lazylr.Terminal
/// @see com.github.forax.lazylr.Production
/// @see com.github.forax.lazylr.Grammar
/// @see com.github.forax.lazylr.MetaGrammar
/// @see com.github.forax.lazylr.Visitor