Skip to main content

jsslint_core/tex/
mod.rs

1//! Tolerant LaTeX parsing substrate — spec 018 Phase 1. Ports
2//! `pylatexenc.latexwalker`'s node model (`node.rs`, `parser.rs`),
3//! `core/parser.py`'s pre-tokenization neutralization
4//! (`neutralize.rs`), `pos_to_lineno_colno` (`position.rs`), and
5//! `_helpers.py`'s prose-context classifier (`prose.rs`).
6//!
7//! No rules live here yet (Phase 3) — this module's job is only to
8//! prove the substrate matches, validated by `tests/parser_parity.rs`
9//! against a Python oracle dump (`tools/dump_tex_nodes.py`).
10
11pub mod debug;
12pub mod extract;
13pub mod neutralize;
14pub mod node;
15pub mod parser;
16pub mod position;
17pub mod prose;
18mod specs;
19
20pub use node::*;
21pub use position::LineIndex;
22
23/// Full `.tex` parse pipeline, mirroring
24/// `core/parser.py::parse_tex_source`'s preprocessing + tokenize order
25/// (tolerant-parsing path only — see `parser::parse`'s doc comment).
26pub struct ParsedTex {
27    pub source: String,
28    pub chars: Vec<char>,
29    pub nodes: Vec<Node>,
30    /// Zero for a normal `.tex`/`.rnw` file. Non-zero for a `.Rmd`
31    /// raw-LaTeX prose fragment (see `crate::rmd`): `chars`/`node.pos`
32    /// stay 0-based within the fragment's own (unpadded) text — same
33    /// as Python's `node.pos`, which `_OffsetWalker` never touches —
34    /// while every rule module's `LineIndex::with_offset(&parsed.chars,
35    /// parsed.line_offset)` call adds this back in so reported lines
36    /// stay source-accurate on the original `.Rmd`.
37    pub line_offset: u32,
38}
39
40pub fn parse_tex_source(source: &str) -> ParsedTex {
41    let preprocessed = neutralize::preprocess(source);
42    let (nodes, chars) = parser::parse(&preprocessed);
43    ParsedTex {
44        source: preprocessed,
45        chars,
46        nodes,
47        line_offset: 0,
48    }
49}