Expand description
The canonical, producer-agnostic AST for R’s Rd documentation format.
rd-ast is the common target of the help-database lowering and the
rd-source Rd source parser. Semantic interpretation is provided by borrowed
views rather than encoded as producer-specific storage.
§Rd AST producer/consumer contract
This is the normative contract for rd-ast v1. MUST, MUST NOT,
REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT,
RECOMMENDED, MAY, and OPTIONAL have the RFC 2119/8174 meanings
when capitalized. A type-enforced guarantee is distinct from a correct
producer obligation: constructors accept arbitrary child shapes, so most
producer obligations are not compiler-enforced.
Every clause is marked as follows:
- [AST contract] producer-agnostic requirement.
- [RDS producer profile] behavior only of the
rds-feature lowering. - [Consumer guidance] renderer recommendation, not a structural guarantee.
- [Non-contract note] observation, corpus guard, or future plan.
§1. Scope and terminology
[AST contract] RdDocument is the common target of the
help-database lowering and the rd-source Rd source parser. Both producers MUST
express the same canonical semantics, and consumers MUST NOT need to know
which producer created a document.
[AST contract] Canonical nodes are Text, RCode, Verb, Comment,
Tagged, and Group. Raw is the lossless escape hatch for a genuinely
non-canonical structure. A view is a borrowed interpretation, never
replacement storage.
[Non-contract note] The crate is independent of both RDS decoding and a source parser. Source locations are outside the v1 AST.
§2. Conformance model: canonical nodes and Raw fallback
[AST contract] An unknown tag MUST become RdNode::Tagged with
RdTag::Unknown containing the original tag string. Unknown spelling alone
MUST NOT produce Raw.
[AST contract] Raw MUST be reserved for genuinely non-canonical
structures (for example unexpected attributes or an untagged non-list value).
When used, Raw preserves opaque node payloads as well as children and
attributes; a producer MUST NOT silently discard a value merely because it
cannot be represented as Rd children.
[RDS producer profile] The RDS lowering maps unrecognized Rd_tag strings
to Unknown; malformed/duplicated tag attributes and rejected attribute
shapes use lossless Raw. srcref is discarded only on a successful
structured path; Raw retains it and nested attributes.
§3. Text and escape semantics
[AST contract] Canonical strings MUST contain the canonical leaf value defined by the applicable producer profile. When an input format has escape spellings, a producer MUST apply that format’s grammar- and context-specific escape rules: it MUST decode a spelling when the grammar resolves it to a literal character, and MUST retain the spelling when the grammar makes that spelling part of the canonical leaf value. A producer MUST NOT decode a spelling that its grammar preserves or reintroduce a spelling after resolving it to a literal character. The AST contract does not impose a blanket rule that every recognized escape spelling is decoded.
[RDS producer profile] The pinned parse_Rd() fixtures contain both
decoded literal characters and contextually retained escape spellings. RDS
lowering MUST preserve the resulting leaf string exactly and MUST NOT perform
an additional escape-decoding or escape-encoding pass.
[AST contract] Producers MUST NOT apply Unicode normalization.
§4. Unicode, encoding, and NA
[AST contract] Canonical String values MUST be valid UTF-8. Producers
MUST convert supported input encodings and MUST NOT use lossy replacement.
[RDS producer profile] Latin-1 input is converted to UTF-8. ASCII Native
and Native explicitly identified as UTF-8 are accepted; non-UTF-8 Native,
invalid UTF-8, and Bytes are hard LowerError::InvalidStringEncoding
failures.
[RDS producer profile] In a structured character leaf, NA elements are
omitted and decoded elements are concatenated in order. In a RawRdValue
character or persisted vector, each NA remains None at its original
position.
[Non-contract note] RawRdReal::Finite being finite is not
type-enforced, although the RDS lowering classifies non-finite inputs into
dedicated variants.
§5. Ordering, whitespace, and comments
[AST contract] Correct producers MUST preserve source order of document nodes, children, options, and Raw vector elements.
[AST contract] Producers MUST NOT trim whitespace or merge text nodes.
Whitespace-only Text nodes are retained content.
[AST contract] Comments supplied by a producer MUST remain
RdNode::Comment nodes at their source position. A producer emitting one MUST
include its leading %; the Comment(String) constructor cannot enforce it.
[RDS producer profile] Comment preservation depends on the input object:
parse_Rd() must retain comments (for example via keep.source) for lowering
to receive them. Lowering does not invent absent comments.
[Consumer guidance] text_contents skips comments and is lossy. Exact
whitespace/comment rendering SHOULD walk the tree.
§6. Positional groups
[AST contract] Every untagged positional-argument group MUST be
RdNode::Group, not List or Raw merely because it has no tag.
[RDS producer profile] An untagged list-valued object with no rejected
attributes and no Rd_option lowers to Group, including nested groups.
§7. Options
[AST contract] RdTagged::option is the lossless syntax layer and MUST be
canonical storage. None means absent; Some(vec![]) means present and
empty; producers MUST preserve that distinction.
[AST contract] RdOptionList and typed option views are consumer views and
MUST NOT replace or mutate syntax-layer storage.
[Consumer guidance] Consumers SHOULD retain syntax nodes for round-trips and diagnostics, and use typed views for parsed pairs and typed overrides.
[RDS producer profile] Rd_option list content is lowered into the option
field; malformed option shapes remain losslessly Raw rather than disappearing.
In particular, a malformed non-list/non-character Rd_option value survives
as a Raw option node with its value in the Raw payload.
§8. Unknown tags and Raw handling
[Consumer guidance] Renderers SHOULD dispatch known tags and provide an
explicit fallback for Unknown, retaining its option and children. They
SHOULD NOT drop an unknown-tag subtree.
[Consumer guidance] A renderer seeing Raw SHOULD preserve or diagnose its children, payload, and attributes and SHOULD NOT claim semantic rendering of the opaque shape. Raw is not the unknown-tag category.
[AST contract] System-macro sequence views are the sole v1 exception to
the rule that semantic views never interpret Raw nodes: they may interpret
only a Raw USERMACRO marker satisfying the corpus-pinned raw-classification
guard and a structurally validated documented definition/expansion profile. All other Raw
nodes remain opaque.
§9. Malformed-tree tolerance and validation boundary
[AST contract] AST data types MUST carry malformed or unexpected child shapes losslessly; public constructors intentionally do not validate shapes.
[Consumer guidance] Lossy accessors MAY skip mismatches. Consumers needing
diagnostics SHOULD use inspect_*, which reports RdShapeError without
changing the tree.
[Consumer guidance] Singleton accessors are lossy and first-wins on
duplicates; strict counterparts report duplicates as errors. Repeatable
sections preserve source order. Custom section traversal is depth-first
preorder, and nesting is syntactic information rather than rendering policy.
Matching Raw nodes are strict errors and MUST NOT be interpreted. Orphan
subsections are outside the section view’s scope.
[AST contract] System-macro views operate on sibling sequences. Curated
Doi, CranPkg, Sspace, and I nodes consume one sibling; a validated
help-database USERMACRO doi, CRANpkg, or sspace representation consumes
the marker and its one exact expansion sibling. Lossy traversal collapses only
fully validated sequences and otherwise keeps every original node visible;
strict traversal reports definition, expansion, and unsupported-representation
mismatches without consuming an unvalidated expansion. The v1 help-database
projection does not recover \I, whose expansion is spliced into surrounding
text without a recoverable sibling boundary. Curated RdTag::I remains
available through this view family.
[AST contract] Link/list/table/equation/option validation belongs to views
and MUST NOT be inferred from RdTagged alone.
[AST contract] Example-control views preserve the direct children and exact
tag identity of \dontrun, \donttest, \dontshow, \dontdiff, and
\testonly.
[Consumer guidance] These views classify source-level wrapper shape only —
execution, visibility, testing, output-comparison, and wrapper-pattern
heuristics belong to consumers. \dontshow and \testonly remain distinct
kinds and MUST NOT be normalized together.
[AST contract] Inline-span views classify exactly \emph, \strong,
\bold, \code, \special, \verb, \url, \email, \file, \pkg,
\samp, \sQuote, \dQuote, \kbd, \var, \env, \command,
\option, \acronym, \abbr, \cite, and \dfn. They preserve direct
children and exact tag identity and assign no typography, quoting,
code-formatting, or URL behavior. One-argument macros lose their argument
group in the AST, so empty and missing arguments are not distinguished. The
views never interpret matching Raw nodes.
[AST contract] Text-symbol views preserve the exact spellings \R,
\dots, and \ldots, with plain-text fallbacks "R" and "...".
Typographic substitution is consumer policy, and the views never interpret
matching Raw nodes.
[AST contract] Conditional views expose \if as exactly two and \ifelse
as exactly three positional groups with an exact Text-scalar format
projection. Branch selection is consumer policy and branch contents are not
validated. \enc exposes exactly two groups — the encoded and ASCII
alternatives — and encoding-side selection is consumer policy. The method family (\method, \S3method, \S4method)
preserves exact spelling and two Text-scalar arguments; the following usage
signature is not part of the view. All three views never interpret matching
Raw nodes.
[AST contract] Figure views expose one or two verbatim groups with exact
Verb-scalar projections. The expert-options discriminator is the
options: prefix followed by whitespace; attribute parsing and image alt
policy are consumer policy. In an R-like \figure, the view owns only its
first brace argument and MUST NOT absorb the sibling second brace. S4-class
link views preserve class contents and optional package syntax without
generating -class topics or resolving links; the bracket option is not
restricted to a single Text node. Both views never interpret matching
Raw nodes.
[Consumer guidance] The generation-header view scans only leading top-level
Comment nodes interleaved with whitespace-only Text. A generated marker
must exactly conform to % Generated by <name>: do not edit by hand, with a
non-empty name containing no colon or line break. roxygen2 maps to the
first-class Roxygen2 generator; any other conforming name is preserved
verbatim as Unknown, and unknown generators still count as generated. The
first recognized marker determines the generator. Source-file lines and %
continuations remain the exact roxygen convention understood by this view.
Source paths are borrowed, retain source order and spelling, and are not
normalized. Non-leading, nested, and near-matching header text are not
interpreted. Roxygen fenced-code-block recognition remains converter policy
outside this view.
[Consumer guidance] Lifecycle-badge views scan every canonical top-level
\description (an explicit exception to the singleton first-wins rule) and
report all lifecycle-named figures in depth-first source order. Filename
recognition uses a case-sensitive lifecycle- basename prefix,
case-insensitive known-stage classification, and accepts any or no extension;
unknown stage spellings remain explicit. Canonical badge-shape evidence is
optional and does not change permissive recognition. Traversal follows
canonical Tagged and Group children but not options or Raw content;
matching Raw nodes and malformed lifecycle figure candidates are diagnostics
in strict inspection and are never interpreted.
§10. Source spans
[AST contract] The v1 AST has no source-span or srcref API. Consumers
MUST NOT rely on spans in RdDocument or RdNode.
[RDS producer profile] Raw-embedded srcref is producer provenance for
Raw losslessness, not a source-span API. Recognized srcref is discarded on
successful structured lowering.
§11. Stability
[AST contract] Rust consumers MUST account for #[non_exhaustive] enums
and SHOULD use public accessors rather than private layout. Additive variants
or fields are permitted by this policy.
[Non-contract note] Serde-enabled AST values round-trip within the same
crate version, as asserted by the serde tests. This serialization is
unversioned persisted interchange: cross-version wire compatibility is
explicitly not guaranteed, and it is unsuitable for long-lived storage until
a schema/version envelope exists. Borrowed semantic views and the typed option
layer have no serde support and are outside serde scope. The JSON wire shape
is independent of the R-level tag spellings returned by RdTag::as_rd_tag.
[Non-contract note] RawRdReal::Finite is not type-enforced; its
finite-value invariant is producer behavior only.
§12. Producer-profile equivalence checklist
[AST contract] Help-DB lowering and the rd-source parser are equivalent
for canonical semantics when they agree on leaf kinds and canonical leaf
strings, tag identity (including exact Unknown spelling), option
presence/content, group boundaries, order, supplied comments, and whitespace
placement.
[AST contract] This equivalence is scoped to canonical semantic nodes.
Raw provenance payloads and Raw internals are excluded, including the
corpus-pinned USERMACRO Raw shape and RawRdValue internals.
[Non-contract note] General USERMACRO remains non-canonical and its
corpus classification stays a regression guard. The four curated system-macro
profiles have the section-8/section-9 sequence-view treatment; help-database
\I is not recovered.
Modules§
- producer
- Advanced, lossless construction surface for AST producers. Normal consumers should inspect Raw values rather than synthesize them.
Structs§
- Lower
Location - RawRd
Node - A losslessly-preserved Rd node that doesn’t fit
RdNode::TaggedorRdNode::Group: it carries attributes beyond those the producer recognizes (for the RDS lowering, beyondRd_tag/Rd_optionplus the deliberately-discardedsrcref– see that module’s validated attribute policy), or has another genuinely non-canonical shape (an untagged non-list value, or an untagged node carrying anRd_option). - RawRd
Object - A recursively preserved object used by raw attribute values and lists.
- RdAlias
- A borrowed, structurally valid
\alias{...}view. - RdArgument
- A single
\item{name}{description}entry within\arguments(seeRdDocument::arguments). - RdAttribute
- A single R-level attribute attached to a raw Rd node, preserved for losslessness.
- RdConcept
- A borrowed, structurally valid
\concept{...}view. - RdConditional
- RdDelimited
Item - RdDescribed
Item - RdDocument
- A complete parsed Rd document.
- RdDynamic
Markup Iter - A depth-first pre-order dynamic-markup traversal.
The resolver deliberately mirrors R’s observable
processRdSexprssemantics: one global options state is folded in document order. Conditional markup (\\if/\\ifelse) is not branch-selected by this inspection pass, so an\\RdOptsinside an arm that a renderer would not select still affects subsequent\\Sexprresolution. - RdEffective
Sexpr Options - Fully resolved options for an Rd
\Sexprexpression. - RdEnc
- RdEquation
- A borrowed, structurally valid
\eqn{latex}{ascii}or\deqn{latex}{ascii}view. - RdExample
Control - A borrowed, structurally valid example-control wrapper view.
- RdFigure
- RdGeneration
Header - A lossy view of generation header comments at the start of a document.
- RdGroup
- An untagged positional-argument group, distinct from the
LISTpseudo-tag. - RdHref
- RdInline
Span - A borrowed source-level inline span.
- RdKeyword
- A borrowed, structurally valid
\keyword{...}view. - RdLifecycle
Badge - RdLifecycle
Badge Shape - RdLifecycle
Badges - RdLink
- RdList
- RdMethod
- A method usage node with exact Text-scalar generic and qualifier arguments.
The following call syntax
(x, ...)in\usageis not part of this method node; it remains a siblingRCodeleaf of the parent section. - RdOption
List - A parsed, borrowed Rd option list and its non-fatal diagnostics.
- RdOption
Pair - One preserved key/value pair from an option list.
- RdOpts
- A borrowed, structurally valid
\\RdOpts{options}view. - RdPath
- A human-oriented structural path through a producer’s Rd object tree.
- RdResolved
Sexpr - The result of resolving one
\\Sexpragainst document-level options. - RdS4
Class Link - A source-level
\linkS4classview. Link resolution and rendering policy belongs to consumers, and differs fromRdLink. - RdSection
- A custom
\section{title}{body}node (seeRdDocument::sections). - RdSection
Visit - A structurally valid custom section-family node in a document.
- RdSexpr
- A borrowed, structurally valid
\\Sexpr{code}view. - RdSexpr
Option Overrides - Typed overrides extracted from an Rd option list.
- RdShape
Error - A human-oriented explanation of a shape mismatch, including its path.
- RdSystem
Macro Items - RdSystem
Macro Items Strict - RdSystem
Macro Match - RdTable
Cell - One cell of a borrowed
\\tabularview. - RdTable
Row - One row of a borrowed
\\tabularview. - RdTabular
- A borrowed, structurally valid
\\tabularview. - RdTagged
- A tagged node with optional bracket content and positional children.
- RdText
Symbol - A source-level zero-argument text symbol.
- Unexpected
RawNode - Details explaining why a Raw node did not match the pinned shape.
Enums§
- Lower
Error - RawNode
Classification - The currently accepted and unexpected shapes of an RDS-lowered
Rawnode. - RawNode
Reason - Coarse structural reason for an unexpected Raw node.
- RawRd
Environment - The environment categories exposed by a producer when preserving a raw value. Environment frames are intentionally not part of the Rd AST.
- RawRd
Real - A single value in an R real vector.
- RawRd
Value - The value of a recursively preserved raw object.
- RdArity
- RdColumn
Align - Alignment of one column in a
\\tabularcolumn specification. - RdConditional
Kind - RdConstruct
- RdDynamic
Markup Event - An event emitted while resolving dynamic markup in document order.
- RdDynamic
Markup State - Resolution state for a surviving dynamic markup expression.
- RdEquation
Display - Whether an equation is rendered inline by
\eqnor as a block by\deqn. - RdExample
Control Kind - The source-level spelling of an example-control wrapper.
- RdExpected
Node - RdFigure
Second Argument - RdGenerator
- The generator that produced a documentation header.
- RdInline
Span Kind - The source-level spelling of a uniform one-argument inline markup macro.
- RdLifecycle
Stage - RdLink
Destination - RdLink
Topic - RdList
Item - RdList
Kind - RdMethod
Kind - RdNode
- A single node of an Rd document tree.
- RdNode
Kind - RdOption
Error - A hard or soft option-list diagnostic.
- RdOption
Pair Error Kind - Reasons a scalar option pair is malformed.
- RdOption
Value Kind - Expected typed value categories for known options.
- RdPath
Segment - RdSection
Kind - The kind of custom section-family node visited by
RdDocument::section_tree. - RdSexpr
Option Key - The recognized names in a
\Sexproption list. - RdSexpr
Results - An Rd
resultsvalue. - RdSexpr
Stage - An Rd
stagevalue. - RdShape
Error Kind - The shared vocabulary of shape errors returned by strict views.
- RdStrip
White - An Rd
strip.whitevalue. - RdSystem
Macro - RdSystem
Macro Item - RdSystem
Macro Origin - RdTag
- The closed vocabulary of Rd markup tags, as found in the
Rd_tagstring attribute R’sparse_Rd()attaches to each node of a parsed Rd object. - RdText
Symbol Kind - The source-level spelling of a zero-argument text symbol.
- String
Encoding
Functions§
- classify_
raw_ node - Classifies a Raw node against the RDS-producer-backed USERMACRO lowering guard.
- is_
inter_ item_ trivia - Returns whether a node is ignorable trivia between structural items.
- lower_
r_ object - Lowers a decoded help-database Rd object into the canonical AST.
- text_
contents - Lossily flattens
nodesinto a single string, discarding all markup structure.