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.