Skip to main content

jsslint_core/tex/
node.rs

1//! LaTeX AST node types — mirrors the subset of `pylatexenc.latexwalker`
2//! node kinds this codebase's rules actually consume (see
3//! `_helpers.py`'s imports: `LatexCharsNode`, `LatexCommentNode`,
4//! `LatexEnvironmentNode`, `LatexGroupNode`, `LatexMacroNode`,
5//! `LatexMathNode`).
6//!
7//! **Positions are Unicode codepoint offsets, not byte offsets** —
8//! matching Python `str` indexing (which is what `pylatexenc.pos`/`.len`
9//! and `Fix.start`/`.end` actually are; see the correction in
10//! `report.rs`'s `Fix` doc comment). A `Vec<char>` is the parser's
11//! working representation of the source for exactly this reason.
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct Span {
15    pub pos: usize,
16    pub len: usize,
17}
18
19impl Span {
20    pub fn end(&self) -> usize {
21        self.pos + self.len
22    }
23}
24
25#[derive(Debug, Clone)]
26pub enum Node {
27    Chars(CharsNode),
28    Comment(CommentNode),
29    Macro(MacroNode),
30    Group(GroupNode),
31    Environment(EnvironmentNode),
32    Math(MathNode),
33    Specials(SpecialsNode),
34}
35
36impl Node {
37    pub fn span(&self) -> Span {
38        match self {
39            Node::Chars(n) => n.span,
40            Node::Comment(n) => n.span,
41            Node::Macro(n) => n.span,
42            Node::Group(n) => n.span,
43            Node::Environment(n) => n.span,
44            Node::Math(n) => n.span,
45            Node::Specials(n) => n.span,
46        }
47    }
48}
49
50#[derive(Debug, Clone)]
51pub struct CharsNode {
52    pub span: Span,
53    pub chars: String,
54}
55
56/// A literal token pylatexenc tokenizes as its own node rather than
57/// plain characters or a macro: `~`, `&`, `--`, `---`, `` `` ``, `''`,
58/// `` !` ``, `` ?` ``. Takes no arguments in the default database.
59#[derive(Debug, Clone)]
60pub struct SpecialsNode {
61    pub span: Span,
62    pub chars: String,
63}
64
65#[derive(Debug, Clone)]
66pub struct CommentNode {
67    pub span: Span,
68    pub comment: String,
69}
70
71/// One argument slot's parse result, aligned 1:1 with the macro/env's
72/// argspec string. `None` means an optional (`[` or `*`) slot that
73/// wasn't present at the call site — mirrors `argnlist`'s `None`
74/// entries in pylatexenc.
75pub type Args = Vec<Option<Node>>;
76
77#[derive(Debug, Clone)]
78pub struct MacroNode {
79    pub span: Span,
80    pub macroname: String,
81    pub args: Args,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum GroupDelims {
86    /// `{...}` — an ordinary brace group.
87    Brace,
88    /// `[...]` — an optional-argument bracket group.
89    Bracket,
90}
91
92#[derive(Debug, Clone)]
93pub struct GroupNode {
94    pub span: Span,
95    pub delims: GroupDelims,
96    pub nodelist: Vec<Node>,
97}
98
99#[derive(Debug, Clone)]
100pub struct EnvironmentNode {
101    pub span: Span,
102    pub environmentname: String,
103    pub args: Args,
104    pub nodelist: Vec<Node>,
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum MathKind {
109    /// `$...$` or `\(...\)`.
110    Inline,
111    /// `$$...$$` or `\[...\]`.
112    Display,
113}
114
115#[derive(Debug, Clone)]
116pub struct MathNode {
117    pub span: Span,
118    pub kind: MathKind,
119    pub nodelist: Vec<Node>,
120}