Module doc

Module doc 

Source
Expand description

Doc comments: ## in the Python surface, ;; in the S-expression one.

docs/16-packages-and-ecosystem.md §16.2 asks for “documentation generated from types and doc-comments for every published version, automatically”. The types were already there — beck_core::iface::Interface has carried each name’s signature, effect row and placement since Phase 2. This module supplies the other half.

§Why a side pass rather than a token

An ordinary comment is skipped by the lexer, and layout treats a comment-only line as having no indentation at all — that is what lets a comment sit at column zero inside an indented block without closing it (crate::lexer). Lexing ## as a real token would put that rule at risk for every file, to serve a feature that only reads declarations.

So doc comments are collected from the source text and attached to nodes afterwards, by position: a run of ## lines belongs to the declaration on the first line beneath it. The token stream, the layout algorithm and the parser are untouched.

§What attaches where

A run attaches to the outermost node beginning that line, which is what makes

## The page the browser subscribes to.
@on(client)
def page(…) -> Html:

attach to the decorate form rather than to nothing: the decorator is part of the declaration, and the doc comment is written above the whole thing.

A doc comment is crate::Meta, not a form, so it is not part of a node’s identity: a doc-only edit does not change crate::Node::structurally_eq, does not invalidate a memo, and does not move beck_core::iface::Interface::digest — documenting a function is not an API change.

§Ordinary comments are collected by the same pass, for the same reason

beck fmt prints from the tree, so a comment the tree does not carry is one the formatter deletes — and a formatter an editor runs on save must not delete what somebody wrote. That was DEFECTS.md::fmt-comments, and it is why textDocument/formatting was deliberately not offered.

One pass rather than two, because what separates the two kinds is one decision: a line beginning ## is documentation and a line beginning # is a comment. Collected apart, that rule would be written twice and the copies would disagree about ###.

Three positions, and each attaches differently:

  • Above a node, as crate::Comments::before — a run of full-line comments, claimed by the outermost node beginning the first line beneath it.
  • At the end of a node’s own line, as crate::Comments::trailing. Finding it means skipping string literals, because "a # b" is not a comment.
  • Below a node with nothing after it, as crate::Comments::after — the end of a body or of the file. These attach backwards, to the last node that began a line above them, because there is nothing beneath to attach forwards to. Without this case the comment at the end of a function would move to whatever came next and out of the block it was written in.

Structs§

DocComments
Every comment in one source file, indexed by the line it belongs to.

Constants§

PY_MARKER
The marker for the Python surface — ##, one more # than a comment, as /// is one more /.
SEXPR_MARKER
The marker for the S-expression surface. ;; is the Lisp convention for a comment about the form beneath it, and ; stays an ordinary comment.

Functions§

attach
Attach every run to the node it documents.
collect
Collect every doc-comment run in a file.
marker_for
The marker a file’s extension implies.
render
Render a doc comment back into source, one ## line each, at the given indentation.