sphinx_ultra/rst/mod.rs
1//! Recursive-descent RST parser with docutils-0.22.4 fidelity (M2 wave 1:
2//! block grammar only — the inline parser arrives in wave 2).
3//!
4//! Fidelity contract: output `pformat()` is byte-identical to
5//! `docutils.parsers.rst.Parser` parse-layer output for the construct set in
6//! `tests/fixtures/doctree_differential.json`. Transforms (doctitle
7//! promotion, target propagation, transition hoisting, message filtering)
8//! are explicitly NOT applied here; they arrive as separate components in
9//! later waves. Behavior sources: the committed differential fixture and the
10//! probe notes in docs/superpowers/plans/2026-08-07-m2-wave1-probes.md.
11
12mod block;
13pub mod lines;
14
15use crate::doctree::Doctree;
16
17#[derive(Debug, Clone)]
18pub struct ParseOptions {
19 /// What `<document source="...">` prints (docutils `new_document` name).
20 pub source_path: String,
21}
22
23impl Default for ParseOptions {
24 fn default() -> Self {
25 ParseOptions {
26 source_path: "<string>".to_string(),
27 }
28 }
29}
30
31/// Parse RST source into a doctree. Total: never panics, never errors —
32/// problems become `system_message` nodes, exactly like docutils.
33pub fn parse_rst(source: &str, opts: &ParseOptions) -> Doctree {
34 let lines = lines::Lines::new(source);
35 let root = block::BlockParser::new(&lines, &opts.source_path, source.len()).parse_document();
36 Doctree { root }
37}