Skip to content

v0.3.3 — peglib-formatter framework

Choose a tag to compare

@siy siy released this 22 Apr 05:32
· 377 commits to main since this release
2272064

Final release in the 0.2.3 → 0.3.3 roadmap. New peglib-formatter module ships a Wadler-Lindig pretty-printer framework for grammar-driven formatters, closing peglib as a complete language-tool substrate: parse → incremental reparse → format.

Doc algebra

Sealed Doc interface with seven records (Text, Line, Softline, Group, Indent, Concat, Empty) + static builders in Docs. Canonical Wadler algebra implemented in ~200 LOC.

Fluent DSL

var formatter = Formatter.builder()
    .rule("Block", (ctx, children) ->
        group(text("{"), line(), indent(4, children.concat()), line(), text("}")))
    .rule("ArgList", (ctx, children) ->
        children.joinWith(text(","), line()))
    .defaultIndent(4)
    .maxLineWidth(100)
    .build();

Result<String> output = formatter.format(cst);

Rule lookup by CstNode#rule() name. Children are pre-formatted before the user's rule combinator runs.

Demo formatters

Three end-to-end demos with idempotency fuzz tests:

  • JSON — objects with braces + indented members; arrays similar.
  • SQL-like — clause-per-line, keywords upper-cased.
  • Arithmetic — precedence-aware with minimal parentheses.

Each passes format(format(x)) == format(x) on fuzz inputs.

Limitations

Trivia preservation is best-effort in v1. Depends on 0.2.4's trivia attribution foundation, which still has a deferred rule-exit pos-rewind for trailing intra-rule trivia. Format output may not byte-equal source for all inputs today; full round-trip lands when the trivia foundation is completed.

Module layout

peglib-formatter depends on peglib-core. Installable independently or via the peglib-parent reactor.

Breaking changes

None. Strictly additive.