tex_parser/
ast.rs

1// SPDX-License-Identifier: LGPL-2.1-or-later
2// See Notices.txt for copyright information
3
4use input_context::InputContext;
5use peg::Parse;
6#[cfg(feature = "serde")]
7use serde::Serialize;
8use std::{borrow::Cow, fmt, str::FromStr};
9
10pub mod input_context;
11
12#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
13pub struct Pos {
14    pub byte_index: usize,
15}
16
17pub trait GetPos {
18    fn pos(&self) -> Pos;
19}
20
21impl<T: ?Sized + GetPos> GetPos for &'_ T {
22    fn pos(&self) -> Pos {
23        (**self).pos()
24    }
25}
26
27impl<T: ?Sized + GetPos> GetPos for &'_ mut T {
28    fn pos(&self) -> Pos {
29        (**self).pos()
30    }
31}
32
33impl GetPos for Pos {
34    fn pos(&self) -> Pos {
35        *self
36    }
37}
38
39macro_rules! impl_get_pos_simple {
40    ($name:ident) => {
41        impl GetPos for $name {
42            fn pos(&self) -> Pos {
43                self.pos
44            }
45        }
46    };
47}
48
49#[cfg(feature = "serde")]
50impl Serialize for Pos {
51    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
52    where
53        S: serde::Serializer,
54    {
55        format!("{:?}", self).serialize(serializer)
56    }
57}
58
59impl fmt::Debug for Pos {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        Self::get_input_context(|input: Option<InputContext<'_>>| match input {
62            Some(input) if input.input.get(..self.byte_index).is_some() => {
63                write!(f, "@{}", input.input.position_repr(self.byte_index))
64            }
65            _ => write!(f, "@{}", self.byte_index),
66        })
67    }
68}
69
70impl Pos {
71    pub fn new(byte_index: usize) -> Self {
72        Self { byte_index }
73    }
74}
75
76#[cfg_attr(feature = "serde", derive(Serialize))]
77#[derive(Debug, Clone)]
78pub struct Escape {
79    pub pos: Pos,
80}
81
82impl_get_pos_simple!(Escape);
83
84#[cfg_attr(feature = "serde", derive(Serialize))]
85#[derive(Debug, Clone)]
86pub struct BeginGroup {
87    pub pos: Pos,
88}
89
90impl_get_pos_simple!(BeginGroup);
91
92#[cfg_attr(feature = "serde", derive(Serialize))]
93#[derive(Debug, Clone)]
94pub struct EndGroup {
95    pub pos: Pos,
96}
97
98impl_get_pos_simple!(EndGroup);
99
100#[cfg_attr(feature = "serde", derive(Serialize))]
101#[derive(Debug, Clone)]
102pub struct AlignmentTab {
103    pub pos: Pos,
104}
105
106impl_get_pos_simple!(AlignmentTab);
107
108#[cfg_attr(feature = "serde", derive(Serialize))]
109#[derive(Debug, Clone)]
110pub struct MacroParameter {
111    pub pos: Pos,
112}
113
114impl_get_pos_simple!(MacroParameter);
115
116#[cfg_attr(feature = "serde", derive(Serialize))]
117#[derive(Debug, Clone)]
118pub struct CommentStart {
119    pub pos: Pos,
120}
121
122impl_get_pos_simple!(CommentStart);
123
124#[cfg_attr(feature = "serde", derive(Serialize))]
125#[derive(Debug, Clone)]
126pub struct MathShift {
127    pub pos: Pos,
128}
129
130impl_get_pos_simple!(MathShift);
131
132#[cfg_attr(feature = "serde", derive(Serialize))]
133#[derive(Debug, Clone)]
134pub struct Superscript {
135    pub pos: Pos,
136}
137
138impl_get_pos_simple!(Superscript);
139
140#[cfg_attr(feature = "serde", derive(Serialize))]
141#[derive(Debug, Clone)]
142pub struct Subscript {
143    pub pos: Pos,
144}
145
146impl_get_pos_simple!(Subscript);
147
148#[cfg_attr(feature = "serde", derive(Serialize))]
149#[derive(Debug, Clone)]
150pub struct Ignore {
151    pub pos: Pos,
152}
153
154impl_get_pos_simple!(Ignore);
155
156#[cfg_attr(feature = "serde", derive(Serialize))]
157#[derive(Debug, Clone)]
158pub struct AnyChar {
159    pub pos: Pos,
160    pub ch: char,
161}
162
163impl_get_pos_simple!(AnyChar);
164
165#[cfg_attr(feature = "serde", derive(Serialize))]
166#[derive(Debug, Clone)]
167pub struct Punctuation {
168    pub pos: Pos,
169    pub ch: char,
170}
171
172impl_get_pos_simple!(Punctuation);
173
174#[cfg_attr(feature = "serde", derive(Serialize))]
175#[derive(Debug, Clone)]
176pub struct Space {
177    pub pos: Pos,
178}
179
180impl_get_pos_simple!(Space);
181
182#[cfg_attr(feature = "serde", derive(Serialize))]
183#[derive(Debug, Clone)]
184pub struct AsciiAlphabetic {
185    pub pos: Pos,
186}
187
188impl_get_pos_simple!(AsciiAlphabetic);
189
190#[cfg_attr(feature = "serde", derive(Serialize))]
191#[derive(Debug, Clone)]
192pub struct AsciiDigit {
193    pub pos: Pos,
194}
195
196impl_get_pos_simple!(AsciiDigit);
197
198#[cfg_attr(feature = "serde", derive(Serialize))]
199#[derive(Debug, Clone)]
200pub struct NewLine {
201    pub pos: Pos,
202}
203
204impl_get_pos_simple!(NewLine);
205
206#[cfg_attr(feature = "serde", derive(Serialize))]
207#[derive(Debug, Clone)]
208pub struct CharToken {
209    pub pos: Pos,
210}
211
212impl_get_pos_simple!(CharToken);
213
214#[cfg_attr(feature = "serde", derive(Serialize))]
215#[derive(Debug, Clone)]
216pub struct CharTokens {
217    pub pos: Pos,
218    pub content: String,
219}
220
221impl CharTokens {
222    pub fn split_off(&mut self, index: usize) -> Self {
223        let content = self.content.split_off(index);
224        Self {
225            pos: Pos {
226                byte_index: self.pos.byte_index + index,
227            },
228            content,
229        }
230    }
231    pub fn split_at(mut self, index: usize) -> (Self, Self) {
232        let tail = self.split_off(index);
233        (self, tail)
234    }
235}
236
237impl_get_pos_simple!(CharTokens);
238
239#[cfg_attr(feature = "serde", derive(Serialize))]
240#[derive(Debug, Clone)]
241pub struct Document {
242    pub content: Vec<Token>,
243}
244
245impl GetPos for Document {
246    fn pos(&self) -> Pos {
247        self.content
248            .first()
249            .map_or(Pos { byte_index: 0 }, GetPos::pos)
250    }
251}
252
253macro_rules! declare_nested_access_fns {
254    ($alternative:ident($alternative_fn:ident, $alternative_mut_fn:ident, $into_alternative_fn:ident), ($outer_alternative_fn:ident, $outer_alternative_mut_fn:ident, $outer_into_alternative_fn:ident)) => {
255        pub fn $alternative_fn(&self) -> Option<&$alternative> {
256            self.$outer_alternative_fn()?.$alternative_fn()
257        }
258        pub fn $alternative_mut_fn(&mut self) -> Option<&mut $alternative> {
259            self.$outer_alternative_mut_fn()?.$alternative_mut_fn()
260        }
261        pub fn $into_alternative_fn(self) -> Option<$alternative> {
262            self.$outer_into_alternative_fn()?.$into_alternative_fn()
263        }
264    };
265}
266
267macro_rules! declare_transparent_enum {
268    (
269        #[serde(tag = $tag:literal)]
270        #[access_fns_macro = $access_fns_macro:ident]
271        enum $name:ident {
272            $(
273                $(#[nested_access_fns = $nested_access_fns:ident])?
274                $alternative:ident($alternative_fn:ident, $alternative_mut_fn:ident, $into_alternative_fn:ident),
275            )+
276        }
277    ) => {
278        #[cfg_attr(feature = "serde", derive(Serialize))]
279        #[derive(Clone)]
280        #[cfg_attr(feature = "serde", serde(tag = $tag))]
281        pub enum $name {
282            $($alternative($alternative),)+
283        }
284
285        #[allow(unused_macros)]
286        macro_rules! $access_fns_macro {
287            ($m:ident!($tt:tt)) => {
288                $($m!($alternative($alternative_fn, $alternative_mut_fn, $into_alternative_fn), $tt);)+
289            };
290        }
291
292        impl $name {
293            $(
294                pub fn $alternative_fn(&self) -> Option<&$alternative> {
295                    if let Self::$alternative(v) = self {
296                        Some(v)
297                    } else {
298                        None
299                    }
300                }
301                pub fn $alternative_mut_fn(&mut self) -> Option<&mut $alternative> {
302                    if let Self::$alternative(v) = self {
303                        Some(v)
304                    } else {
305                        None
306                    }
307                }
308                pub fn $into_alternative_fn(self) -> Option<$alternative> {
309                    if let Self::$alternative(v) = self {
310                        Some(v)
311                    } else {
312                        None
313                    }
314                }
315                $(
316                    $nested_access_fns!(declare_nested_access_fns!(($alternative_fn, $alternative_mut_fn, $into_alternative_fn)));
317                )?
318            )+
319        }
320
321        impl GetPos for $name {
322            fn pos(&self) -> Pos {
323                match self {
324                    $(Self::$alternative(v) => v.pos(),)+
325                }
326            }
327        }
328
329        impl fmt::Debug for $name {
330            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331                match self {
332                    $(Self::$alternative(v) => fmt::Debug::fmt(v, f),)+
333                }
334            }
335        }
336    };
337}
338
339declare_transparent_enum! {
340    #[serde(tag = "special_macro_type")]
341    #[access_fns_macro = special_macro_access_fns]
342    enum SpecialMacro {
343        Verb(verb, verb_mut, into_verb),
344        VerbatimEnvironment(verbatim_environment, verbatim_environment_mut, into_verbatim_environment),
345        DisplayMath(display_math, display_math_mut, into_display_math),
346        ParenthesizedInlineMath(parenthesized_inline_math, parenthesized_inline_math_mut, into_parenthesized_inline_math),
347        MathEnvironment(math_environment, math_environment_mut, into_math_environment),
348        Environment(environment, environment_mut, into_environment),
349    }
350}
351
352declare_transparent_enum! {
353    #[serde(tag = "token_type")]
354    #[access_fns_macro = token_access_fns]
355    enum Token {
356        #[nested_access_fns = special_macro_access_fns]
357        SpecialMacro(special_macro, special_macro_mut, into_special_macro),
358        Macro(macro_, macro_mut, into_macro),
359        FullComment(full_comment, full_comment_mut, into_full_comment),
360        Group(group, group_mut, into_group),
361        DollarInlineMath(dollar_inline_math, dollar_inline_math_mut, into_dollar_inline_math),
362        AlignmentTab(alignment_tab, alignment_tab_mut, into_alignment_tab),
363        ParBreak(par_break, par_break_mut, into_par_break),
364        MacroParameter(macro_parameter, macro_parameter_mut, into_macro_parameter),
365        Ignore(ignore, ignore_mut, into_ignore),
366        Number(number, number_mut, into_number),
367        Whitespace(whitespace, whitespace_mut, into_whitespace),
368        Punctuation(punctuation, punctuation_mut, into_punctuation),
369        CharTokens(char_tokens, char_tokens_mut, into_char_tokens),
370        BeginGroup(begin_group, begin_group_mut, into_begin_group),
371        EndGroup(end_group, end_group_mut, into_end_group),
372        MathShift(math_shift, math_shift_mut, into_math_shift),
373    }
374}
375
376pub struct SplitCharTokensIter<Iter> {
377    next_chars: Option<CharTokens>,
378    iter: Iter,
379}
380
381impl<Iter: Iterator> SplitCharTokensIter<Iter> {
382    pub fn new<T: IntoIterator<IntoIter = Iter>>(iter: T) -> Self {
383        Self {
384            next_chars: None,
385            iter: iter.into_iter(),
386        }
387    }
388    pub fn into(self) -> (Option<CharTokens>, Iter) {
389        (self.next_chars, self.iter)
390    }
391    fn take_first_char(&mut self, next_chars: Option<CharTokens>) -> Option<CharTokens> {
392        let next_chars = next_chars?;
393        let ch = next_chars.content.chars().next()?;
394        let (retval, rest) = next_chars.split_at(ch.len_utf8());
395        if !rest.content.is_empty() {
396            self.next_chars = Some(rest);
397        }
398        Some(retval)
399    }
400}
401
402mod sealed {
403    pub trait Sealed {}
404    impl Sealed for super::Token {}
405    impl Sealed for &'_ super::Token {}
406}
407
408pub trait SplitCharTokensIterHelper: Sized + sealed::Sealed {
409    type Item;
410    fn next<I: Iterator<Item = Self>>(this: &mut SplitCharTokensIter<I>) -> Option<Self::Item>;
411}
412
413impl SplitCharTokensIterHelper for Token {
414    type Item = Token;
415
416    fn next<I: Iterator<Item = Self>>(this: &mut SplitCharTokensIter<I>) -> Option<Self::Item> {
417        let next_chars = this.next_chars.take();
418        if let Some(retval) = this.take_first_char(next_chars) {
419            return Some(Token::CharTokens(retval));
420        }
421        loop {
422            match this.iter.next()? {
423                Token::CharTokens(next_chars) => {
424                    if let Some(retval) = this.take_first_char(Some(next_chars)) {
425                        return Some(Token::CharTokens(retval));
426                    }
427                }
428                retval => return Some(retval),
429            }
430        }
431    }
432}
433
434impl<'a> SplitCharTokensIterHelper for &'a Token {
435    type Item = Cow<'a, Token>;
436
437    fn next<I: Iterator<Item = Self>>(this: &mut SplitCharTokensIter<I>) -> Option<Self::Item> {
438        let next_chars = this.next_chars.take();
439        if let Some(retval) = this.take_first_char(next_chars) {
440            return Some(Cow::Owned(Token::CharTokens(retval)));
441        }
442        loop {
443            match this.iter.next()? {
444                Token::CharTokens(next_chars) => {
445                    if let Some(retval) = this.take_first_char(Some(next_chars.clone())) {
446                        return Some(Cow::Owned(Token::CharTokens(retval)));
447                    }
448                }
449                retval => return Some(Cow::Borrowed(retval)),
450            }
451        }
452    }
453}
454
455impl<I, Item> Iterator for SplitCharTokensIter<I>
456where
457    I: Iterator<Item = Item>,
458    Item: SplitCharTokensIterHelper,
459{
460    type Item = Item::Item;
461
462    fn next(&mut self) -> Option<Self::Item> {
463        Item::next(self)
464    }
465}
466
467declare_transparent_enum! {
468    #[serde(tag = "math_token_type")]
469    #[access_fns_macro = math_token_access_fns]
470    enum MathToken {
471        #[nested_access_fns = special_macro_access_fns]
472        SpecialMacro(special_macro, special_macro_mut, into_special_macro),
473        Macro(macro_, macro_mut, into_macro),
474        FullComment(full_comment, full_comment_mut, into_full_comment),
475        MathGroup(math_group, math_group_mut, into_math_group),
476        AlignmentTab(alignment_tab, alignment_tab_mut, into_alignment_tab),
477        MacroParameter(macro_parameter, macro_parameter_mut, into_macro_parameter),
478        Superscript(superscript, superscript_mut, into_superscript),
479        Subscript(subscript, subscript_mut, into_subscript),
480        Ignore(ignore, ignore_mut, into_ignore),
481        Whitespace(whitespace, whitespace_mut, into_whitespace),
482        Number(number, number_mut, number_char),
483        AnyChar(any_char, any_char_mut, into_any_char),
484    }
485}
486
487#[cfg_attr(feature = "serde", derive(Serialize))]
488#[derive(Debug, Clone)]
489pub struct Verb {
490    pub escape: Escape,
491    pub env: String,
492    pub delimiter: char,
493    pub content: String,
494}
495
496impl GetPos for Verb {
497    fn pos(&self) -> Pos {
498        self.escape.pos()
499    }
500}
501
502#[cfg_attr(feature = "serde", derive(Serialize))]
503#[derive(Debug, Clone)]
504pub struct ParenthesizedInlineMath {
505    pub begin: BeginInlineMath,
506    pub content: Vec<MathToken>,
507    pub end: EndInlineMath,
508}
509
510impl ParenthesizedInlineMath {
511    pub fn content_pos(&self) -> Pos {
512        self.content.first().map_or(self.end.pos(), GetPos::pos)
513    }
514}
515
516impl GetPos for ParenthesizedInlineMath {
517    fn pos(&self) -> Pos {
518        self.begin.pos()
519    }
520}
521
522#[cfg_attr(feature = "serde", derive(Serialize))]
523#[derive(Debug, Clone)]
524pub struct DollarInlineMath {
525    pub begin: MathShift,
526    pub content: Vec<MathToken>,
527    pub end: MathShift,
528}
529
530impl DollarInlineMath {
531    pub fn content_pos(&self) -> Pos {
532        self.content.first().map_or(self.end.pos(), GetPos::pos)
533    }
534}
535
536impl GetPos for DollarInlineMath {
537    fn pos(&self) -> Pos {
538        self.begin.pos()
539    }
540}
541
542#[cfg_attr(feature = "serde", derive(Serialize))]
543#[derive(Debug, Clone)]
544pub struct VerbatimEnvironment {
545    pub begin: BeginEnvironment,
546    pub name: VerbatimEnvironmentName,
547    pub body: String,
548    pub end: EndEnvironment,
549}
550
551impl GetPos for VerbatimEnvironment {
552    fn pos(&self) -> Pos {
553        self.begin.pos()
554    }
555}
556
557#[cfg_attr(feature = "serde", derive(Serialize))]
558#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
559pub enum VerbatimEnvironmentNameKind {
560    VerbatimStar,
561    Verbatim,
562    FileContentsStar,
563    FileContents,
564    Comment,
565    ListListing,
566}
567
568#[cfg_attr(feature = "serde", derive(Serialize))]
569#[derive(Debug, Clone)]
570pub struct VerbatimEnvironmentName {
571    pub pos: Pos,
572    pub kind: VerbatimEnvironmentNameKind,
573}
574
575impl_get_pos_simple!(VerbatimEnvironmentName);
576
577#[cfg_attr(feature = "serde", derive(Serialize))]
578#[derive(Debug, Clone)]
579pub struct DisplayMath {
580    pub pos: Pos,
581    pub content: Vec<MathToken>,
582}
583
584impl_get_pos_simple!(DisplayMath);
585
586#[cfg_attr(feature = "serde", derive(Serialize))]
587#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
588pub enum MathEnvironmentNameKind {
589    EquationStar,
590    Equation,
591    AlignStar,
592    Align,
593    AlignAtStar,
594    AlignAt,
595    GatherStar,
596    Gather,
597    MultiLineStar,
598    MultiLine,
599    FlAlignStar,
600    FlAlign,
601    Split,
602    Math,
603    DisplayMath,
604}
605
606#[cfg_attr(feature = "serde", derive(Serialize))]
607#[derive(Debug, Clone)]
608pub struct MathEnvironmentName {
609    pub pos: Pos,
610    pub kind: MathEnvironmentNameKind,
611}
612
613impl_get_pos_simple!(MathEnvironmentName);
614
615#[cfg_attr(feature = "serde", derive(Serialize))]
616#[derive(Debug, Clone)]
617pub struct MathEnvironment {
618    pub begin: BeginEnvironment,
619    pub name: MathEnvironmentName,
620    pub environment_comment: Option<SameLineComment>,
621    pub body: Vec<MathToken>,
622    pub end: EndEnvironment,
623}
624
625impl MathEnvironment {
626    pub fn environment_comment_pos(&self) -> Pos {
627        self.environment_comment
628            .as_ref()
629            .map_or_else(|| self.body_pos(), GetPos::pos)
630    }
631    pub fn body_pos(&self) -> Pos {
632        self.body.first().map_or(self.end.pos(), GetPos::pos)
633    }
634}
635
636impl GetPos for MathEnvironment {
637    fn pos(&self) -> Pos {
638        self.begin.pos()
639    }
640}
641
642#[cfg_attr(feature = "serde", derive(Serialize))]
643#[derive(Debug, Clone)]
644pub struct Environment {
645    pub begin: BeginEnvironment,
646    pub name: CharTokens,
647    pub body: Vec<Token>,
648    pub end: EndEnvironment,
649}
650
651impl Environment {
652    pub fn body_pos(&self) -> Pos {
653        self.body.first().map_or(self.end.pos(), GetPos::pos)
654    }
655}
656
657impl GetPos for Environment {
658    fn pos(&self) -> Pos {
659        self.begin.pos()
660    }
661}
662
663#[cfg_attr(feature = "serde", derive(Serialize))]
664#[derive(Debug, Clone)]
665pub struct Number {
666    pub pos: Pos,
667    pub content: String,
668}
669
670impl Number {
671    pub fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
672        self.content.parse()
673    }
674    pub fn parse_with_err_arg<T: FromStr, E, A, ErrFn: FnOnce(A, Pos, String) -> E>(
675        &self,
676        err_fn_arg: A,
677        err_fn: ErrFn,
678    ) -> Result<T, E>
679    where
680        T::Err: fmt::Display,
681    {
682        self.parse()
683            .map_err(|e: T::Err| err_fn(err_fn_arg, self.pos, e.to_string()))
684    }
685}
686
687impl_get_pos_simple!(Number);
688
689#[cfg_attr(feature = "serde", derive(Serialize))]
690#[derive(Debug, Clone)]
691pub struct Group {
692    pub begin: BeginGroup,
693    pub tokens: Vec<Token>,
694    pub end: EndGroup,
695}
696
697impl Group {
698    pub fn tokens_pos(&self) -> Pos {
699        self.tokens.first().map_or(self.end.pos(), GetPos::pos)
700    }
701}
702
703impl GetPos for Group {
704    fn pos(&self) -> Pos {
705        self.begin.pos()
706    }
707}
708
709#[cfg_attr(feature = "serde", derive(Serialize))]
710#[derive(Debug, Clone)]
711pub struct MathGroup {
712    pub begin: BeginGroup,
713    pub tokens: Vec<MathToken>,
714    pub end: EndGroup,
715}
716
717impl MathGroup {
718    pub fn tokens_pos(&self) -> Pos {
719        self.tokens.first().map_or(self.end.pos(), GetPos::pos)
720    }
721}
722
723impl GetPos for MathGroup {
724    fn pos(&self) -> Pos {
725        self.begin.pos()
726    }
727}
728
729#[cfg_attr(feature = "serde", derive(Serialize))]
730#[derive(Debug, Clone)]
731pub struct Whitespace {
732    pub pos: Pos,
733}
734
735impl_get_pos_simple!(Whitespace);
736
737declare_transparent_enum! {
738    #[serde(tag = "comment_type")]
739    #[access_fns_macro = full_comment_access_fns]
740    enum FullComment {
741        OwnLineComment(own_line_comment, own_line_comment_mut, into_own_line_comment),
742        SameLineComment(same_line_comment, same_line_comment_mut, into_same_line_comment),
743    }
744}
745
746#[cfg_attr(feature = "serde", derive(Serialize))]
747#[derive(Debug, Clone)]
748pub struct OwnLineComment {
749    pub pos: Pos,
750    pub leading_space: LeadingSpace,
751    pub comment: Comment,
752}
753
754impl_get_pos_simple!(OwnLineComment);
755
756#[cfg_attr(feature = "serde", derive(Serialize))]
757#[derive(Debug, Clone)]
758pub struct SameLineComment {
759    pub pos: Pos,
760    pub leading_spaces: bool,
761    pub comment: Comment,
762}
763
764impl_get_pos_simple!(SameLineComment);
765
766#[cfg_attr(feature = "serde", derive(Serialize))]
767#[derive(Debug, Clone)]
768pub struct LeadingSpace {
769    pub pos: Pos,
770    pub empty: bool,
771}
772
773impl_get_pos_simple!(LeadingSpace);
774
775#[cfg_attr(feature = "serde", derive(Serialize))]
776#[derive(Debug, Clone)]
777pub struct Comment {
778    pub comment_start: CommentStart,
779    pub content: String,
780}
781
782#[cfg_attr(feature = "serde", derive(Serialize))]
783#[derive(Debug, Clone)]
784pub struct ParBreak {
785    pub pos: Pos,
786}
787
788impl_get_pos_simple!(ParBreak);
789
790#[cfg_attr(feature = "serde", derive(Serialize))]
791#[derive(Debug, Clone)]
792pub struct MacroName {
793    pub pos: Pos,
794    pub content: String,
795}
796
797impl_get_pos_simple!(MacroName);
798
799#[cfg_attr(feature = "serde", derive(Serialize))]
800#[derive(Debug, Clone)]
801pub struct Macro {
802    pub escape: Escape,
803    pub name: MacroName,
804}
805
806impl GetPos for Macro {
807    fn pos(&self) -> Pos {
808        self.escape.pos()
809    }
810}
811
812#[cfg_attr(feature = "serde", derive(Serialize))]
813#[derive(Debug, Clone)]
814pub struct BeginDisplayMath {
815    pub escape: Escape,
816}
817
818impl GetPos for BeginDisplayMath {
819    fn pos(&self) -> Pos {
820        self.escape.pos()
821    }
822}
823
824#[cfg_attr(feature = "serde", derive(Serialize))]
825#[derive(Debug, Clone)]
826pub struct EndDisplayMath {
827    pub escape: Escape,
828}
829
830impl GetPos for EndDisplayMath {
831    fn pos(&self) -> Pos {
832        self.escape.pos()
833    }
834}
835
836#[cfg_attr(feature = "serde", derive(Serialize))]
837#[derive(Debug, Clone)]
838pub struct BeginInlineMath {
839    pub escape: Escape,
840}
841
842impl GetPos for BeginInlineMath {
843    fn pos(&self) -> Pos {
844        self.escape.pos()
845    }
846}
847
848#[cfg_attr(feature = "serde", derive(Serialize))]
849#[derive(Debug, Clone)]
850pub struct EndInlineMath {
851    pub escape: Escape,
852}
853
854impl GetPos for EndInlineMath {
855    fn pos(&self) -> Pos {
856        self.escape.pos()
857    }
858}
859
860#[cfg_attr(feature = "serde", derive(Serialize))]
861#[derive(Debug, Clone)]
862pub struct BeginEnvironment {
863    pub escape: Escape,
864}
865
866impl GetPos for BeginEnvironment {
867    fn pos(&self) -> Pos {
868        self.escape.pos()
869    }
870}
871
872#[cfg_attr(feature = "serde", derive(Serialize))]
873#[derive(Debug, Clone)]
874pub struct EndEnvironment {
875    pub escape: Escape,
876}
877
878impl GetPos for EndEnvironment {
879    fn pos(&self) -> Pos {
880        self.escape.pos()
881    }
882}