Skip to main content

katex_parser/
ast.rs

1use std::collections::HashMap;
2
3use crate::source_location::SourceLocation;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6/// The parsing mode: math or text.
7pub enum Mode {
8
9    Math,
10    Text,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14/// The math atom class of a symbol, used for spacing decisions.
15pub enum AtomFamily {
16
17    Mord,
18    Mop,
19    Mbin,
20    Mrel,
21    Mopen,
22    Mclose,
23    Mpunct,
24    Minner,
25}
26
27#[derive(Debug, Clone, PartialEq)]
28/// A dimension with a numeric value and a unit (e.g. `em`, `pt`).
29pub struct Measurement {
30    pub number: f64,
31    pub unit: String,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35/// The typesetting style level, as selected by \\displaystyle and friends.
36pub enum StyleLevel {
37
38    DisplayStyle,
39    TextStyle,
40    ScriptStyle,
41    ScriptScriptStyle,
42}
43
44#[derive(Debug, Clone, PartialEq)]
45/// The body of an `Op` node: a symbol, a named operator, or an argument body.
46pub enum OperatorContent {
47    SymbolOperator(String),
48    BodyOperator(Vec<ParseNode>),
49    NamedOperator(String),
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53/// Horizontal alignment of a `Lap` (mathllap/mathrlap/mathclap) node.
54pub enum LapAlignment {
55
56    LLap,
57    RLap,
58    CLap,
59}
60
61#[derive(Debug, Clone, PartialEq)]
62/// A column of an array environment: an alignment cell or a vertical separator.
63pub enum ArrayColumn {
64    AlignColumn {
65        alignment: String,
66        pre_gap: f64,
67        post_gap: f64,
68    },
69    SeparatorColumn {
70        separator: String,
71    },
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75/// How columns of an array are separated.
76pub enum ColumnSeparationType {
77
78    AlignSeparation,
79    AlignAtSeparation,
80    GatherSeparation,
81    SmallSeparation,
82    CdSeparation,
83}
84
85#[derive(Debug, Clone, PartialEq)]
86/// A parsed node in the LaTeX AST.
87pub enum ParseNode {
88    Internal { mode: Mode },
89    Raw { mode: Mode, string: String },
90    ColorToken { mode: Mode, color: String },
91    Size {
92        mode: Mode,
93        value: Measurement,
94        is_blank: bool,
95    },
96    Url { mode: Mode, url: String },
97    Styling {
98        mode: Mode,
99        body: Vec<ParseNode>,
100        style: StyleLevel,
101        reset_font: bool,
102    },
103    Sqrt {
104        mode: Mode,
105        body: Box<ParseNode>,
106        index: Option<Box<ParseNode>>,
107    },
108    Infix {
109        mode: Mode,
110        replace_with: String,
111        size: Option<Measurement>,
112        loc: Option<SourceLocation>,
113    },
114    GenFrac {
115        mode: Mode,
116        numer: Box<ParseNode>,
117        denom: Box<ParseNode>,
118        continued: bool,
119        has_bar_line: bool,
120        bar_size: Option<Measurement>,
121        left_delim: Option<String>,
122        right_delim: Option<String>,
123    },
124    Text {
125        mode: Mode,
126        body: Vec<ParseNode>,
127        font: String,
128    },
129    Font {
130        mode: Mode,
131        font: String,
132        body: Box<ParseNode>,
133    },
134    MClass {
135        mode: Mode,
136        mclass: AtomFamily,
137        body: Vec<ParseNode>,
138        is_character_box: bool,
139    },
140    Op {
141        mode: Mode,
142        limits: bool,
143        always_handle_sup_sub: bool,
144        parent_is_sup_sub: bool,
145        suppress_base_shift: bool,
146        content: OperatorContent,
147    },
148    OperatorName {
149        mode: Mode,
150        body: Vec<ParseNode>,
151        always_handle_sup_sub: bool,
152        limits: bool,
153        parent_is_sup_sub: bool,
154    },
155    Overline { mode: Mode, body: Box<ParseNode> },
156    Underline { mode: Mode, body: Box<ParseNode> },
157    Smash {
158        mode: Mode,
159        body: Box<ParseNode>,
160        smash_height: bool,
161        smash_depth: bool,
162    },
163    Phantom { mode: Mode, body: Vec<ParseNode> },
164    VPhantom { mode: Mode, body: Box<ParseNode> },
165    Pmb {
166        mode: Mode,
167        mclass: AtomFamily,
168        body: Vec<ParseNode>,
169    },
170    VCenter { mode: Mode, body: Box<ParseNode> },
171    Rule {
172        mode: Mode,
173        shift: Option<Measurement>,
174        width: Measurement,
175        height: Measurement,
176    },
177    RaiseBox {
178        mode: Mode,
179        dy: Measurement,
180        body: Box<ParseNode>,
181    },
182    HBox { mode: Mode, body: Vec<ParseNode> },
183    Lap {
184        mode: Mode,
185        alignment: LapAlignment,
186        body: Box<ParseNode>,
187    },
188    MathChoice {
189        mode: Mode,
190        display: Vec<ParseNode>,
191        text: Vec<ParseNode>,
192        script: Vec<ParseNode>,
193        scriptscript: Vec<ParseNode>,
194    },
195    Sizing {
196        mode: Mode,
197        size: usize,
198        body: Vec<ParseNode>,
199    },
200    HorizBrace {
201        mode: Mode,
202        label: String,
203        is_over: bool,
204        base: Box<ParseNode>,
205    },
206    XArrow {
207        mode: Mode,
208        label: String,
209        body: Box<ParseNode>,
210        below: Option<Box<ParseNode>>,
211    },
212    AccentUnder {
213        mode: Mode,
214        label: String,
215        base: Box<ParseNode>,
216    },
217    DelimSizing {
218        mode: Mode,
219        size: usize,
220        mclass: AtomFamily,
221        delim: String,
222    },
223    LeftRightRight {
224        mode: Mode,
225        delim: String,
226        color: Option<String>,
227    },
228    LeftRight {
229        mode: Mode,
230        body: Vec<ParseNode>,
231        left: String,
232        right: String,
233        right_color: Option<String>,
234    },
235    Middle { mode: Mode, delim: String },
236    Kern { mode: Mode, dimension: Measurement },
237    Enclose {
238        mode: Mode,
239        body: Box<ParseNode>,
240        label: String,
241        background_color: Option<String>,
242        border_color: Option<String>,
243    },
244    Href {
245        mode: Mode,
246        href: String,
247        body: Vec<ParseNode>,
248    },
249    Html {
250        mode: Mode,
251        attributes: HashMap<String, String>,
252        body: Vec<ParseNode>,
253    },
254    IncludeGraphics {
255        mode: Mode,
256        alt: String,
257        width: Measurement,
258        height: Measurement,
259        totalheight: Measurement,
260        src: String,
261    },
262    Tag {
263        mode: Mode,
264        body: Vec<ParseNode>,
265        tag: Vec<ParseNode>,
266    },
267    Array {
268        mode: Mode,
269        body: Vec<Vec<ParseNode>>,
270        add_jot: bool,
271        array_stretch: f64,
272        columns: Option<Vec<ArrayColumn>>,
273        row_gaps: Vec<Option<Measurement>>,
274        hskip_before_and_after: bool,
275        hlines_before_row: Vec<Vec<bool>>,
276        column_separation_type: Option<ColumnSeparationType>,
277        tags: Option<Vec<Option<Vec<ParseNode>>>>,
278        auto_tags: Option<Vec<bool>>,
279        leqno: bool,
280    },
281    EnvironmentEnd { mode: Mode, name: String },
282    CdLabel {
283        mode: Mode,
284        side: String,
285        label: Box<ParseNode>,
286    },
287    CdParent {
288        mode: Mode,
289        fragment: Box<ParseNode>,
290    },
291    Cr {
292        mode: Mode,
293        new_line: bool,
294        size: Option<Measurement>,
295    },
296    HtmlMathML {
297        mode: Mode,
298        html: Vec<ParseNode>,
299        mathml: Vec<ParseNode>,
300    },
301    OrdGroup {
302        mode: Mode,
303        loc: Option<SourceLocation>,
304        body: Vec<ParseNode>,
305        semisimple: bool,
306    },
307    SupSub {
308        mode: Mode,
309        base: Option<Box<ParseNode>>,
310        sup: Option<Box<ParseNode>>,
311        sub: Option<Box<ParseNode>>,
312    },
313    TextOrd {
314        mode: Mode,
315        loc: Option<SourceLocation>,
316        text: String,
317    },
318    MathOrd {
319        mode: Mode,
320        loc: Option<SourceLocation>,
321        text: String,
322    },
323    Spacing {
324        mode: Mode,
325        loc: Option<SourceLocation>,
326        text: String,
327    },
328    AccentToken {
329        mode: Mode,
330        loc: Option<SourceLocation>,
331        text: String,
332    },
333    OperatorToken {
334        mode: Mode,
335        loc: Option<SourceLocation>,
336        text: String,
337    },
338    Accent {
339        mode: Mode,
340        loc: Option<SourceLocation>,
341        label: String,
342        is_stretchy: bool,
343        is_shifty: bool,
344        base: Box<ParseNode>,
345    },
346    Verb {
347        mode: Mode,
348        loc: Option<SourceLocation>,
349        body: String,
350        star: bool,
351    },
352    Atom {
353        mode: Mode,
354        loc: Option<SourceLocation>,
355        family: AtomFamily,
356        text: String,
357    },
358    Color {
359        mode: Mode,
360        color: String,
361        body: Vec<ParseNode>,
362    },
363}
364
365impl ParseNode {
366    /// Returns the [`Mode`] this node was parsed in.
367    pub fn mode(&self) -> Mode {
368        match self {
369            ParseNode::Internal { mode }
370            | ParseNode::Raw { mode, .. }
371            | ParseNode::ColorToken { mode, .. }
372            | ParseNode::Size { mode, .. }
373            | ParseNode::Url { mode, .. }
374            | ParseNode::Styling { mode, .. }
375            | ParseNode::Sqrt { mode, .. }
376            | ParseNode::Infix { mode, .. }
377            | ParseNode::GenFrac { mode, .. }
378            | ParseNode::Text { mode, .. }
379            | ParseNode::Font { mode, .. }
380            | ParseNode::MClass { mode, .. }
381            | ParseNode::Op { mode, .. }
382            | ParseNode::OperatorName { mode, .. }
383            | ParseNode::Overline { mode, .. }
384            | ParseNode::Underline { mode, .. }
385            | ParseNode::Smash { mode, .. }
386            | ParseNode::Phantom { mode, .. }
387            | ParseNode::VPhantom { mode, .. }
388            | ParseNode::Pmb { mode, .. }
389            | ParseNode::VCenter { mode, .. }
390            | ParseNode::Rule { mode, .. }
391            | ParseNode::RaiseBox { mode, .. }
392            | ParseNode::HBox { mode, .. }
393            | ParseNode::Lap { mode, .. }
394            | ParseNode::MathChoice { mode, .. }
395            | ParseNode::Sizing { mode, .. }
396            | ParseNode::HorizBrace { mode, .. }
397            | ParseNode::XArrow { mode, .. }
398            | ParseNode::AccentUnder { mode, .. }
399            | ParseNode::DelimSizing { mode, .. }
400            | ParseNode::LeftRightRight { mode, .. }
401            | ParseNode::LeftRight { mode, .. }
402            | ParseNode::Middle { mode, .. }
403            | ParseNode::Kern { mode, .. }
404            | ParseNode::Enclose { mode, .. }
405            | ParseNode::Href { mode, .. }
406            | ParseNode::Html { mode, .. }
407            | ParseNode::IncludeGraphics { mode, .. }
408            | ParseNode::Tag { mode, .. }
409            | ParseNode::Array { mode, .. }
410            | ParseNode::EnvironmentEnd { mode, .. }
411            | ParseNode::CdLabel { mode, .. }
412            | ParseNode::CdParent { mode, .. }
413            | ParseNode::Cr { mode, .. }
414            | ParseNode::HtmlMathML { mode, .. }
415            | ParseNode::OrdGroup { mode, .. }
416            | ParseNode::SupSub { mode, .. }
417            | ParseNode::TextOrd { mode, .. }
418            | ParseNode::MathOrd { mode, .. }
419            | ParseNode::Spacing { mode, .. }
420            | ParseNode::AccentToken { mode, .. }
421            | ParseNode::OperatorToken { mode, .. }
422            | ParseNode::Accent { mode, .. }
423            | ParseNode::Verb { mode, .. }
424            | ParseNode::Atom { mode, .. }
425            | ParseNode::Color { mode, .. } => *mode,
426        }
427    }
428}