katex/parser/
parse_node.rs

1//! Parse node type definitions for KaTeX AST representation
2//!
3//! This module contains the Rust equivalents of the JavaScript Flow type
4//! definitions for parse nodes, which form the core of KaTeX's Abstract Syntax
5//! Tree (AST).
6
7use crate::build_html::DomType;
8use crate::spacing_data::MeasurementOwned;
9use crate::style::Style;
10use crate::symbols::Atom;
11use crate::types::{Mode, SourceLocation, Token};
12
13use crate::namespace::KeyMap;
14use strum::{AsRefStr, Display, EnumDiscriminants};
15use thiserror::Error;
16
17/// Represents the different types of column separation used in array
18/// environments within LaTeX/KaTeX mathematical expressions.
19///
20/// This enum defines the various alignment and separation styles that can be
21/// applied to columns in array-like structures, such as matrices or tables in
22/// mathematical typesetting. Each variant corresponds to a specific LaTeX array
23/// column type and influences how spacing and alignment are handled during
24/// rendering.
25///
26/// # Examples
27///
28/// In LaTeX source:
29/// ```latex
30/// \begin{pmatrix} a & b \\ c & d \end{pmatrix}  // Uses Align or Gather
31/// \begin{alignat}{2} x &= 1 \\ y &= 2 \end{alignat}  // Uses Alignat
32/// ```
33///
34/// # Usage
35///
36/// Used internally by the parser when constructing [`ParseNodeArray`] nodes to
37/// specify how columns should be separated and aligned. The choice affects
38/// spacing calculations and rendering behavior in the final output.
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum ColSeparationType {
41    /// Standard alignment with default spacing, typically centered columns
42    Align,
43    /// Alignment with specific left/right positioning, often used for equation
44    /// arrays
45    Alignat,
46    /// Gathering style with centered columns and appropriate spacing
47    Gather,
48    /// Compact spacing for dense arrays
49    Small,
50    /// Special handling for commutative diagram environments
51    CD,
52}
53
54/// Specifies the alignment and spacing properties for individual columns in
55/// array environments.
56///
57/// This enum provides detailed control over how each column in a mathematical
58/// array (matrix, table, etc.) should be aligned and spaced. It supports both
59/// simple separator-based alignment and more complex alignment specifications
60/// with custom gaps.
61///
62/// # Usage
63///
64/// Used in [`ParseNodeArray`] to define column properties. The alignment
65/// affects how mathematical expressions are positioned within each cell of the
66/// array structure.
67#[derive(Debug, Clone, PartialEq)]
68pub enum AlignSpec {
69    /// Simple alignment using a separator string (e.g., "|", ":", etc.)
70    Separator {
71        /// The string used to separate or align the column (e.g., "|", ":",
72        /// etc.)
73        separator: String,
74    },
75    /// Advanced alignment with custom spacing
76    Align {
77        /// The alignment string (e.g., "c", "l", "r" for center/left/right)
78        align: String,
79        /// Optional space before the column content (in em units)
80        pregap: Option<f64>,
81        /// Optional space after the column content (in em units)
82        postgap: Option<f64>,
83    },
84}
85
86/// The core Abstract Syntax Tree (AST) node type for KaTeX mathematical
87/// expressions.
88///
89/// This enum represents all possible parse nodes that can appear in a parsed
90/// LaTeX/KaTeX mathematical expression. Each variant corresponds to a specific
91/// type of mathematical construct, from simple symbols to complex structures
92/// like arrays and fractions.
93///
94/// The AST is built during parsing and represents the hierarchical structure of
95/// mathematical expressions, which is then used for rendering and further
96/// processing.
97///
98/// # Architecture
99///
100/// The enum uses the `strum` crate for discriminant generation, allowing
101/// runtime type checking and serialization. The [`NodeType`] discriminant
102/// provides a way to identify node types without pattern matching.
103///
104/// # Usage
105///
106/// Parse nodes are typically created by the parser from LaTeX input and then
107/// processed by the rendering engine. They can be traversed, transformed, and
108/// analyzed using the provided utility functions.
109///
110/// # See Also
111///
112/// * [`NodeType`] - The discriminant type for runtime type checking
113/// * [`assert_node_type`] - Type assertion utility
114/// * [`ParseNode`] - Type alias for this enum
115#[derive(Debug, Clone, PartialEq, EnumDiscriminants)]
116#[strum_discriminants(vis(pub))]
117#[strum_discriminants(doc = "Discriminant type for runtime type checking of parse nodes")]
118#[strum_discriminants(derive(Display, Hash, AsRefStr), strum(serialize_all = "lowercase"))]
119#[strum_discriminants(name(NodeType))]
120pub enum AnyParseNode {
121    /// ## Structural Nodes
122    /// Array/matrix environments with rows and columns
123    Array(ParseNodeArray),
124    /// Ordered groups of expressions (parentheses, etc.)
125    OrdGroup(ParseNodeOrdGroup),
126    /// Superscript/subscript combinations
127    SupSub(ParseNodeSupSub),
128    /// Generalized fractions (fractions, binomials)
129    Genfrac(Box<ParseNodeGenfrac>),
130    /// Left-right delimiter pairs
131    LeftRight(ParseNodeLeftRight),
132    #[strum_discriminants(strum(serialize = "leftright-right"))]
133    /// Right delimiters in left-right delimiter pairs (\left...\right).
134    LeftRightRight(ParseNodeLeftRightRight),
135    /// Square roots and nth roots
136    Sqrt(Box<ParseNodeSqrt>),
137
138    /// ## Symbol Nodes
139    /// Atomic symbols with specific mathematical meaning
140    Atom(ParseNodeAtom),
141    /// Ordinary mathematical symbols
142    MathOrd(ParseNodeMathOrd),
143    /// Mathematical operators
144    Op(ParseNodeOp),
145    /// Explicit spacing elements
146    Spacing(ParseNodeSpacing),
147
148    /// ## Text and Styling
149    /// Text content within math
150    Text(ParseNodeText),
151    /// Style changes (bold, italic, etc.)
152    Styling(ParseNodeStyling),
153    /// Font family changes
154    Font(ParseNodeFont),
155    /// Color specifications
156    Color(ParseNodeColor),
157
158    /// ## Functions and Commands
159    /// Accents over symbols (hats, bars, etc.)
160    Accent(Box<ParseNodeAccent>),
161    /// Horizontal lines on top of expressions
162    Overline(ParseNodeOverline),
163    /// Horizontal lines below expressions
164    Underline(ParseNodeUnderline),
165    /// Invisible content for spacing or alignment
166    Phantom(ParseNodePhantom),
167    /// Horizontal phantom content for spacing (\hphantom{...}).
168    Hphantom(ParseNodeHphantom),
169    /// Vertical phantom content for spacing (\vphantom{...}).
170    Vphantom(ParseNodeVphantom),
171    /// Horizontal/vertical rules
172    Rule(ParseNodeRule),
173
174    /// ## Miscellaneous Nodes
175    /// Labels for arrows in commutative diagram environments
176    /// (\begin{CD}...\end{CD}).
177    CdLabel(ParseNodeCdLabel),
178    /// Parent containers for CD labels in commutative diagrams.
179    CdLabelParent(ParseNodeCdLabelParent),
180    #[strum_discriminants(strum(serialize = "color-token"))]
181    /// Color tokens for setting current color context (\color{name}).
182    ColorToken(ParseNodeColorToken),
183    /// Raw content passed through without mathematical processing.
184    Raw(ParseNodeRaw),
185    /// Size specifications for spacing and dimensions (\rule, spacing
186    /// commands).
187    Size(ParseNodeSize),
188    /// Tagged equations with labels (\tag{label} or automatic numbering).
189    Tag(ParseNodeTag),
190    /// Hyperlinks in mathematical expressions (\url{...}).
191    Url(ParseNodeUrl),
192    /// Verbatim text preserving exact formatting (\verb|text| or
193    /// \begin{verbatim}...\end{verbatim}).
194    Verb(ParseNodeVerb),
195    /// Ordinary text symbols in math mode (letters, punctuation).
196    TextOrd(ParseNodeTextOrd),
197    #[strum_discriminants(strum(serialize = "accent-token"))]
198    /// Accent symbols for diacritical marks (\hat, \bar, \tilde, etc.).
199    AccentToken(ParseNodeAccentToken),
200    #[strum_discriminants(strum(serialize = "op-token"))]
201    /// Operator symbols with special positioning (\sum, \int, \lim, etc.).
202    OpToken(ParseNodeOpToken),
203    #[strum_discriminants(strum(serialize = "accentUnder"))]
204    /// Accent marks placed below expressions (\underline, \underbar, etc.).
205    AccentUnder(Box<ParseNodeAccentUnder>),
206    /// Carriage returns and line breaks (\\, \newline).
207    Cr(ParseNodeCr),
208    /// Delimiter sizing for proper enclosure (\big, \Big, \bigg, etc.).
209    Delimsizing(ParseNodeDelimsizing),
210    /// Enclosed expressions with styling (\boxed, \colorbox, etc.).
211    Enclose(ParseNodeEnclose),
212    /// Custom mathematical environments (\begin{env}...\end{env}).
213    Environment(Box<ParseNodeEnvironment>),
214    /// Horizontal boxes for grouping content (\hbox{...}).
215    Hbox(ParseNodeHbox),
216    /// Horizontal braces above/below expressions (\overbrace, \underbrace).
217    HorizBrace(ParseNodeHorizBrace),
218    /// Hyperlinks with custom text (\href{url}{text}).
219    Href(ParseNodeHref),
220    /// Embedded HTML content within math expressions.
221    Html(ParseNodeHtml),
222    /// Content renderable in both HTML and MathML formats.
223    HtmlMathMl(ParseNodeHtmlMathMl),
224    /// Included graphics/images (\includegraphics{...}).
225    Includegraphics(ParseNodeIncludegraphics),
226    /// Custom infix operators between operands.
227    Infix(ParseNodeInfix),
228    /// Internal parser nodes for implementation details.
229    Internal(ParseNodeInternal),
230    /// Explicit kerning/spacing adjustments (\kern, \mkern).
231    Kern(ParseNodeKern),
232    /// Overlapping content for annotations (\rlap, \llap, \clap).
233    Lap(ParseNodeLap),
234    /// Different renderings for display/text/script modes
235    /// (\mathchoice{...}{...}{...}{...}).
236    MathChoice(ParseNodeMathChoice),
237    /// Middle delimiters in expressions (\middle|).
238    Middle(ParseNodeMiddle),
239    /// Math class specifications for spacing and rendering (mord, mbin, mrel,
240    /// etc.).
241    Mclass(ParseNodeMclass),
242    /// Operator names with special formatting (\operatorname{...}).
243    OperatorName(ParseNodeOperatorName),
244    /// Poor man's bold text formatting (\pmb{...}).
245    Pmb(ParseNodePmb),
246    /// Raised or lowered content (\raisebox{...}{...}).
247    Raisebox(ParseNodeRaisebox),
248    /// Size changes for expressions (\scriptsize, \large, etc.).
249    Sizing(ParseNodeSizing),
250    /// Smashed content ignoring height/depth (\smash{...}).
251    Smash(ParseNodeSmash),
252    /// Vertically centered content (\vcenter{...}).
253    Vcenter(ParseNodeVcenter),
254    #[strum_discriminants(strum(serialize = "x-arrow"))]
255    /// Extensible arrows with labels (\xleftarrow{...}, \xrightarrow{...}).
256    XArrow(ParseNodeXArrow),
257}
258
259impl AnyParseNode {
260    /// TeXbook algorithms often reference "character boxes", which are simply
261    /// groups with a single character in them. To decide if something is a
262    /// character box, we find its innermost group, and see if it is a
263    /// single character.
264    ///
265    /// This is equivalent to `utils.isCharacterBox` in the JS codebase.
266    pub fn is_character_box(&self) -> Result<bool, ParseNodeError> {
267        let base_elem = self.to_base_elem()?;
268        Ok(matches!(
269            base_elem,
270            Self::MathOrd { .. } | Self::TextOrd { .. } | Self::Atom { .. }
271        ))
272    }
273
274    /// Sometimes we want to pull out the innermost element of a group. In most
275    /// cases, this will just be the group itself, but when ordgroups and colors
276    /// have a single element, we want to pull that out.
277    ///
278    /// This is equivalent to `utils.getBaseElem` in the JS codebase.
279    pub fn to_base_elem(&self) -> Result<&Self, ParseNodeError> {
280        match self {
281            Self::OrdGroup(ord) => {
282                if ord.body.len() == 1 {
283                    ord.body[0].to_base_elem()
284                } else {
285                    Ok(self)
286                }
287            }
288            Self::Color(color) => {
289                if color.body.len() == 1 {
290                    color.body[0].to_base_elem()
291                } else {
292                    Ok(self)
293                }
294            }
295            Self::Font(font) => font.body.to_base_elem(),
296            _ => Ok(self),
297        }
298    }
299
300    /// Get the mode of current node
301    #[must_use]
302    pub fn mode(&self) -> Mode {
303        match self {
304            Self::Array(node) => node.mode,
305            Self::OrdGroup(node) => node.mode,
306            Self::SupSub(node) => node.mode,
307            Self::Genfrac(node) => node.mode,
308            Self::LeftRight(node) => node.mode,
309            Self::LeftRightRight(node) => node.mode,
310            Self::Sqrt(node) => node.mode,
311            Self::Atom(node) => node.mode,
312            Self::MathOrd(node) => node.mode,
313            Self::Op(op) => match op {
314                ParseNodeOp::Symbol { mode, .. } | ParseNodeOp::Body { mode, .. } => *mode,
315            },
316            Self::Spacing(node) => node.mode,
317            Self::Text(node) => node.mode,
318            Self::Styling(node) => node.mode,
319            Self::Font(node) => node.mode,
320            Self::Color(node) => node.mode,
321            Self::Accent(node) => node.mode,
322            Self::Overline(node) => node.mode,
323            Self::Underline(node) => node.mode,
324            Self::Phantom(node) => node.mode,
325            Self::Hphantom(node) => node.mode,
326            Self::Vphantom(node) => node.mode,
327            Self::Rule(node) => node.mode,
328            Self::CdLabel(node) => node.mode,
329            Self::CdLabelParent(node) => node.mode,
330            Self::ColorToken(node) => node.mode,
331            Self::Raw(node) => node.mode,
332            Self::Size(node) => node.mode,
333            Self::Tag(node) => node.mode,
334            Self::Url(node) => node.mode,
335            Self::Verb(node) => node.mode,
336            Self::TextOrd(node) => node.mode,
337            Self::AccentToken(node) => node.mode,
338            Self::OpToken(node) => node.mode,
339            Self::AccentUnder(node) => node.mode,
340            Self::Cr(node) => node.mode,
341            Self::Delimsizing(node) => node.mode,
342            Self::Enclose(node) => node.mode,
343            Self::Environment(node) => node.mode,
344            Self::Hbox(node) => node.mode,
345            Self::HorizBrace(node) => node.mode,
346            Self::Href(node) => node.mode,
347            Self::Html(node) => node.mode,
348            Self::HtmlMathMl(node) => node.mode,
349            Self::Includegraphics(node) => node.mode,
350            Self::Infix(node) => node.mode,
351            Self::Internal(node) => node.mode,
352            Self::Kern(node) => node.mode,
353            Self::Lap(node) => node.mode,
354            Self::MathChoice(node) => node.mode,
355            Self::Middle(node) => node.mode,
356            Self::Mclass(node) => node.mode,
357            Self::OperatorName(node) => node.mode,
358            Self::Pmb(node) => node.mode,
359            Self::Raisebox(node) => node.mode,
360            Self::Sizing(node) => node.mode,
361            Self::Smash(node) => node.mode,
362            Self::Vcenter(node) => node.mode,
363            Self::XArrow(node) => node.mode,
364        }
365    }
366
367    /// Get the text field of the node
368    ///
369    /// `checkSymbolNodeType` checks if the node is a symbol and returns its
370    /// text later in Javascript.
371    #[must_use]
372    pub fn text(&self) -> Option<&str> {
373        match self {
374            // Atom
375            Self::Atom(node) => Some(&node.text),
376            // Non-Atom
377            Self::AccentToken(node) => Some(&node.text),
378            Self::MathOrd(node) => Some(&node.text),
379            Self::OpToken(node) => Some(&node.text),
380            Self::Spacing(node) => Some(&node.text),
381            Self::TextOrd(node) => Some(&node.text),
382            _ => None,
383        }
384    }
385
386    /// Get the label field of the node
387    #[must_use]
388    pub fn label(&self) -> Option<&str> {
389        match self {
390            Self::Accent(acc) => Some(&acc.label),
391            Self::AccentUnder(acc_under) => Some(&acc_under.label),
392            Self::HorizBrace(hb) => Some(&hb.label),
393            Self::XArrow(xa) => Some(&xa.label),
394            Self::Enclose(enclose) => Some(&enclose.label),
395            _ => None,
396        }
397    }
398}
399
400/// The array item of tags in array
401#[derive(Debug, Clone, PartialEq)]
402pub enum ParseNodeArrayTag {
403    /// A boolean value indicating if the tag is active
404    Bool(bool),
405    /// A list of nodes associated with the tag
406    Nodes(Vec<AnyParseNode>),
407}
408
409impl From<Vec<AnyParseNode>> for ParseNodeArrayTag {
410    fn from(nodes: Vec<AnyParseNode>) -> Self {
411        Self::Nodes(nodes)
412    }
413}
414
415impl From<bool> for ParseNodeArrayTag {
416    fn from(b: bool) -> Self {
417        Self::Bool(b)
418    }
419}
420
421impl ParseNodeArrayTag {
422    /// If is true or has nodes
423    #[must_use]
424    pub const fn is_true(&self) -> bool {
425        match self {
426            Self::Bool(b) => *b,
427            // In Javascript, `[]` is true
428            Self::Nodes(_) => true,
429        }
430    }
431}
432
433/// Represents array and matrix environments in mathematical expressions.
434///
435/// This struct handles the parsing and representation of array-like structures
436/// such as matrices, tables, and aligned equations in LaTeX/KaTeX. It supports
437/// various column alignments, spacing, and formatting options.
438///
439/// # LaTeX Correspondence
440///
441/// Corresponds to LaTeX environments like:
442/// ```latex
443/// \begin{pmatrix} a & b \\ c & d \end{pmatrix}  % Matrix
444/// \begin{array}{cc} a & b \\ c & d \end{array}  % General array
445/// \begin{align} x &= 1 \\ y &= 2 \end{align}    % Aligned equations
446/// ```
447///
448/// # Usage
449///
450/// Arrays are fundamental for representing matrices, systems of equations, and
451/// tabular data in mathematical typesetting. The parser creates these nodes
452/// when encountering array environments.
453#[derive(Debug, Clone, PartialEq)]
454pub struct ParseNodeArray {
455    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
456    pub mode: Mode,
457    /// Optional source location for error reporting
458    pub loc: Option<SourceLocation>,
459    /// Type of column separation ([`ColSeparationType`])
460    pub col_separation_type: Option<ColSeparationType>,
461    /// Whether to add horizontal skip before/after the array
462    pub hskip_before_and_after: Option<bool>,
463    /// Whether to add extra vertical spacing between rows
464    pub add_jot: Option<bool>,
465    /// Column alignment specifications ([`AlignSpec`])
466    pub cols: Option<Vec<AlignSpec>>,
467    /// Vertical stretching factor for the array
468    pub arraystretch: f64,
469    /// The array content as a vector of rows, each containing cells
470    pub body: Vec<Vec<AnyParseNode>>,
471    /// Vertical gaps between rows
472    pub row_gaps: Vec<Option<MeasurementOwned>>,
473    /// Horizontal lines to draw before each row
474    pub h_lines_before_row: Vec<Vec<bool>>,
475    /// Optional equation tags/numbers for each row
476    pub tags: Option<Vec<ParseNodeArrayTag>>,
477    /// Whether to place equation numbers on the left
478    pub leqno: Option<bool>,
479    /// Whether this is a commutative diagram array
480    pub is_cd: Option<bool>,
481}
482
483/// Represents labels in commutative diagram (CD) environments.
484///
485/// This struct handles labels attached to arrows or objects in commutative
486/// diagrams, which are specialized mathematical diagrams showing relationships
487/// between objects.
488///
489/// # Fields
490///
491/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
492/// * `loc` - Optional source location for error reporting
493/// * `side` - The side of the arrow/object where the label appears ("top",
494///   "bottom", "left", "right")
495/// * `label` - The mathematical expression serving as the label
496///
497/// # LaTeX Correspondence
498///
499/// Used in CD environments:
500/// ```latex
501/// \begin{CD}
502/// A @>f>> B
503/// @VVgV @VVhV
504/// C @>>k> D
505/// \end{CD}
506/// ```
507///
508/// # Usage
509///
510/// CD labels provide annotations for arrows and objects in commutative
511/// diagrams, helping to clarify the mathematical relationships being depicted.
512#[derive(Debug, Clone, PartialEq)]
513pub struct ParseNodeCdLabel {
514    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
515    pub mode: Mode,
516    /// Optional source location for error reporting
517    pub loc: Option<SourceLocation>,
518    /// The side of the arrow/object where the label appears ("top", "bottom",
519    /// "left", "right")
520    pub side: String,
521    /// The mathematical expression serving as the label
522    pub label: Box<AnyParseNode>,
523}
524
525/// Represents parent containers for CD labels in commutative diagrams.
526///
527/// This struct serves as a wrapper for fragments that contain CD labels,
528/// maintaining the hierarchical structure of commutative diagram elements.
529///
530/// # Fields
531///
532/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
533/// * `loc` - Optional source location for error reporting
534/// * `fragment` - The contained mathematical expression or diagram fragment
535///
536/// # Usage
537///
538/// Used internally to maintain proper nesting and structure in commutative
539/// diagram parsing. The fragment typically contains the arrow or object being
540/// labeled.
541#[derive(Debug, Clone, PartialEq)]
542pub struct ParseNodeCdLabelParent {
543    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
544    pub mode: Mode,
545    /// Optional source location for error reporting
546    pub loc: Option<SourceLocation>,
547    /// The contained mathematical expression or diagram fragment
548    pub fragment: Box<AnyParseNode>,
549}
550
551/// Represents color changes applied to mathematical expressions.
552///
553/// This struct wraps mathematical content with color specifications, allowing
554/// different parts of expressions to be rendered in different colors.
555///
556/// # Fields
557///
558/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
559/// * `loc` - Optional source location for error reporting
560/// * `color` - The color specification (name, hex code, or RGB values)
561/// * `body` - The mathematical expressions to be colored
562///
563/// # LaTeX Correspondence
564///
565/// Corresponds to LaTeX color commands:
566/// ```latex
567/// \color{red}{x + y}
568/// {\color{blue} \frac{a}{b}}
569/// ```
570///
571/// # Usage
572///
573/// Color nodes allow visual distinction of different parts of mathematical
574/// expressions, useful for highlighting important terms or distinguishing
575/// different variables.
576#[derive(Debug, Clone, PartialEq)]
577pub struct ParseNodeColor {
578    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
579    pub mode: Mode,
580    /// Optional source location for error reporting
581    pub loc: Option<SourceLocation>,
582    /// The color specification (name, hex code, or RGB values)
583    pub color: String,
584    /// The mathematical expressions to be colored
585    pub body: Vec<AnyParseNode>,
586}
587
588impl From<ParseNodeColor> for AnyParseNode {
589    fn from(node: ParseNodeColor) -> Self {
590        Self::Color(node)
591    }
592}
593
594/// Represents color tokens in mathematical expressions.
595///
596/// This struct handles standalone color specifications that don't wrap content,
597/// typically used for setting the current color context.
598///
599/// # Fields
600///
601/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
602/// * `loc` - Optional source location for error reporting
603/// * `color` - The color specification string
604///
605/// # Usage
606///
607/// Used for color commands that set the current color without immediately
608/// applying it to content, allowing subsequent expressions to inherit the
609/// color.
610#[derive(Debug, Clone, PartialEq, Eq)]
611pub struct ParseNodeColorToken {
612    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
613    pub mode: Mode,
614    /// Optional source location for error reporting
615    pub loc: Option<SourceLocation>,
616    /// The color specification string
617    pub color: String,
618}
619
620/// Represents mathematical operators in KaTeX expressions, supporting both
621/// symbolic and compound operators.
622///
623/// This enum handles operators that can appear in mathematical expressions,
624/// including those with limits (subscripts/superscripts above/below) and those
625/// that contain other expressions as their body.
626///
627/// # Usage
628///
629/// Used for operators like `\sum`, `\int`, `\lim`, etc. The `limits` field
630/// controls whether sub/super scripts appear as limits (above/below) or as
631/// regular scripts (right side).
632///
633/// # LaTeX Examples
634///
635/// ```latex
636/// \sum_{i=1}^{n} x_i     % limits = true
637/// \int_a^b f(x) dx      % limits = false (default)
638/// \lim_{x \to 0} f(x)   % limits = true
639/// ```
640#[derive(Debug, Clone, PartialEq)]
641pub enum ParseNodeOp {
642    /// A simple operator symbol with optional limit positioning
643    Symbol {
644        /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
645        mode: Mode,
646        /// Optional source location for error reporting
647        loc: Option<SourceLocation>,
648        /// Whether limits should be displayed above/below (true) or as
649        /// sub/super scripts (false)
650        limits: bool,
651        /// Force special handling of adjacent superscripts/subscripts
652        always_handle_sup_sub: Option<bool>,
653        /// Suppress vertical shifting of the base symbol
654        suppress_base_shift: Option<bool>,
655        /// Whether this operator is part of a sup/sub script context
656        parent_is_sup_sub: bool,
657        /// The operator name/symbol (e.g., "sum", "lim", "int")
658        name: String,
659        /// Whether it is a symbol
660        symbol: bool,
661    },
662    /// An operator that contains other expressions as its body
663    Body {
664        /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
665        mode: Mode,
666        /// Optional source location for error reporting
667        loc: Option<SourceLocation>,
668        /// Whether limits should be displayed above/below (true) or as
669        /// sub/super scripts (false)
670        limits: bool,
671        /// Force special handling of adjacent superscripts/subscripts
672        always_handle_sup_sub: Option<bool>,
673        /// Suppress vertical shifting of the base symbol
674        suppress_base_shift: Option<bool>,
675        /// Whether this operator is part of a sup/sub script context
676        parent_is_sup_sub: bool,
677        /// The expressions that form the operator's content
678        body: Vec<AnyParseNode>,
679    },
680}
681
682impl ParseNodeOp {
683    /// Get the limits field
684    #[must_use]
685    pub const fn limits(&self) -> bool {
686        match self {
687            Self::Symbol { limits, .. } | Self::Body { limits, .. } => *limits,
688        }
689    }
690
691    /// Mutate the limits field
692    #[must_use]
693    pub const fn limits_mut(&mut self) -> &mut bool {
694        match self {
695            Self::Symbol { limits, .. } | Self::Body { limits, .. } => limits,
696        }
697    }
698
699    /// Get the always_handle_sup_sub field
700    #[must_use]
701    pub fn always_handle_sup_sub(&self) -> bool {
702        let field = match self {
703            Self::Symbol {
704                always_handle_sup_sub,
705                ..
706            }
707            | Self::Body {
708                always_handle_sup_sub,
709                ..
710            } => *always_handle_sup_sub,
711        };
712        field.unwrap_or(false)
713    }
714
715    /// Mutate the always_handle_sup_sub field
716    #[must_use]
717    pub const fn always_handle_sup_sub_mut(&mut self) -> &mut Option<bool> {
718        match self {
719            Self::Symbol {
720                always_handle_sup_sub,
721                ..
722            }
723            | Self::Body {
724                always_handle_sup_sub,
725                ..
726            } => always_handle_sup_sub,
727        }
728    }
729
730    /// Get the name field
731    #[must_use]
732    pub fn name(&self) -> Option<&str> {
733        match self {
734            Self::Symbol { name, .. } => Some(name),
735            Self::Body { .. } => None,
736        }
737    }
738}
739
740/// Represents ordered groups of mathematical expressions, typically enclosed in
741/// parentheses or brackets.
742///
743/// This struct handles grouped expressions that should be treated as a single
744/// unit, such as parenthesized subexpressions or bracketed terms.
745///
746/// # Fields
747///
748/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
749/// * `loc` - Optional source location for error reporting
750/// * `body` - The expressions contained within the group
751/// * `semisimple` - Whether this is a simple grouping (affects spacing and
752///   rendering)
753///
754/// # LaTeX Correspondence
755///
756/// Corresponds to grouped expressions:
757/// ```latex
758/// (x + y)    % Parentheses
759/// {a + b}    % Braces
760/// [c + d]    % Brackets
761/// ```
762///
763/// # Usage
764///
765/// OrdGroups ensure proper precedence and grouping in mathematical expressions,
766/// affecting both parsing order and visual rendering with appropriate
767/// delimiters.
768#[derive(Debug, Clone, PartialEq)]
769pub struct ParseNodeOrdGroup {
770    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
771    pub mode: Mode,
772    /// Optional source location for error reporting
773    pub loc: Option<SourceLocation>,
774    /// The expressions contained within the group
775    pub body: Vec<AnyParseNode>,
776    /// Whether this is a simple grouping (affects spacing and rendering)
777    pub semisimple: Option<bool>,
778}
779
780/// Represents raw, unprocessed content in mathematical expressions.
781///
782/// This struct contains literal text or content that should be passed through
783/// without further mathematical processing or rendering.
784///
785/// # Fields
786///
787/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
788/// * `loc` - Optional source location for error reporting
789/// * `string` - The raw string content
790///
791/// # Usage
792///
793/// Used for content that needs to be preserved exactly as-is, such as
794/// literal text within math mode or special formatting commands.
795#[derive(Debug, Clone, PartialEq, Eq)]
796pub struct ParseNodeRaw {
797    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
798    pub mode: Mode,
799    /// Optional source location for error reporting
800    pub loc: Option<SourceLocation>,
801    /// The raw string content
802    pub string: String,
803}
804
805/// Represents size specifications for spacing or dimensions in mathematical
806/// expressions.
807///
808/// This struct handles explicit size measurements used for spacing, rules, or
809/// other dimensional elements in mathematical typesetting.
810///
811/// # Fields
812///
813/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
814/// * `loc` - Optional source location for error reporting
815/// * `value` - The size measurement ([`MeasurementOwned`])
816/// * `is_blank` - Whether this represents a blank/zero size
817///
818/// # Usage
819///
820/// Size nodes control the dimensions of various elements like rules, spacing,
821/// and other measurable components in mathematical layouts.
822#[derive(Debug, Clone, PartialEq)]
823pub struct ParseNodeSize {
824    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
825    pub mode: Mode,
826    /// Optional source location for error reporting
827    pub loc: Option<SourceLocation>,
828    /// The size measurement ([`MeasurementOwned`])
829    pub value: MeasurementOwned,
830    /// Whether this represents a blank/zero size
831    pub is_blank: bool,
832}
833
834/// Represents style changes applied to mathematical expressions.
835///
836/// This struct wraps mathematical content with style specifications like bold,
837/// italic, or other text styling attributes.
838///
839/// # Fields
840///
841/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
842/// * `loc` - Optional source location for error reporting
843/// * `style` - The style specification ([`Style`])
844/// * `body` - The expressions to be styled
845///
846/// # LaTeX Correspondence
847///
848/// Corresponds to LaTeX styling commands:
849/// ```latex
850/// \mathbf{x}    % Bold
851/// \mathit{f}    % Italic
852/// \mathrm{dx}   % Roman/upright
853/// ```
854///
855/// # Usage
856///
857/// Styling nodes allow different visual appearances for mathematical symbols,
858/// useful for distinguishing vectors from scalars or emphasizing certain terms.
859#[derive(Debug, Clone, PartialEq)]
860pub struct ParseNodeStyling {
861    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
862    pub mode: Mode,
863    /// Optional source location for error reporting
864    pub loc: Option<SourceLocation>,
865    /// The style specification ([`Style`])
866    pub style: &'static Style,
867    /// The expressions to be styled
868    pub body: Vec<AnyParseNode>,
869}
870
871/// Represents superscript and subscript combinations in mathematical
872/// expressions.
873///
874/// This struct handles the attachment of superscript and/or subscript
875/// expressions to a base expression, supporting complex nested structures.
876///
877/// # Fields
878///
879/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
880/// * `loc` - Optional source location for error reporting
881/// * `base` - The base expression being modified
882/// * `sup` - Optional superscript expression
883/// * `sub` - Optional subscript expression
884///
885/// # LaTeX Correspondence
886///
887/// Corresponds to LaTeX superscript/subscript syntax:
888/// ```latex
889/// x^2        % Superscript
890/// a_i        % Subscript
891/// x^{n+1}    % Complex superscript
892/// a_{i,j}    % Complex subscript
893/// ```
894///
895/// # Usage
896///
897/// SupSub nodes are fundamental for mathematical notation, allowing expressions
898/// like exponents, indices, and other modifiers to be properly positioned
899/// relative to their base.
900#[derive(Debug, Clone, PartialEq)]
901pub struct ParseNodeSupSub {
902    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
903    pub mode: Mode,
904    /// Optional source location for error reporting
905    pub loc: Option<SourceLocation>,
906    /// The base expression being modified
907    pub base: Option<Box<AnyParseNode>>,
908    /// Optional superscript expression
909    pub sup: Option<Box<AnyParseNode>>,
910    /// Optional subscript expression
911    pub sub: Option<Box<AnyParseNode>>,
912}
913
914/// Represents tagged equations or expressions with labels.
915///
916/// This struct handles equation tags, numbers, or labels that are associated
917/// with mathematical expressions, typically for referencing.
918///
919/// # Fields
920///
921/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
922/// * `loc` - Optional source location for error reporting
923/// * `body` - The main mathematical expression
924/// * `tag` - The tag/label expressions
925///
926/// # LaTeX Correspondence
927///
928/// Corresponds to LaTeX equation tagging:
929/// ```latex
930/// \tag{1} E = mc^2
931/// \begin{equation}\label{eq:energy}
932/// E = mc^2
933/// \end{equation}
934/// ```
935///
936/// # Usage
937///
938/// Tag nodes enable equation numbering and referencing in mathematical
939/// documents, allowing readers to cite specific equations.
940#[derive(Debug, Clone, PartialEq)]
941pub struct ParseNodeTag {
942    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
943    pub mode: Mode,
944    /// Optional source location for error reporting
945    pub loc: Option<SourceLocation>,
946    /// The main mathematical expression
947    pub body: Vec<AnyParseNode>,
948    /// The tag/label expressions
949    pub tag: Vec<AnyParseNode>,
950}
951
952/// Represents text content within mathematical expressions.
953///
954/// This struct handles text that appears in math mode, with optional font
955/// specifications for proper rendering of textual elements in mathematical
956/// contexts.
957///
958/// # Fields
959///
960/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
961/// * `loc` - Optional source location for error reporting
962/// * `body` - The text content as parse nodes
963/// * `font` - Optional font family specification
964///
965/// # LaTeX Correspondence
966///
967/// Corresponds to LaTeX text commands in math:
968/// ```latex
969/// \text{if}        % Text in math
970/// \mathrm{dx}      % Roman font
971/// \mathbf{v}       % Bold font
972/// ```
973///
974/// # Usage
975///
976/// Text nodes allow mixing of textual and mathematical content, ensuring
977/// proper font rendering for words and phrases within mathematical expressions.
978#[derive(Debug, Clone, PartialEq)]
979pub struct ParseNodeText {
980    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
981    pub mode: Mode,
982    /// Optional source location for error reporting
983    pub loc: Option<SourceLocation>,
984    /// The text content as parse nodes
985    pub body: Vec<AnyParseNode>,
986    /// Optional font family specification
987    pub font: Option<String>,
988}
989
990/// Represents URL links in mathematical expressions.
991///
992/// This struct handles hyperlinks within mathematical content, allowing
993/// mathematical expressions to contain clickable links.
994///
995/// # Fields
996///
997/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
998/// * `loc` - Optional source location for error reporting
999/// * `url` - The URL string
1000///
1001/// # LaTeX Correspondence
1002///
1003/// Corresponds to LaTeX hyperlink commands:
1004/// ```latex
1005/// \url{https://example.com}
1006/// \href{https://example.com}{link text}
1007/// ```
1008///
1009/// # Usage
1010///
1011/// URL nodes enable interactive mathematical documents with embedded links,
1012/// useful for referencing external resources or documentation.
1013#[derive(Debug, Clone, PartialEq, Eq)]
1014pub struct ParseNodeUrl {
1015    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1016    pub mode: Mode,
1017    /// Optional source location for error reporting
1018    pub loc: Option<SourceLocation>,
1019    /// The URL string
1020    pub url: String,
1021}
1022
1023/// Represents verbatim text content that should be rendered exactly as written.
1024///
1025/// This struct handles text that must preserve its exact formatting and
1026/// spacing, without any mathematical interpretation or processing.
1027///
1028/// # Fields
1029///
1030/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1031/// * `loc` - Optional source location for error reporting
1032/// * `body` - The verbatim text content
1033/// * `star` - Whether this is a starred version (affects rendering)
1034///
1035/// # LaTeX Correspondence
1036///
1037/// Corresponds to LaTeX verbatim commands:
1038/// ```latex
1039/// \verb|exact text|
1040/// \begin{verbatim}
1041/// exact text
1042/// \end{verbatim}
1043/// ```
1044///
1045/// # Usage
1046///
1047/// Verb nodes are essential for including code snippets, file paths, or other
1048/// text that must maintain exact spacing and special characters.
1049#[derive(Debug, Clone, PartialEq, Eq)]
1050pub struct ParseNodeVerb {
1051    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1052    pub mode: Mode,
1053    /// Optional source location for error reporting
1054    pub loc: Option<SourceLocation>,
1055    /// The verbatim text content
1056    pub body: String,
1057    /// Whether this is a starred version (affects rendering)
1058    pub star: bool,
1059}
1060
1061// Symbol parse nodes (from symbols.js)
1062
1063/// Represents atomic symbols with specific mathematical meaning and spacing
1064/// rules.
1065///
1066/// This struct handles individual symbols that have special significance in
1067/// mathematical typesetting, such as operators, relations, and other atomic
1068/// elements with defined spacing behavior.
1069///
1070/// # Fields
1071///
1072/// * `family` - The atom type ([`Atom`]) determining spacing and behavior
1073/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1074/// * `loc` - Optional source location for error reporting
1075/// * `text` - The symbol text
1076///
1077/// # Usage
1078///
1079/// Atoms are the fundamental building blocks of mathematical expressions,
1080/// with each atom type having specific spacing rules that affect layout.
1081#[derive(Debug, Clone, PartialEq, Eq)]
1082pub struct ParseNodeAtom {
1083    /// The atom type ([`Atom`]) determining spacing and behavior
1084    pub family: Atom,
1085    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1086    pub mode: Mode,
1087    /// Optional source location for error reporting
1088    pub loc: Option<SourceLocation>,
1089    /// The symbol text
1090    pub text: String,
1091}
1092
1093/// Represents ordinary mathematical symbols without special spacing rules.
1094///
1095/// This struct handles regular mathematical symbols that don't have special
1096/// spacing or positioning requirements, such as variables and digits.
1097///
1098/// # Fields
1099///
1100/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1101/// * `loc` - Optional source location for error reporting
1102/// * `text` - The symbol text
1103///
1104///
1105/// # LaTeX Correspondence
1106///
1107/// Corresponds to ordinary symbols in math mode:
1108/// ```latex
1109/// x y z     % Variables
1110/// 1 2 3     % Digits
1111/// a b c     % Letters
1112/// ```
1113///
1114/// # Usage
1115///
1116/// MathOrd nodes represent the most common type of mathematical symbols,
1117/// forming the basic content of expressions.
1118#[derive(Debug, Clone, PartialEq, Eq)]
1119pub struct ParseNodeMathOrd {
1120    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1121    pub mode: Mode,
1122    /// Optional source location for error reporting
1123    pub loc: Option<SourceLocation>,
1124    /// The symbol text
1125    pub text: String,
1126}
1127
1128/// Represents explicit spacing elements in mathematical expressions.
1129///
1130/// This struct handles manually inserted spacing that affects the layout
1131/// and positioning of mathematical elements.
1132///
1133/// # Fields
1134///
1135/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1136/// * `loc` - Optional source location for error reporting
1137/// * `text` - The spacing command or symbol
1138///
1139/// # LaTeX Correspondence
1140///
1141/// Corresponds to LaTeX spacing commands:
1142/// ```latex
1143/// \,    % Thin space
1144/// \:    % Medium space
1145/// \;    % Thick space
1146/// \!    % Negative thin space
1147/// ```
1148///
1149/// # Usage
1150///
1151/// Spacing nodes allow fine control over the horizontal spacing between
1152/// mathematical elements for proper visual appearance.
1153#[derive(Debug, Clone, PartialEq, Eq)]
1154pub struct ParseNodeSpacing {
1155    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1156    pub mode: Mode,
1157    /// Optional source location for error reporting
1158    pub loc: Option<SourceLocation>,
1159    /// The spacing command or symbol
1160    pub text: String,
1161}
1162
1163/// Represents ordinary text symbols within mathematical expressions.
1164///
1165/// This struct handles text characters that appear in math mode but don't
1166/// have mathematical symbol properties.
1167///
1168/// # Fields
1169///
1170/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1171/// * `loc` - Optional source location for error reporting
1172/// * `text` - The text content
1173///
1174/// # Usage
1175///
1176/// TextOrd nodes are used for text characters in mathematical contexts,
1177/// ensuring proper font and spacing treatment.
1178#[derive(Debug, Clone, PartialEq, Eq)]
1179pub struct ParseNodeTextOrd {
1180    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1181    pub mode: Mode,
1182    /// Optional source location for error reporting
1183    pub loc: Option<SourceLocation>,
1184    /// The text content
1185    pub text: String,
1186}
1187
1188/// Represents accent symbols used for diacritical marks.
1189///
1190/// This struct handles the symbol portion of accent commands,
1191/// which modify the appearance of base characters.
1192///
1193/// # Fields
1194///
1195/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1196/// * `loc` - Optional source location for error reporting
1197/// * `text` - The accent symbol
1198///
1199/// # LaTeX Correspondence
1200///
1201/// Corresponds to accent symbols:
1202/// ```latex
1203/// \hat{x}     % ^
1204/// \bar{y}     % -
1205/// \tilde{z}   % ~
1206/// ```
1207///
1208/// # Usage
1209///
1210/// Accent tokens are combined with base characters to create accented symbols
1211/// in mathematical notation.
1212#[derive(Debug, Clone, PartialEq, Eq)]
1213pub struct ParseNodeAccentToken {
1214    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1215    pub mode: Mode,
1216    /// Optional source location for error reporting
1217    pub loc: Option<SourceLocation>,
1218    /// The accent symbol
1219    pub text: String,
1220}
1221
1222/// Represents operator symbols with special positioning rules.
1223///
1224/// This struct handles operator tokens that may have special rendering
1225/// requirements, such as limits positioning.
1226///
1227/// # Fields
1228///
1229/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1230/// * `loc` - Optional source location for error reporting
1231/// * `text` - The operator symbol
1232///
1233///
1234/// # Usage
1235///
1236/// OpTokens represent operators that may need special handling for
1237/// subscripts/superscripts (limits vs. regular scripts).
1238#[derive(Debug, Clone, PartialEq, Eq)]
1239pub struct ParseNodeOpToken {
1240    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1241    pub mode: Mode,
1242    /// Optional source location for error reporting
1243    pub loc: Option<SourceLocation>,
1244    /// The operator symbol
1245    pub text: String,
1246}
1247
1248// Function parse nodes (from functions/*.js)
1249
1250/// Represents accent marks placed above mathematical expressions.
1251///
1252/// This struct handles diacritical marks and accents that modify the appearance
1253/// of base mathematical expressions, such as hats, bars, and tildes.
1254///
1255/// # Fields
1256///
1257/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1258/// * `loc` - Optional source location for error reporting
1259/// * `label` - The accent symbol (e.g., "^", "-", "~")
1260/// * `is_stretchy` - Whether the accent stretches to fit the base width
1261/// * `is_shifty` - Whether the accent is shifted for better positioning
1262/// * `base` - The expression being accented
1263///
1264///
1265/// # LaTeX Correspondence
1266///
1267/// Corresponds to LaTeX accent commands:
1268/// ```latex
1269/// \hat{x}      % Hat
1270/// \bar{y}      % Bar
1271/// \tilde{z}    % Tilde
1272/// \widehat{abc} % Wide hat
1273/// ```
1274///
1275/// # Usage
1276///
1277/// Accent nodes modify the visual appearance of mathematical symbols,
1278/// commonly used for vectors, complex numbers, and special notation.
1279#[derive(Debug, Clone, PartialEq)]
1280pub struct ParseNodeAccent {
1281    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1282    pub mode: Mode,
1283    /// Optional source location for error reporting
1284    pub loc: Option<SourceLocation>,
1285    /// The accent symbol (e.g., "^", "-", "~")
1286    pub label: String,
1287    /// Whether the accent stretches to fit the base width
1288    pub is_stretchy: Option<bool>,
1289    /// Whether the accent is shifted for better positioning
1290    pub is_shifty: Option<bool>,
1291    /// The expression being accented
1292    pub base: AnyParseNode,
1293}
1294
1295/// Represents accent marks placed below mathematical expressions.
1296///
1297/// This struct handles under-accents, which are diacritical marks positioned
1298/// beneath base expressions, such as underbars and undertildes.
1299///
1300/// # Fields
1301///
1302/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1303/// * `loc` - Optional source location for error reporting
1304/// * `label` - The under-accent symbol
1305/// * `is_stretchy` - Whether the accent stretches to fit the base width
1306/// * `is_shifty` - Whether the accent is shifted for better positioning
1307/// * `base` - The expression being under-accented
1308///
1309/// # LaTeX Correspondence
1310///
1311/// Corresponds to LaTeX under-accent commands:
1312/// ```latex
1313/// \underline{x}    % Underline
1314/// \underbar{y}     % Underbar
1315/// \utilde{z}       % Undertilde
1316/// ```
1317///
1318/// # Usage
1319///
1320/// Under-accent nodes provide visual modifications below expressions,
1321/// useful for emphasis and special mathematical notation.
1322#[derive(Debug, Clone, PartialEq)]
1323pub struct ParseNodeAccentUnder {
1324    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1325    pub mode: Mode,
1326    /// Optional source location for error reporting
1327    pub loc: Option<SourceLocation>,
1328    /// The under-accent symbol
1329    pub label: String,
1330    /// Whether the accent stretches to fit the base width
1331    pub is_stretchy: Option<bool>,
1332    /// Whether the accent is shifted for better positioning
1333    pub is_shifty: Option<bool>,
1334    /// The expression being under-accented
1335    pub base: Box<AnyParseNode>,
1336}
1337
1338/// Represents carriage returns and line breaks in mathematical expressions.
1339///
1340/// This struct handles explicit line breaks and vertical spacing within
1341/// mathematical content, particularly in arrays and multiline constructs.
1342///
1343/// # Fields
1344///
1345/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1346/// * `loc` - Optional source location for error reporting
1347/// * `new_line` - Whether this represents a new line
1348/// * `size` - Optional size of the break ([`MeasurementOwned`])
1349///
1350/// # LaTeX Correspondence
1351///
1352/// Corresponds to LaTeX line break commands:
1353/// ```latex
1354/// \\          % Basic line break
1355/// \\[1em]     % Line break with spacing
1356/// \newline    % New line
1357/// ```
1358///
1359/// # Usage
1360///
1361/// CR nodes control line breaks in multiline mathematical expressions,
1362/// such as in arrays, cases, and aligned equations.
1363#[derive(Debug, Clone, PartialEq)]
1364pub struct ParseNodeCr {
1365    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1366    pub mode: Mode,
1367    /// Optional source location for error reporting
1368    pub loc: Option<SourceLocation>,
1369    /// Whether this represents a new line
1370    pub new_line: bool,
1371    /// Optional size of the break ([`MeasurementOwned`])
1372    pub size: Option<MeasurementOwned>,
1373}
1374
1375/// Represents delimiter sizing for mathematical symbols.
1376///
1377/// This struct handles the sizing of delimiters (parentheses, brackets, etc.)
1378/// to properly enclose mathematical expressions of varying heights.
1379///
1380/// # Fields
1381///
1382/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1383/// * `loc` - Optional source location for error reporting
1384/// * `size` - The size level (1-4, where 4 is largest)
1385/// * `mclass` - The math class ("mopen", "mclose", "mrel", "mord")
1386/// * `delim` - The delimiter symbol
1387///
1388///
1389/// # LaTeX Correspondence
1390///
1391/// Corresponds to LaTeX delimiter sizing:
1392/// ```latex
1393/// \big(       % Size 2
1394/// \Big[       % Size 3
1395/// \bigg\{     % Size 4
1396/// \Bigg\langle % Size 5
1397/// ```
1398///
1399/// # Usage
1400///
1401/// Delimsizing nodes ensure delimiters scale appropriately to contain
1402/// their enclosed mathematical content.
1403#[derive(Debug, Clone, PartialEq, Eq)]
1404pub struct ParseNodeDelimsizing {
1405    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1406    pub mode: Mode,
1407    /// Optional source location for error reporting
1408    pub loc: Option<SourceLocation>,
1409    /// The size level (1-4, where 4 is largest)
1410    pub size: u8, // 1 | 2 | 3 | 4
1411    /// The math class ("mopen", "mclose", "mrel", "mord")
1412    pub mclass: DomType, // "mopen" | "mclose" | "mrel" | "mord"
1413    /// The delimiter symbol
1414    pub delim: String,
1415}
1416
1417/// Represents enclosed mathematical expressions with background and border
1418/// styling.
1419///
1420/// This struct handles expressions that are enclosed with colored backgrounds
1421/// or borders, often used for highlighting or special notation.
1422///
1423/// # Fields
1424///
1425/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1426/// * `loc` - Optional source location for error reporting
1427/// * `label` - The enclosure type/label
1428/// * `background_color` - Optional background color
1429/// * `border_color` - Optional border color
1430/// * `body` - The enclosed expression
1431///
1432///
1433/// # LaTeX Correspondence
1434///
1435/// Corresponds to LaTeX enclosure commands:
1436/// ```latex
1437/// \boxed{x}              % Boxed
1438/// \colorbox{yellow}{x}   % Background color
1439/// \fcolorbox{red}{blue}{x} % Border and background
1440/// ```
1441///
1442/// # Usage
1443///
1444/// Enclose nodes provide visual emphasis and grouping for mathematical
1445/// expressions, useful for highlighting important terms or creating visual
1446/// distinctions.
1447#[derive(Debug, Clone, PartialEq)]
1448pub struct ParseNodeEnclose {
1449    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1450    pub mode: Mode,
1451    /// Optional source location for error reporting
1452    pub loc: Option<SourceLocation>,
1453    /// The enclosure type/label
1454    pub label: String,
1455    /// Optional background color
1456    pub background_color: Option<String>,
1457    /// Optional border color
1458    pub border_color: Option<String>,
1459    /// The enclosed expression
1460    pub body: Box<AnyParseNode>,
1461}
1462
1463/// Represents custom mathematical environments.
1464///
1465/// This struct handles user-defined or custom mathematical environments
1466/// that extend beyond the standard KaTeX environments.
1467///
1468/// # Fields
1469///
1470/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1471/// * `loc` - Optional source location for error reporting
1472/// * `name` - The environment name
1473/// * `name_group` - The parsed name as an expression
1474///
1475///
1476/// # Usage
1477///
1478/// Environment nodes support custom mathematical constructs and
1479/// user-defined environments in LaTeX documents.
1480#[derive(Debug, Clone, PartialEq)]
1481pub struct ParseNodeEnvironment {
1482    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1483    pub mode: Mode,
1484    /// Optional source location for error reporting
1485    pub loc: Option<SourceLocation>,
1486    /// The environment name
1487    pub name: String,
1488    /// The parsed name as an expression
1489    pub name_group: Box<AnyParseNode>,
1490}
1491
1492impl From<ParseNodeEnvironment> for AnyParseNode {
1493    fn from(value: ParseNodeEnvironment) -> Self {
1494        Self::Environment(Box::new(value))
1495    }
1496}
1497
1498/// Represents font changes applied to mathematical expressions.
1499///
1500/// This struct handles font family changes for mathematical content,
1501/// allowing different typefaces within expressions.
1502///
1503/// # Fields
1504///
1505/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1506/// * `loc` - Optional source location for error reporting
1507/// * `font` - The font family name
1508/// * `body` - The expression in the specified font
1509///
1510/// # LaTeX Correspondence
1511///
1512/// Corresponds to LaTeX font commands:
1513/// ```latex
1514/// \mathrm{dx}     % Roman/upright
1515/// \mathbf{v}     % Bold
1516/// \mathit{f}     % Italic
1517/// \mathsf{S}     % Sans-serif
1518/// ```
1519///
1520/// # Usage
1521///
1522/// Font nodes control the typeface of mathematical symbols, essential for
1523/// distinguishing different types of mathematical objects (scalars, vectors,
1524/// etc.).
1525#[derive(Debug, Clone, PartialEq)]
1526pub struct ParseNodeFont {
1527    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1528    pub mode: Mode,
1529    /// Optional source location for error reporting
1530    pub loc: Option<SourceLocation>,
1531    /// The font family name
1532    pub font: String,
1533    /// The expression in the specified font
1534    pub body: Box<AnyParseNode>,
1535}
1536
1537/// Represents generalized fractions and binomial coefficients.
1538///
1539/// This struct handles various types of fractions including regular fractions,
1540/// binomial coefficients, and other stacked expressions with optional
1541/// delimiters.
1542///
1543/// # Fields
1544///
1545/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1546/// * `loc` - Optional source location for error reporting
1547/// * `continued` - Whether this is a continued fraction
1548/// * `numer` - The numerator expression
1549/// * `denom` - The denominator expression
1550/// * `has_bar_line` - Whether to draw a fraction bar
1551/// * `left_delim` - Optional left delimiter
1552/// * `right_delim` - Optional right delimiter
1553/// * `size` - The display size ([`Style`])
1554/// * `bar_size` - Optional custom bar thickness
1555///
1556/// # LaTeX Correspondence
1557///
1558/// Corresponds to LaTeX fraction commands:
1559/// ```latex
1560/// \frac{1}{2}       % Regular fraction
1561/// \binom{n}{k}      % Binomial coefficient
1562/// \dfrac{a}{b}      % Display style fraction
1563/// \cfrac{1}{1+x}    % Continued fraction
1564/// ```
1565///
1566/// # Usage
1567///
1568/// Genfrac nodes are fundamental for representing ratios, probabilities,
1569/// and complex mathematical relationships in stacked form.
1570#[derive(Debug, Clone, PartialEq)]
1571pub struct ParseNodeGenfrac {
1572    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1573    pub mode: Mode,
1574    /// Optional source location for error reporting
1575    pub loc: Option<SourceLocation>,
1576    /// Whether this is a continued fraction
1577    pub continued: bool,
1578    /// The numerator expression
1579    pub numer: Box<AnyParseNode>,
1580    /// The denominator expression
1581    pub denom: Box<AnyParseNode>,
1582    /// Whether to draw a fraction bar
1583    pub has_bar_line: bool,
1584    /// Optional left delimiter
1585    pub left_delim: Option<String>,
1586    /// Optional right delimiter
1587    pub right_delim: Option<String>,
1588    /// The display size ([`Style`])
1589    /// Corresponds to KaTeX's `\genfrac` size parameter:
1590    /// If this is None, the equivalent to "auto" is used.
1591    pub size: Option<&'static Style>,
1592    /// Optional custom bar thickness
1593    pub bar_size: Option<MeasurementOwned>,
1594}
1595
1596/// Represents horizontal boxes for grouping mathematical content.
1597///
1598/// This struct handles horizontal grouping of mathematical expressions
1599/// that should be treated as a single unit for layout purposes.
1600///
1601/// # Fields
1602///
1603/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1604/// * `loc` - Optional source location for error reporting
1605/// * `body` - The expressions contained in the horizontal box
1606///
1607/// # LaTeX Correspondence
1608///
1609/// Corresponds to LaTeX horizontal box commands:
1610/// ```latex
1611/// \hbox{ab}     % Horizontal box
1612/// \mbox{xy}    % Math box
1613/// ```
1614///
1615/// # Usage
1616///
1617/// Hbox nodes control horizontal spacing and grouping of mathematical elements,
1618/// ensuring they are treated as a single layout unit.
1619#[derive(Debug, Clone, PartialEq)]
1620pub struct ParseNodeHbox {
1621    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1622    pub mode: Mode,
1623    /// Optional source location for error reporting
1624    pub loc: Option<SourceLocation>,
1625    /// The expressions contained in the horizontal box
1626    pub body: Vec<AnyParseNode>,
1627}
1628
1629/// Represents horizontal braces above or below mathematical expressions.
1630///
1631/// This struct handles overbraces and underbraces that span multiple symbols
1632/// with optional labels for annotation.
1633///
1634/// # Fields
1635///
1636/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1637/// * `loc` - Optional source location for error reporting
1638/// * `label` - The brace label/annotation
1639/// * `is_over` - Whether the brace is above (true) or below (false)
1640/// * `base` - The expression being braced
1641///
1642///
1643/// # LaTeX Correspondence
1644///
1645/// Corresponds to LaTeX brace commands:
1646/// ```latex
1647/// \overbrace{abc}^{sum}    % Overbrace
1648/// \underbrace{xyz}_{total} % Underbrace
1649/// ```
1650///
1651/// # Usage
1652///
1653/// HorizBrace nodes provide visual grouping and annotation of related
1654/// mathematical terms or operations.
1655#[derive(Debug, Clone, PartialEq)]
1656pub struct ParseNodeHorizBrace {
1657    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1658    pub mode: Mode,
1659    /// Optional source location for error reporting
1660    pub loc: Option<SourceLocation>,
1661    /// The brace label/annotation
1662    pub label: String,
1663    /// Whether the brace is above (true) or below (false)
1664    pub is_over: bool,
1665    /// The expression being braced
1666    pub base: Box<AnyParseNode>,
1667}
1668
1669/// Represents hyperlink references within mathematical expressions.
1670///
1671/// This struct handles clickable links in mathematical content,
1672/// allowing expressions to link to external resources or references.
1673///
1674/// # Fields
1675///
1676/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1677/// * `loc` - Optional source location for error reporting
1678/// * `href` - The hyperlink URL
1679/// * `body` - The linked mathematical expression
1680///
1681///
1682/// # LaTeX Correspondence
1683///
1684/// Corresponds to LaTeX hyperlink commands:
1685/// ```latex
1686/// \href{https://example.com}{x}
1687/// \url{https://example.com}
1688/// ```
1689///
1690/// # Usage
1691///
1692/// Href nodes enable interactive mathematical documents with embedded
1693/// navigation and reference links.
1694#[derive(Debug, Clone, PartialEq)]
1695pub struct ParseNodeHref {
1696    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1697    pub mode: Mode,
1698    /// Optional source location for error reporting
1699    pub loc: Option<SourceLocation>,
1700    /// The hyperlink URL
1701    pub href: String,
1702    /// The linked mathematical expression
1703    pub body: Vec<AnyParseNode>,
1704}
1705
1706/// Represents embedded HTML content within mathematical expressions.
1707///
1708/// This struct handles raw HTML that needs to be included in the
1709/// rendered mathematical output.
1710///
1711/// # Fields
1712///
1713/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1714/// * `loc` - Optional source location for error reporting
1715/// * `attributes` - HTML attributes as key-value pairs
1716/// * `body` - The HTML content as parse nodes
1717///
1718/// # Usage
1719///
1720/// HTML nodes allow embedding custom HTML elements within mathematical
1721/// expressions for advanced formatting or interactivity.
1722#[derive(Debug, Clone, PartialEq)]
1723pub struct ParseNodeHtml {
1724    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1725    pub mode: Mode,
1726    /// Optional source location for error reporting
1727    pub loc: Option<SourceLocation>,
1728    /// HTML attributes as key-value pairs
1729    pub attributes: KeyMap<String, String>,
1730    /// The HTML content as parse nodes
1731    pub body: Vec<AnyParseNode>,
1732}
1733
1734/// Represents content that can be rendered in both HTML and MathML formats.
1735///
1736/// This struct handles mathematical expressions that have different
1737/// representations for HTML and MathML output formats.
1738///
1739/// # Fields
1740///
1741/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1742/// * `loc` - Optional source location for error reporting
1743/// * `html` - HTML representation
1744/// * `mathml` - MathML representation
1745///
1746/// # Usage
1747///
1748/// HtmlMathMl nodes support dual-format output for better compatibility
1749/// across different rendering engines and accessibility tools.
1750#[derive(Debug, Clone, PartialEq)]
1751pub struct ParseNodeHtmlMathMl {
1752    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1753    pub mode: Mode,
1754    /// Optional source location for error reporting
1755    pub loc: Option<SourceLocation>,
1756    /// HTML representation
1757    pub html: Vec<AnyParseNode>,
1758    /// MathML representation
1759    pub mathml: Vec<AnyParseNode>,
1760}
1761
1762/// Represents included graphics/images within mathematical expressions.
1763///
1764/// This struct handles the inclusion of external images or graphics
1765/// that are part of mathematical content.
1766///
1767/// # Fields
1768///
1769/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1770/// * `loc` - Optional source location for error reporting
1771/// * `alt` - Alternative text for accessibility
1772/// * `width` - Image width ([`MeasurementOwned`])
1773/// * `height` - Image height ([`MeasurementOwned`])
1774/// * `total_height` - Total height including depth
1775/// * `src` - Image source path/URL
1776///
1777/// # LaTeX Correspondence
1778///
1779/// Corresponds to LaTeX include graphics commands:
1780/// ```latex
1781/// \includegraphics[width=5em]{diagram.png}
1782/// \includegraphics[height=3em]{figure.jpg}
1783/// ```
1784///
1785/// # Usage
1786///
1787/// Includegraphics nodes allow embedding diagrams, plots, and other
1788/// visual elements within mathematical expressions.
1789#[derive(Debug, Clone, PartialEq)]
1790pub struct ParseNodeIncludegraphics {
1791    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1792    pub mode: Mode,
1793    /// Optional source location for error reporting
1794    pub loc: Option<SourceLocation>,
1795    /// Alternative text for accessibility
1796    pub alt: String,
1797    /// Image width ([`MeasurementOwned`])
1798    pub width: MeasurementOwned,
1799    /// Image height ([`MeasurementOwned`])
1800    pub height: MeasurementOwned,
1801    /// Total height including depth
1802    pub total_height: MeasurementOwned,
1803    /// Image source path/URL
1804    pub src: String,
1805}
1806
1807/// Represents infix operators in mathematical expressions.
1808///
1809/// This struct handles operators that appear between operands,
1810/// such as custom or extensible operators.
1811///
1812/// # Fields
1813///
1814/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1815/// * `loc` - Optional source location for error reporting
1816/// * `replace_with` - The replacement string for the operator
1817/// * `size` - Optional size specification
1818/// * `token` - Optional associated token
1819///
1820/// # Usage
1821///
1822/// Infix nodes handle custom operators and extensible operator syntax
1823/// in mathematical expressions.
1824#[derive(Debug, Clone, PartialEq)]
1825pub struct ParseNodeInfix {
1826    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1827    pub mode: Mode,
1828    /// Optional source location for error reporting
1829    pub loc: Option<SourceLocation>,
1830    /// The replacement string for the operator
1831    pub replace_with: String,
1832    /// Optional size specification
1833    pub size: Option<MeasurementOwned>,
1834    /// Optional associated token
1835    pub token: Option<Token>,
1836}
1837
1838/// Represents internal parser nodes for implementation details.
1839///
1840/// This struct handles nodes used internally by the parser for
1841/// processing and transformation purposes.
1842///
1843/// # Fields
1844///
1845/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1846/// * `loc` - Optional source location for error reporting
1847///
1848/// # Usage
1849///
1850/// Internal nodes are used for parser implementation details and
1851/// intermediate processing steps.
1852#[derive(Debug, Clone, PartialEq, Eq)]
1853pub struct ParseNodeInternal {
1854    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1855    pub mode: Mode,
1856    /// Optional source location for error reporting
1857    pub loc: Option<SourceLocation>,
1858}
1859
1860/// Represents explicit kerning/spacing adjustments in mathematical expressions.
1861///
1862/// This struct handles manual spacing adjustments between mathematical elements
1863/// for precise layout control.
1864///
1865/// # Fields
1866///
1867/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1868/// * `loc` - Optional source location for error reporting
1869/// * `dimension` - The spacing amount ([`MeasurementOwned`])
1870///
1871/// # LaTeX Correspondence
1872///
1873/// Corresponds to LaTeX kerning commands:
1874/// ```latex
1875/// \kern 0.5em    % Positive kerning
1876/// \mkern 3mu     % Math unit kerning
1877/// ```
1878///
1879/// # Usage
1880///
1881/// Kern nodes provide fine-grained control over spacing in mathematical
1882/// expressions for typographical precision.
1883#[derive(Debug, Clone, PartialEq)]
1884pub struct ParseNodeKern {
1885    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1886    pub mode: Mode,
1887    /// Optional source location for error reporting
1888    pub loc: Option<SourceLocation>,
1889    /// The spacing amount ([`MeasurementOwned`])
1890    pub dimension: MeasurementOwned,
1891}
1892
1893/// Represents overlapping content (lap) in mathematical expressions.
1894///
1895/// This struct handles text or symbols that overlap other content,
1896/// commonly used for annotations or special positioning.
1897///
1898/// # Fields
1899///
1900/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1901/// * `loc` - Optional source location for error reporting
1902/// * `alignment` - The alignment for overlapping ("l", "r", "c")
1903/// * `body` - The overlapping content
1904///
1905/// # LaTeX Correspondence
1906///
1907/// Corresponds to LaTeX lap commands:
1908/// ```latex
1909/// \rlap{*}     % Right overlap
1910/// \llap{#}     % Left overlap
1911/// \clap{^}     % Center overlap
1912/// ```
1913///
1914/// # Usage
1915///
1916/// Lap nodes enable overlapping text for annotations, superscripts,
1917/// or special positioning requirements.
1918#[derive(Debug, Clone, PartialEq)]
1919pub struct ParseNodeLap {
1920    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1921    pub mode: Mode,
1922    /// Optional source location for error reporting
1923    pub loc: Option<SourceLocation>,
1924    /// The alignment for overlapping ("l", "r", "c")
1925    pub alignment: LapAlignment,
1926    /// The overlapping content
1927    pub body: Box<AnyParseNode>,
1928}
1929
1930/// Alignment options for overlapping content.
1931#[derive(Debug, Clone, PartialEq, Eq)]
1932pub enum LapAlignment {
1933    /// Align left
1934    Left,
1935    /// Align center
1936    Center,
1937    /// Align right
1938    Right,
1939}
1940
1941impl LapAlignment {
1942    /// Get as static string reference.
1943    #[must_use]
1944    pub const fn as_str(&self) -> &'static str {
1945        match self {
1946            Self::Left => "llap",
1947            Self::Center => "clap",
1948            Self::Right => "rlap",
1949        }
1950    }
1951}
1952
1953/// Represents left-right delimiter pairs in mathematical expressions.
1954///
1955/// This struct handles matching delimiter pairs that enclose mathematical
1956/// content, such as parentheses, brackets, and braces with automatic sizing.
1957///
1958/// # Fields
1959///
1960/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1961/// * `loc` - Optional source location for error reporting
1962/// * `body` - The enclosed mathematical expressions
1963/// * `left` - The left delimiter symbol
1964/// * `right` - The right delimiter symbol
1965/// * `right_color` - Optional color for the right delimiter
1966///
1967///
1968/// # LaTeX Correspondence
1969///
1970/// Corresponds to LaTeX left-right delimiters:
1971/// ```latex
1972/// \left( \frac{a}{b} \right)
1973/// \left[ x + y \right]
1974/// \left\{ a, b, c \right\}
1975/// ```
1976///
1977/// # Usage
1978///
1979/// LeftRight nodes automatically size delimiters to fit their content,
1980/// ensuring proper visual grouping of mathematical expressions.
1981#[derive(Debug, Clone, PartialEq)]
1982pub struct ParseNodeLeftRight {
1983    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
1984    pub mode: Mode,
1985    /// Optional source location for error reporting
1986    pub loc: Option<SourceLocation>,
1987    /// The enclosed mathematical expressions
1988    pub body: Vec<AnyParseNode>,
1989    /// The left delimiter symbol
1990    pub left: String,
1991    /// The right delimiter symbol
1992    pub right: String,
1993    /// Optional color for the right delimiter
1994    pub right_color: Option<String>,
1995}
1996
1997/// Represents right delimiters in left-right pairs.
1998///
1999/// This struct handles the right delimiter in a left-right delimiter pair,
2000/// allowing for separate styling or coloring.
2001///
2002/// # Fields
2003///
2004/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2005/// * `loc` - Optional source location for error reporting
2006/// * `delim` - The delimiter symbol
2007/// * `color` - Optional color specification
2008///
2009/// # Usage
2010///
2011/// LeftRightRight nodes handle the right side of delimiter pairs,
2012/// supporting different styling from the left delimiter.
2013#[derive(Debug, Clone, PartialEq, Eq)]
2014pub struct ParseNodeLeftRightRight {
2015    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2016    pub mode: Mode,
2017    /// Optional source location for error reporting
2018    pub loc: Option<SourceLocation>,
2019    /// The delimiter symbol
2020    pub delim: String,
2021    /// Optional color specification
2022    pub color: Option<String>,
2023}
2024
2025/// Represents different renderings for various math styles.
2026///
2027/// This struct handles expressions that display differently depending on the
2028/// mathematical context (display, text, script, scriptscript sizes).
2029///
2030/// # Fields
2031///
2032/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2033/// * `loc` - Optional source location for error reporting
2034/// * `display` - Display style rendering
2035/// * `text` - Text style rendering
2036/// * `script` - Script style rendering
2037/// * `scriptscript` - Scriptscript style rendering
2038///
2039/// # LaTeX Correspondence
2040///
2041/// Corresponds to LaTeX math choice command:
2042/// ```latex
2043/// \mathchoice{\sum}{\sum}{\sum}{\sum}
2044/// ```
2045///
2046/// # Usage
2047///
2048/// MathChoice nodes allow different visual representations based on the
2049/// mathematical context, ensuring optimal readability at different sizes.
2050#[derive(Debug, Clone, PartialEq)]
2051pub struct ParseNodeMathChoice {
2052    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2053    pub mode: Mode,
2054    /// Optional source location for error reporting
2055    pub loc: Option<SourceLocation>,
2056    /// Display style rendering
2057    pub display: Vec<AnyParseNode>,
2058    /// Text style rendering
2059    pub text: Vec<AnyParseNode>,
2060    /// Script style rendering
2061    pub script: Vec<AnyParseNode>,
2062    /// Scriptscript style rendering
2063    pub scriptscript: Vec<AnyParseNode>,
2064}
2065
2066/// Represents middle delimiters in mathematical expressions.
2067///
2068/// This struct handles delimiters that appear in the middle of expressions,
2069/// such as separators in continued fractions or special punctuation.
2070///
2071/// # Fields
2072///
2073/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2074/// * `loc` - Optional source location for error reporting
2075/// * `delim` - The delimiter symbol
2076///
2077///
2078/// # LaTeX Correspondence
2079///
2080/// Corresponds to LaTeX middle delimiters:
2081/// ```latex
2082/// \middle|
2083/// \middle.
2084/// ```
2085///
2086/// # Usage
2087///
2088/// Middle nodes handle delimiters that separate parts of mathematical
2089/// expressions without being part of left-right pairs.
2090#[derive(Debug, Clone, PartialEq, Eq)]
2091pub struct ParseNodeMiddle {
2092    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2093    pub mode: Mode,
2094    /// Optional source location for error reporting
2095    pub loc: Option<SourceLocation>,
2096    /// The delimiter symbol
2097    pub delim: String,
2098}
2099
2100/// Represents math class specifications for mathematical elements.
2101///
2102/// This struct handles the classification of mathematical symbols for
2103/// proper spacing and rendering behavior.
2104///
2105/// # Fields
2106///
2107/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2108/// * `loc` - Optional source location for error reporting
2109/// * `mclass` - The math class ("mord", "mbin", "mrel", etc.)
2110/// * `body` - The mathematical expressions
2111/// * `is_character_box` - Whether this represents a single character box
2112///
2113///
2114/// # Usage
2115///
2116/// Mclass nodes control the spacing and positioning behavior of mathematical
2117/// elements according to their semantic classification.
2118#[derive(Debug, Clone, PartialEq)]
2119pub struct ParseNodeMclass {
2120    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2121    pub mode: Mode,
2122    /// Optional source location for error reporting
2123    pub loc: Option<SourceLocation>,
2124    /// The math class ("mord", "mbin", "mrel", etc.)
2125    pub mclass: DomType,
2126    /// The mathematical expressions
2127    pub body: Vec<AnyParseNode>,
2128    /// Whether this represents a single character box
2129    pub is_character_box: bool,
2130}
2131
2132/// Represents operator names with special formatting.
2133///
2134/// This struct handles named operators like "lim", "max", "sin" that
2135/// have specific formatting rules for subscripts and superscripts.
2136///
2137/// # Fields
2138///
2139/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2140/// * `loc` - Optional source location for error reporting
2141/// * `body` - The operator name content
2142/// * `always_handle_sup_sub` - Force special subscript/superscript handling
2143/// * `limits` - Whether to place limits above/below (true) or as scripts
2144///   (false)
2145/// * `parent_is_sup_sub` - Whether this is within a sup/sub context
2146///
2147///
2148/// # LaTeX Correspondence
2149///
2150/// Corresponds to LaTeX operator name commands:
2151/// ```latex
2152/// \lim_{x \to 0} f(x)
2153/// \max_{a,b} f(a,b)
2154/// \sin^2 \theta
2155/// ```
2156///
2157/// # Usage
2158///
2159/// OperatorName nodes ensure proper formatting of mathematical operators
2160/// with their arguments and limits.
2161#[derive(Debug, Clone, PartialEq)]
2162pub struct ParseNodeOperatorName {
2163    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2164    pub mode: Mode,
2165    /// Optional source location for error reporting
2166    pub loc: Option<SourceLocation>,
2167    /// The operator name content
2168    pub body: Vec<AnyParseNode>,
2169    /// Force special subscript/superscript handling
2170    pub always_handle_sup_sub: bool,
2171    /// Whether to place limits above/below (true) or as scripts (false)
2172    pub limits: bool,
2173    /// Whether this is within a sup/sub context
2174    pub parent_is_sup_sub: bool,
2175}
2176
2177/// Represents overlines above mathematical expressions.
2178///
2179/// This struct handles horizontal lines drawn above mathematical content
2180/// for emphasis or special notation.
2181///
2182/// # Fields
2183///
2184/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2185/// * `loc` - Optional source location for error reporting
2186/// * `body` - The expression being overlined
2187///
2188/// # LaTeX Correspondence
2189///
2190/// Corresponds to LaTeX overline command:
2191/// ```latex
2192/// \overline{ABC}
2193/// ```
2194///
2195/// # Usage
2196///
2197/// Overline nodes provide visual emphasis for mathematical expressions,
2198/// commonly used for repeating decimals or special notation.
2199#[derive(Debug, Clone, PartialEq)]
2200pub struct ParseNodeOverline {
2201    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2202    pub mode: Mode,
2203    /// Optional source location for error reporting
2204    pub loc: Option<SourceLocation>,
2205    /// The expression being overlined
2206    pub body: Box<AnyParseNode>,
2207}
2208
2209/// Represents phantom content for spacing purposes.
2210///
2211/// This struct handles invisible content that affects layout and spacing
2212/// without being visible in the final output.
2213///
2214/// # Fields
2215///
2216/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2217/// * `loc` - Optional source location for error reporting
2218/// * `body` - The phantom content (invisible but affects spacing)
2219///
2220/// # LaTeX Correspondence
2221///
2222/// Corresponds to LaTeX phantom commands:
2223/// ```latex
2224/// \phantom{x}    % Invisible but takes space
2225/// \hphantom{y}   % Horizontal space only
2226/// \vphantom{z}   % Vertical space only
2227/// ```
2228///
2229/// # Usage
2230///
2231/// Phantom nodes allow precise control over spacing and alignment by
2232/// including invisible content that affects layout calculations.
2233#[derive(Debug, Clone, PartialEq)]
2234pub struct ParseNodePhantom {
2235    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2236    pub mode: Mode,
2237    /// Optional source location for error reporting
2238    pub loc: Option<SourceLocation>,
2239    /// The phantom content (invisible but affects spacing)
2240    pub body: Vec<AnyParseNode>,
2241}
2242
2243/// Represents horizontal phantom content.
2244///
2245/// This struct handles invisible content that only affects horizontal spacing
2246/// and width calculations.
2247///
2248/// # Fields
2249///
2250/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2251/// * `loc` - Optional source location for error reporting
2252/// * `body` - The horizontal phantom content
2253///
2254/// # Usage
2255///
2256/// Hphantom nodes reserve horizontal space without vertical extent,
2257/// useful for alignment and spacing control.
2258#[derive(Debug, Clone, PartialEq)]
2259pub struct ParseNodeHphantom {
2260    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2261    pub mode: Mode,
2262    /// Optional source location for error reporting
2263    pub loc: Option<SourceLocation>,
2264    /// The horizontal phantom content
2265    pub body: Box<AnyParseNode>,
2266}
2267
2268/// Represents vertical phantom content.
2269///
2270/// This struct handles invisible content that only affects vertical spacing
2271/// and height calculations.
2272///
2273/// # Fields
2274///
2275/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2276/// * `loc` - Optional source location for error reporting
2277/// * `body` - The vertical phantom content
2278///
2279///
2280/// # Usage
2281///
2282/// Vphantom nodes reserve vertical space without horizontal extent,
2283/// useful for consistent baseline alignment.
2284#[derive(Debug, Clone, PartialEq)]
2285pub struct ParseNodeVphantom {
2286    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2287    pub mode: Mode,
2288    /// Optional source location for error reporting
2289    pub loc: Option<SourceLocation>,
2290    /// The vertical phantom content
2291    pub body: Box<AnyParseNode>,
2292}
2293
2294/// Represents poor man's bold text formatting.
2295///
2296/// This struct handles bold formatting created by overprinting characters,
2297/// used when proper bold fonts are not available.
2298///
2299/// # Fields
2300///
2301/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2302/// * `loc` - Optional source location for error reporting
2303/// * `mclass` - The math class of the content
2304/// * `body` - The content to be made bold
2305///
2306///
2307/// # LaTeX Correspondence
2308///
2309/// Corresponds to LaTeX poor man's bold:
2310/// ```latex
2311/// \pmb{x}    % Poor man's bold
2312/// ```
2313///
2314/// # Usage
2315///
2316/// Pmb nodes create bold appearance by slight overprinting of characters,
2317/// useful for mathematical notation when bold fonts are unavailable.
2318#[derive(Debug, Clone, PartialEq)]
2319pub struct ParseNodePmb {
2320    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2321    pub mode: Mode,
2322    /// Optional source location for error reporting
2323    pub loc: Option<SourceLocation>,
2324    /// The math class of the content
2325    pub mclass: DomType,
2326    /// The content to be made bold
2327    pub body: Vec<AnyParseNode>,
2328}
2329
2330/// Represents raised or lowered content in mathematical expressions.
2331///
2332/// This struct handles vertical displacement of mathematical content
2333/// for special positioning requirements.
2334///
2335/// # Fields
2336///
2337/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2338/// * `loc` - Optional source location for error reporting
2339/// * `dy` - The vertical displacement amount ([`MeasurementOwned`])
2340/// * `body` - The content to be displaced
2341///
2342/// # LaTeX Correspondence
2343///
2344/// Corresponds to LaTeX raisebox command:
2345/// ```latex
2346/// \raisebox{0.5em}{x}
2347/// ```
2348///
2349/// # Usage
2350///
2351/// Raisebox nodes allow precise vertical positioning of mathematical elements
2352/// for special layout requirements.
2353#[derive(Debug, Clone, PartialEq)]
2354pub struct ParseNodeRaisebox {
2355    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2356    pub mode: Mode,
2357    /// Optional source location for error reporting
2358    pub loc: Option<SourceLocation>,
2359    /// The vertical displacement amount ([`MeasurementOwned`])
2360    pub dy: MeasurementOwned,
2361    /// The content to be displaced
2362    pub body: Box<AnyParseNode>,
2363}
2364
2365/// Represents horizontal or vertical rules in mathematical expressions.
2366///
2367/// This struct handles the creation of straight lines for various
2368/// mathematical notation purposes.
2369///
2370/// # Fields
2371///
2372/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2373/// * `loc` - Optional source location for error reporting
2374/// * `shift` - Optional vertical shift of the rule
2375/// * `width` - The width of the rule ([`MeasurementOwned`])
2376/// * `height` - The height/thickness of the rule ([`MeasurementOwned`])
2377///
2378/// # LaTeX Correspondence
2379///
2380/// Corresponds to LaTeX rule command:
2381/// ```latex
2382/// \rule{2em}{0.1em}
2383/// ```
2384///
2385/// # Usage
2386///
2387/// Rule nodes create horizontal or vertical lines for mathematical
2388/// notation, such as fraction bars or special symbols.
2389#[derive(Debug, Clone, PartialEq)]
2390pub struct ParseNodeRule {
2391    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2392    pub mode: Mode,
2393    /// Optional source location for error reporting
2394    pub loc: Option<SourceLocation>,
2395    /// Optional vertical shift of the rule
2396    pub shift: Option<MeasurementOwned>,
2397    /// The width of the rule ([`MeasurementOwned`])
2398    pub width: MeasurementOwned,
2399    /// The height/thickness of the rule ([`MeasurementOwned`])
2400    pub height: MeasurementOwned,
2401}
2402
2403/// Represents size changes for mathematical expressions.
2404///
2405/// This struct handles scaling of mathematical content to different
2406/// display sizes for various contexts.
2407///
2408/// # Fields
2409///
2410/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2411/// * `loc` - Optional source location for error reporting
2412/// * `size` - The size level/index
2413/// * `body` - The expressions to be sized
2414///
2415///
2416/// # LaTeX Correspondence
2417///
2418/// Corresponds to LaTeX sizing commands:
2419/// ```latex
2420/// \scriptsize x
2421/// \large y
2422/// \Huge z
2423/// ```
2424///
2425/// # Usage
2426///
2427/// Sizing nodes control the scale of mathematical expressions for
2428/// different display contexts and emphasis.
2429#[derive(Debug, Clone, PartialEq)]
2430pub struct ParseNodeSizing {
2431    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2432    pub mode: Mode,
2433    /// Optional source location for error reporting
2434    pub loc: Option<SourceLocation>,
2435    /// The size level/index
2436    pub size: usize,
2437    /// The expressions to be sized
2438    pub body: Vec<AnyParseNode>,
2439}
2440
2441/// Represents smashed content that ignores height or depth.
2442///
2443/// This struct handles content where the height or depth is ignored
2444/// for layout purposes, useful for alignment control.
2445///
2446/// # Fields
2447///
2448/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2449/// * `loc` - Optional source location for error reporting
2450/// * `body` - The content to be smashed
2451/// * `smash_height` - Whether to ignore the height above baseline
2452/// * `smash_depth` - Whether to ignore the depth below baseline
2453///
2454/// # LaTeX Correspondence
2455///
2456/// Corresponds to LaTeX smash commands:
2457/// ```latex
2458/// \smash{x}        % Smash both
2459/// \smash[t]{y}     % Smash top only
2460/// \smash[b]{z}     % Smash bottom only
2461/// ```
2462///
2463/// # Usage
2464///
2465/// Smash nodes allow content to be treated as having zero height or depth
2466/// for alignment purposes without affecting the actual rendering.
2467#[derive(Debug, Clone, PartialEq)]
2468pub struct ParseNodeSmash {
2469    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2470    pub mode: Mode,
2471    /// Optional source location for error reporting
2472    pub loc: Option<SourceLocation>,
2473    /// The content to be smashed
2474    pub body: Box<AnyParseNode>,
2475    /// Whether to ignore the height above baseline
2476    pub smash_height: bool,
2477    /// Whether to ignore the depth below baseline
2478    pub smash_depth: bool,
2479}
2480
2481/// Represents square roots and nth roots in mathematical expressions.
2482///
2483/// This struct handles radical expressions with optional indices
2484/// for nth roots.
2485///
2486/// # Fields
2487///
2488/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2489/// * `loc` - Optional source location for error reporting
2490/// * `body` - The expression under the radical
2491/// * `index` - Optional index for nth roots
2492///
2493/// # LaTeX Correspondence
2494///
2495/// Corresponds to LaTeX radical commands:
2496/// ```latex
2497/// \sqrt{x}      % Square root
2498/// \sqrt[3]{x}   % Cube root
2499/// \sqrt[n]{x}   % nth root
2500/// ```
2501///
2502/// # Usage
2503///
2504/// Sqrt nodes represent radical expressions, automatically sizing the
2505/// radical symbol to fit the content and handling nth root indices.
2506#[derive(Debug, Clone, PartialEq)]
2507pub struct ParseNodeSqrt {
2508    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2509    pub mode: Mode,
2510    /// Optional source location for error reporting
2511    pub loc: Option<SourceLocation>,
2512    /// The expression under the radical
2513    pub body: AnyParseNode,
2514    /// Optional index for nth roots
2515    pub index: Option<AnyParseNode>,
2516}
2517
2518/// Represents underlines below mathematical expressions.
2519///
2520/// This struct handles horizontal lines drawn below mathematical content
2521/// for emphasis or special notation.
2522///
2523/// # Fields
2524///
2525/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2526/// * `loc` - Optional source location for error reporting
2527/// * `body` - The expression being underlined
2528///
2529/// # LaTeX Correspondence
2530///
2531/// Corresponds to LaTeX underline command:
2532/// ```latex
2533/// \underline{ABC}
2534/// ```
2535///
2536/// # Usage
2537///
2538/// Underline nodes provide visual emphasis for mathematical expressions,
2539/// commonly used for highlighting or special notation.
2540#[derive(Debug, Clone, PartialEq)]
2541pub struct ParseNodeUnderline {
2542    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2543    pub mode: Mode,
2544    /// Optional source location for error reporting
2545    pub loc: Option<SourceLocation>,
2546    /// The expression being underlined
2547    pub body: Box<AnyParseNode>,
2548}
2549
2550/// Represents vertically centered content in mathematical expressions.
2551///
2552/// This struct handles content that should be centered vertically
2553/// relative to the current line.
2554///
2555/// # Fields
2556///
2557/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2558/// * `loc` - Optional source location for error reporting
2559/// * `body` - The content to be vertically centered
2560///
2561/// # LaTeX Correspondence
2562///
2563/// Corresponds to LaTeX vcenter command:
2564/// ```latex
2565/// \vcenter{x}
2566/// ```
2567///
2568/// # Usage
2569///
2570/// Vcenter nodes center content vertically, useful for aligning
2571/// elements in complex mathematical layouts.
2572#[derive(Debug, Clone, PartialEq)]
2573pub struct ParseNodeVcenter {
2574    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2575    pub mode: Mode,
2576    /// Optional source location for error reporting
2577    pub loc: Option<SourceLocation>,
2578    /// The content to be vertically centered
2579    pub body: Box<AnyParseNode>,
2580}
2581
2582/// Represents extensible arrows in mathematical expressions.
2583///
2584/// This struct handles arrows that can stretch to fit their content,
2585/// with optional labels above or below.
2586///
2587/// # Fields
2588///
2589/// * `mode` - The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2590/// * `loc` - Optional source location for error reporting
2591/// * `label` - The arrow type/label (e.g., "->", "<=>")
2592/// * `body` - The content above the arrow
2593/// * `below` - Optional content below the arrow
2594///
2595/// # LaTeX Correspondence
2596///
2597/// Corresponds to LaTeX extensible arrow commands:
2598/// ```latex
2599/// \xleftarrow{f}
2600/// \xrightarrow[g]{f}
2601/// \xleftrightarrow{h}
2602/// ```
2603///
2604/// # Usage
2605///
2606/// XArrow nodes create arrows that automatically size to fit their labels,
2607/// commonly used for function mappings and transformations.
2608#[derive(Debug, Clone, PartialEq)]
2609pub struct ParseNodeXArrow {
2610    /// The parsing mode ([`Mode::Math`] or [`Mode::Text`])
2611    pub mode: Mode,
2612    /// Optional source location for error reporting
2613    pub loc: Option<SourceLocation>,
2614    /// The arrow type/label (e.g., "->", "<=>")
2615    pub label: String,
2616    /// The content above the arrow
2617    pub body: Option<Box<AnyParseNode>>,
2618    /// Optional content below the arrow
2619    pub below: Option<Box<AnyParseNode>>,
2620}
2621
2622/// Type alias for symbol parse nodes that represent individual mathematical
2623/// symbols.
2624///
2625/// This alias refers to the subset of [`AnyParseNode`] variants that represent
2626/// atomic mathematical symbols with specific spacing and rendering properties.
2627/// These include atoms, operators, ordinals, and other symbol-like elements.
2628///
2629/// # Symbol Types
2630///
2631/// The following [`AnyParseNode`] variants are considered symbol nodes:
2632/// * [`AnyParseNode::Atom`] - Atomic symbols with mathematical meaning
2633/// * [`AnyParseNode::MathOrd`] - Ordinary mathematical symbols
2634/// * [`AnyParseNode::Op`] - Mathematical operators
2635/// * [`AnyParseNode::Spacing`] - Explicit spacing elements
2636/// * [`AnyParseNode::TextOrd`] - Text symbols in math mode
2637/// * [`AnyParseNode::AccentToken`] - Accent symbol components
2638/// * [`AnyParseNode::OpToken`] - Operator symbol components
2639///
2640/// # Usage
2641///
2642/// Used for type checking and validation when a function expects only
2643/// symbol-type nodes. The utility functions [`check_symbol_node_type`] and
2644/// [`assert_symbol_node_type`] work specifically with this type of node.
2645///
2646/// # See Also
2647///
2648/// * [`check_symbol_node_type`] - Check if a node is a symbol node
2649/// * [`assert_symbol_node_type`] - Assert that a node is a symbol node
2650pub type SymbolParseNode = AnyParseNode;
2651
2652/// Type alias for parse nodes representing unsupported or partially supported
2653/// commands.
2654///
2655/// This alias currently refers to color-related nodes that may have limited
2656/// functionality or require special handling in certain rendering contexts.
2657///
2658/// # Current Usage
2659///
2660/// Primarily used for [`ParseNodeColor`] nodes, which represent color changes
2661/// in mathematical expressions. These nodes may not be fully supported in all
2662/// output formats or rendering engines.
2663///
2664/// # Future Extensions
2665///
2666/// This type alias may be extended to include other command types that have
2667/// limited support or require special processing in the KaTeX rendering
2668/// pipeline.
2669///
2670/// # See Also
2671///
2672/// * [`ParseNodeColor`] - The color node type
2673pub type UnsupportedCmdParseNode = ParseNodeColor;
2674
2675/// Primary type alias for all parse nodes in the KaTeX AST.
2676///
2677/// This is the main type used throughout the KaTeX parsing and rendering
2678/// pipeline to represent mathematical expressions. It is equivalent to
2679/// [`AnyParseNode`] and provides a more convenient name for the core AST node
2680/// type.
2681///
2682/// # Architecture
2683///
2684/// The parse node system uses an enum-based approach where each variant
2685/// represents a different type of mathematical construct, from simple symbols
2686/// to complex structures like fractions and arrays.
2687///
2688/// # Usage
2689///
2690/// This type is used extensively in:
2691/// * Parser output - the result of parsing LaTeX input
2692/// * AST transformations - modifying or analyzing the parse tree
2693/// * Rendering pipeline - converting to visual output
2694/// * Type checking and validation - ensuring correct node types
2695///
2696/// # See Also
2697///
2698/// * [`AnyParseNode`] - The underlying enum type
2699/// * [`NodeType`] - Discriminant type for runtime type checking
2700/// * [`assert_node_type`] - Type assertion utility
2701pub type ParseNode = AnyParseNode;
2702
2703/// Errors that can occur during parse node validation and type checking.
2704///
2705/// This enum represents the various error conditions that can arise when
2706/// working with parse nodes, particularly during type assertions and
2707/// validation.
2708///
2709/// The error type implements [`std::error::Error`] and [`std::fmt::Display`]
2710/// for proper error handling and reporting throughout the KaTeX pipeline.
2711///
2712/// # Usage
2713///
2714/// These errors are typically returned by:
2715/// * [`assert_node_type`] - When type assertion fails
2716/// * [`assert_symbol_node_type`] - When symbol node assertion fails
2717///
2718/// They provide detailed information about what went wrong during node
2719/// validation, helping with debugging and error reporting in parsing and
2720/// rendering operations.
2721///
2722/// # Error Messages
2723///
2724/// Error messages are designed to be informative and include both the expected
2725/// and actual types to aid in troubleshooting type-related issues.
2726#[derive(Debug, Error, PartialEq, Eq)]
2727pub enum ParseNodeError {
2728    /// A node has an unexpected type during type checking
2729    #[error("Expected node of type {expected}, but got {actual}")]
2730    TypeMismatch {
2731        /// The expected [`NodeType`] that the node should have
2732        expected: NodeType,
2733        /// The actual type as a string representation
2734        actual: String,
2735    },
2736    /// A node is not one of the symbol node types
2737    #[error("Expected node of symbol group type, but got {actual}")]
2738    NotSymbolNode {
2739        /// The actual node type as a string
2740        actual: String,
2741    },
2742}
2743
2744/// Asserts that a parse node has the expected type and returns the node type.
2745///
2746/// This function performs runtime type checking on parse nodes, ensuring that
2747/// a node matches the expected [`NodeType`] before allowing further processing.
2748/// It's particularly useful when working with the dynamically-typed
2749/// [`AnyParseNode`] enum.
2750///
2751/// # Parameters
2752///
2753/// * `node` - An optional reference to the parse node to check
2754/// * `expected_type` - The expected [`NodeType`] that the node should have
2755///
2756/// # Returns
2757///
2758/// * `Ok(NodeType)` - The node type if the type matches
2759/// * `Err(ParseNodeError::TypeMismatch)` - If the node has a different type
2760/// * `Err(ParseNodeError::TypeMismatch)` - If `node` is `None` (with "null" as
2761///   actual type)
2762///
2763/// # Error Handling
2764///
2765/// The function provides detailed error information through [`ParseNodeError`],
2766/// including both the expected and actual types to aid in debugging.
2767///
2768/// # Performance
2769///
2770/// This function performs a simple discriminant check and string conversion,
2771/// making it suitable for use in performance-critical code paths.
2772///
2773/// # See Also
2774///
2775/// * [`NodeType`] - The enum of possible node types
2776/// * [`ParseNodeError`] - Error type returned on failure
2777/// * [`check_symbol_node_type`] - Check for symbol node types specifically
2778pub fn assert_node_type(
2779    node: Option<&AnyParseNode>,
2780    expected_type: NodeType,
2781) -> Result<NodeType, ParseNodeError> {
2782    let node = node.ok_or_else(|| ParseNodeError::TypeMismatch {
2783        expected: expected_type,
2784        actual: "null".to_owned(),
2785    })?;
2786
2787    let actual_type = NodeType::from(node);
2788
2789    if actual_type == expected_type {
2790        Ok(actual_type)
2791    } else {
2792        Err(ParseNodeError::TypeMismatch {
2793            expected: expected_type,
2794            actual: actual_type.to_string(),
2795        })
2796    }
2797}
2798
2799/// Checks if a parse node represents a symbol-type element and returns the node
2800/// type if so.
2801///
2802/// This function determines whether a given parse node belongs to the symbol
2803/// group, which includes atomic symbols, operators, ordinals, and other
2804/// fundamental mathematical elements that have specific spacing and rendering
2805/// properties.
2806///
2807/// # Symbol Node Types
2808///
2809/// The following [`AnyParseNode`] variants are considered symbol nodes:
2810/// * [`AnyParseNode::Atom`] - Atomic symbols with mathematical meaning
2811/// * [`AnyParseNode::MathOrd`] - Ordinary mathematical symbols
2812/// * [`AnyParseNode::Op`] - Mathematical operators
2813/// * [`AnyParseNode::Spacing`] - Explicit spacing elements
2814/// * [`AnyParseNode::TextOrd`] - Text symbols in math mode
2815/// * [`AnyParseNode::AccentToken`] - Accent symbol components
2816/// * [`AnyParseNode::OpToken`] - Operator symbol components
2817///
2818/// # Parameters
2819///
2820/// * `node` - An optional reference to the parse node to check
2821///
2822/// # Returns
2823///
2824/// * `Some(NodeType)` - The node type if it's a symbol node
2825/// * `None` - If the node is not a symbol node or if `node` is `None`
2826///
2827/// # Examples
2828///
2829/// Checking various node types:
2830/// ```rust
2831/// use katex::parser::parse_node::*;
2832/// use katex::symbols::Atom;
2833/// use katex::types::Mode;
2834///
2835/// // Symbol node - will return Some
2836/// let atom_node = AnyParseNode::Atom(ParseNodeAtom {
2837///     family: Atom::Bin,
2838///     mode: Mode::Math,
2839///     loc: None,
2840///     text: "+".to_string(),
2841/// });
2842/// assert!(check_symbol_node_type(Some(&atom_node)).is_some());
2843///
2844/// // Non-symbol node - will return None
2845/// let array_node = AnyParseNode::Array(ParseNodeArray {
2846///     mode: Mode::Math,
2847///     loc: None,
2848///     col_separation_type: None,
2849///     hskip_before_and_after: None,
2850///     add_jot: None,
2851///     cols: None,
2852///     arraystretch: 1.0,
2853///     body: vec![],
2854///     row_gaps: vec![],
2855///     h_lines_before_row: vec![],
2856///     tags: None,
2857///     leqno: None,
2858///     is_cd: None,
2859/// });
2860/// assert!(check_symbol_node_type(Some(&array_node)).is_none());
2861///
2862/// // None input - will return None
2863/// assert!(check_symbol_node_type(None).is_none());
2864/// ```
2865///
2866/// # Usage
2867///
2868/// This function is useful when you need to handle symbol nodes differently
2869/// from structural nodes (like arrays, fractions, etc.) in processing or
2870/// rendering logic.
2871///
2872/// # Performance
2873///
2874/// Uses a simple pattern match on the node variant, making it very efficient
2875/// for use in performance-critical code.
2876///
2877/// # See Also
2878///
2879/// * [`assert_symbol_node_type`] - Similar function that returns an error
2880///   instead of `None`
2881/// * [`SymbolParseNode`] - Type alias for symbol parse nodes
2882/// * [`assert_node_type`] - More general type checking function
2883#[must_use]
2884pub fn check_symbol_node_type(node: Option<&AnyParseNode>) -> Option<NodeType> {
2885    let node = node?;
2886
2887    // Check if this node is one of the symbol types
2888    match node {
2889        AnyParseNode::Atom(_)
2890        | AnyParseNode::MathOrd(_)
2891        | AnyParseNode::Spacing(_)
2892        | AnyParseNode::TextOrd(_)
2893        | AnyParseNode::AccentToken(_)
2894        | AnyParseNode::OpToken(_) => Some(NodeType::from(node)),
2895        _ => None,
2896    }
2897}
2898
2899/// Asserts that a parse node is a symbol-type element and returns the node
2900/// type, or returns an error.
2901///
2902/// This function is similar to [`check_symbol_node_type`] but returns a
2903/// [`ParseNodeError`] instead of `None` when the node is not a symbol type.
2904/// It's useful when you require a symbol node and want detailed error
2905/// information about why the assertion failed.
2906///
2907/// # Symbol Node Types
2908///
2909/// The following [`AnyParseNode`] variants are considered symbol nodes:
2910/// * [`AnyParseNode::Atom`] - Atomic symbols with mathematical meaning
2911/// * [`AnyParseNode::MathOrd`] - Ordinary mathematical symbols
2912/// * [`AnyParseNode::Op`] - Mathematical operators
2913/// * [`AnyParseNode::Spacing`] - Explicit spacing elements
2914/// * [`AnyParseNode::TextOrd`] - Text symbols in math mode
2915/// * [`AnyParseNode::AccentToken`] - Accent symbol components
2916/// * [`AnyParseNode::OpToken`] - Operator symbol components
2917///
2918/// # Parameters
2919///
2920/// * `node` - An optional reference to the parse node to check
2921///
2922/// # Returns
2923///
2924/// * `Ok(NodeType)` - The node type if it's a symbol node
2925/// * `Err(ParseNodeError::NotSymbolNode)` - If the node is not a symbol node
2926/// * `Err(ParseNodeError::NotSymbolNode)` - If `node` is `None` (with "null" as
2927///   the type)
2928///
2929/// # Error Handling
2930///
2931/// Provides detailed error information through
2932/// [`ParseNodeError::NotSymbolNode`], including the actual node type that was
2933/// encountered.
2934///
2935/// # Usage
2936///
2937/// Use this function when you need to ensure a node is a symbol type and want
2938/// to handle the error case explicitly, rather than just checking and
2939/// proceeding.
2940///
2941/// # Performance
2942///
2943/// Similar performance characteristics to [`check_symbol_node_type`], with the
2944/// added overhead of error construction on failure.
2945///
2946/// # See Also
2947///
2948/// * [`check_symbol_node_type`] - Non-panicking version that returns `Option`
2949/// * [`SymbolParseNode`] - Type alias for symbol parse nodes
2950/// * [`ParseNodeError`] - Error type returned on failure
2951pub fn assert_symbol_node_type(node: Option<&AnyParseNode>) -> Result<NodeType, ParseNodeError> {
2952    check_symbol_node_type(node).ok_or_else(|| {
2953        let actual = node.map_or_else(|| "null".to_owned(), |n| NodeType::from(n).to_string());
2954
2955        ParseNodeError::NotSymbolNode { actual }
2956    })
2957}
2958
2959#[cfg(test)]
2960mod tests {
2961    use super::*;
2962
2963    #[test]
2964    fn test_assert_node_type_success() {
2965        let node = AnyParseNode::Atom(ParseNodeAtom {
2966            family: Atom::Bin,
2967            mode: Mode::Math,
2968            loc: None,
2969            text: "+".to_owned(),
2970        });
2971
2972        let result = assert_node_type(Some(&node), NodeType::Atom);
2973        assert!(result.is_ok());
2974        assert_eq!(result.unwrap(), NodeType::Atom);
2975    }
2976
2977    #[test]
2978    fn test_assert_node_type_failure() {
2979        let node = AnyParseNode::Atom(ParseNodeAtom {
2980            family: Atom::Bin,
2981            mode: Mode::Math,
2982            loc: None,
2983            text: "+".to_owned(),
2984        });
2985
2986        let result = assert_node_type(Some(&node), NodeType::MathOrd);
2987        assert!(result.is_err());
2988        assert_eq!(
2989            result.unwrap_err(),
2990            ParseNodeError::TypeMismatch {
2991                expected: NodeType::MathOrd,
2992                actual: "atom".to_owned()
2993            }
2994        );
2995    }
2996
2997    #[test]
2998    fn test_assert_node_type_none() {
2999        let result = assert_node_type(None, NodeType::Atom);
3000        assert!(result.is_err());
3001        assert_eq!(
3002            result.unwrap_err(),
3003            ParseNodeError::TypeMismatch {
3004                expected: NodeType::Atom,
3005                actual: "null".to_owned()
3006            }
3007        );
3008    }
3009
3010    #[test]
3011    fn test_check_symbol_node_type_success() {
3012        let node = AnyParseNode::Atom(ParseNodeAtom {
3013            family: Atom::Bin,
3014            mode: Mode::Math,
3015            loc: None,
3016            text: "+".to_owned(),
3017        });
3018
3019        let result = check_symbol_node_type(Some(&node));
3020        assert!(result.is_some());
3021    }
3022
3023    #[test]
3024    fn test_check_symbol_node_type_failure() {
3025        let node = AnyParseNode::Array(ParseNodeArray {
3026            mode: Mode::Math,
3027            loc: None,
3028            col_separation_type: None,
3029            hskip_before_and_after: None,
3030            add_jot: None,
3031            cols: None,
3032            arraystretch: 1.0,
3033            body: vec![],
3034            row_gaps: vec![],
3035            h_lines_before_row: vec![],
3036            tags: None,
3037            leqno: None,
3038            is_cd: None,
3039        });
3040
3041        let result = check_symbol_node_type(Some(&node));
3042        assert!(result.is_none());
3043    }
3044
3045    #[test]
3046    fn test_assert_symbol_node_type_success() {
3047        let node = AnyParseNode::Atom(ParseNodeAtom {
3048            family: Atom::Bin,
3049            mode: Mode::Math,
3050            loc: None,
3051            text: "+".to_owned(),
3052        });
3053
3054        let result = assert_symbol_node_type(Some(&node));
3055        assert!(result.is_ok());
3056    }
3057
3058    #[test]
3059    fn test_assert_symbol_node_type_failure() {
3060        let node = AnyParseNode::Array(ParseNodeArray {
3061            mode: Mode::Math,
3062            loc: None,
3063            col_separation_type: None,
3064            hskip_before_and_after: None,
3065            add_jot: None,
3066            cols: None,
3067            arraystretch: 1.0,
3068            body: vec![],
3069            row_gaps: vec![],
3070            h_lines_before_row: vec![],
3071            tags: None,
3072            leqno: None,
3073            is_cd: None,
3074        });
3075
3076        let result = assert_symbol_node_type(Some(&node));
3077        assert!(result.is_err());
3078        assert_eq!(
3079            result.unwrap_err(),
3080            ParseNodeError::NotSymbolNode {
3081                actual: "array".to_owned()
3082            }
3083        );
3084    }
3085}