Skip to main content

flams_stex/quickparse/latex/
mod.rs

1pub mod directives;
2pub mod rules;
3
4use crate::quickparse::tokens::TeXToken;
5use flams_utils::{
6    CondSerialize,
7    parsing::{SourceParser, StrParser, StringOrStr},
8    prelude::*,
9    sourcerefs::{StringPosition, StringRange},
10};
11use ftml_uris::Language;
12use rules::{AnyEnv, AnyMacro, EnvironmentResult, EnvironmentRule, MacroResult, MacroRule};
13use smallvec::SmallVec;
14use std::convert::Into;
15use std::{borrow::Cow, collections::hash_map::Entry};
16use tex_engine::utils::HMap;
17
18use super::stex::DiagnosticLevel;
19
20pub trait FromLaTeXToken<'a, Pos: StringPosition>: Sized + std::fmt::Debug {
21    fn from_comment(r: StringRange<Pos>) -> Option<Self>;
22    fn from_group(r: StringRange<Pos>, children: Vec<Self>) -> Option<Self>;
23    fn from_math(display: bool, r: StringRange<Pos>, children: Vec<Self>) -> Option<Self>;
24    fn from_control_sequence(start: Pos, name: &'a str) -> Option<Self>;
25    fn from_text(r: StringRange<Pos>, text: &'a str) -> Option<Self>;
26    fn from_macro_application(m: Macro<'a, Pos>) -> Option<Self>;
27    fn from_environment(e: Environment<'a, Pos, Self>) -> Option<Self>;
28}
29
30#[derive(Debug)]
31pub enum LaTeXToken<'a, Pos: StringPosition> {
32    Comment(StringRange<Pos>),
33    Group {
34        range: StringRange<Pos>,
35        children: Vec<Self>,
36    },
37    Math {
38        display: bool,
39        range: StringRange<Pos>,
40        children: Vec<Self>,
41    },
42    ControlSequence {
43        start: Pos,
44        name: &'a str,
45    },
46    Text {
47        range: StringRange<Pos>,
48        text: &'a str,
49    },
50    MacroApplication(Macro<'a, Pos>),
51    Environment(Environment<'a, Pos, Self>),
52}
53
54impl<'a, Pos: StringPosition> FromLaTeXToken<'a, Pos> for LaTeXToken<'a, Pos> {
55    #[inline]
56    fn from_comment(r: StringRange<Pos>) -> Option<Self> {
57        Some(LaTeXToken::Comment(r))
58    }
59    #[inline]
60    fn from_group(r: StringRange<Pos>, children: Vec<Self>) -> Option<Self> {
61        Some(LaTeXToken::Group { range: r, children })
62    }
63    #[inline]
64    fn from_math(display: bool, r: StringRange<Pos>, children: Vec<Self>) -> Option<Self> {
65        Some(LaTeXToken::Math {
66            display,
67            range: r,
68            children,
69        })
70    }
71    #[inline]
72    fn from_control_sequence(start: Pos, name: &'a str) -> Option<Self> {
73        Some(LaTeXToken::ControlSequence { start, name })
74    }
75    #[inline]
76    fn from_text(range: StringRange<Pos>, text: &'a str) -> Option<Self> {
77        Some(LaTeXToken::Text { range, text })
78    }
79    #[inline]
80    fn from_macro_application(m: Macro<'a, Pos>) -> Option<Self> {
81        Some(LaTeXToken::MacroApplication(m))
82    }
83    #[inline]
84    fn from_environment(e: Environment<'a, Pos, Self>) -> Option<Self> {
85        Some(LaTeXToken::Environment(e))
86    }
87}
88
89#[derive(Debug)]
90pub struct Macro<'a, Pos: StringPosition> {
91    pub token_range: StringRange<Pos>,
92    pub range: StringRange<Pos>,
93    pub name: &'a str,
94}
95
96#[derive(Debug)]
97pub struct Environment<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>> {
98    pub begin: Macro<'a, Pos>,
99    pub end: Option<Macro<'a, Pos>>,
100    pub name: &'a str,
101    pub name_range: StringRange<Pos>,
102    //pub args: Vec<T>,
103    pub children: Vec<T>,
104}
105
106pub struct OptArg<'a, Pos: StringPosition> {
107    inner: Option<&'a str>,
108    range: StringRange<Pos>,
109}
110
111impl<'a, Pos: StringPosition> OptArg<'a, Pos> {
112    #[inline]
113    pub const fn is_some(&self) -> bool {
114        self.inner.is_some()
115    }
116    pub fn into_name(self) -> Option<(&'a str, StringRange<Pos>)> {
117        self.inner.map(|i| (i, self.range))
118    }
119    pub fn as_keyvals(&'a self) -> VecMap<&'a str, OptVal<'a, Pos>> {
120        let mut map = VecMap::default();
121        if let Some(s) = &self.inner {
122            let mut curr = self.range;
123            for e in s.split_noparens_bytes(b'{', b'}', b',') {
124                if let Some((a, b)) = e.split_once('=') {
125                    curr.end += Pos::len(a);
126                    let key_range = curr;
127                    curr.end.inc_by('=');
128                    curr.start = curr.end;
129                    curr.end += Pos::len(b);
130                    let val_range = curr;
131                    curr.end.inc_by(',');
132                    curr.start = curr.end;
133                    let a = a.trim();
134                    map.insert(
135                        a,
136                        OptVal {
137                            key: a,
138                            key_range,
139                            val: b.trim(),
140                            val_range,
141                        },
142                    );
143                } else {
144                    curr.end += Pos::len(e);
145                    let key_range = curr;
146                    curr.end.inc_by(',');
147                    curr.start = curr.end;
148                    map.insert(
149                        e.trim(),
150                        OptVal {
151                            key: e,
152                            key_range,
153                            val: "",
154                            val_range: curr,
155                        },
156                    );
157                }
158            }
159        }
160        map
161    }
162}
163
164pub struct OptVal<'a, Pos: StringPosition> {
165    pub key: &'a str,
166    pub key_range: StringRange<Pos>,
167    pub val: &'a str,
168    pub val_range: StringRange<Pos>,
169}
170
171#[derive(Debug)]
172pub struct OptMapVal<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>> {
173    pub key_range: StringRange<Pos>,
174    pub val_range: StringRange<Pos>,
175    pub val: Vec<T>,
176    pub str: &'a str,
177}
178
179#[derive(Debug)]
180pub struct OptMap<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>> {
181    pub inner: VecMap<&'a str, OptMapVal<'a, Pos, T>>,
182}
183
184pub struct Group<
185    'a,
186    Pos: StringPosition,
187    T: FromLaTeXToken<'a, Pos>,
188    State: ParserState<'a, Pos, T>,
189> {
190    previous_letters: Option<String>,
191    #[allow(clippy::type_complexity)]
192    pub macro_rule_changes: HMap<Cow<'a, str>, Option<AnyMacro<'a, Pos, T, State>>>,
193    #[allow(clippy::type_complexity)]
194    pub environment_rule_changes: HMap<Cow<'a, str>, Option<AnyEnv<'a, Pos, T, State>>>,
195}
196
197pub trait GroupState<
198    'a,
199    Pos: StringPosition,
200    T: FromLaTeXToken<'a, Pos>,
201    State: ParserState<'a, Pos, T>,
202>
203{
204    fn new(parent: Option<&mut Self>) -> Self;
205    fn inner(&self) -> &Group<'a, Pos, T, State>;
206    fn inner_mut(&mut self) -> &mut Group<'a, Pos, T, State>;
207    fn close(self, parser: &mut LaTeXParser<'a, Pos, T, State>);
208    fn add_macro_rule(&mut self, name: Cow<'a, str>, old: Option<AnyMacro<'a, Pos, T, State>>);
209    fn add_environment_rule(&mut self, name: Cow<'a, str>, old: Option<AnyEnv<'a, Pos, T, State>>);
210    fn letter_change(&mut self, old: &str);
211}
212
213impl<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>, State: ParserState<'a, Pos, T>>
214    GroupState<'a, Pos, T, State> for Group<'a, Pos, T, State>
215{
216    fn new(_: Option<&mut Self>) -> Self {
217        Group {
218            previous_letters: None,
219            macro_rule_changes: HMap::default(),
220            environment_rule_changes: HMap::default(),
221        }
222    }
223    fn inner(&self) -> &Self {
224        self
225    }
226    fn inner_mut(&mut self) -> &mut Self {
227        self
228    }
229
230    fn add_macro_rule(&mut self, name: Cow<'a, str>, old: Option<AnyMacro<'a, Pos, T, State>>) {
231        if let Entry::Vacant(e) = self.macro_rule_changes.entry(name) {
232            e.insert(old);
233        }
234    }
235    fn add_environment_rule(&mut self, name: Cow<'a, str>, old: Option<AnyEnv<'a, Pos, T, State>>) {
236        if let Entry::Vacant(e) = self.environment_rule_changes.entry(name) {
237            e.insert(old);
238        }
239    }
240
241    fn letter_change(&mut self, old: &str) {
242        if self.previous_letters.is_none() {
243            self.previous_letters = Some(old.to_string());
244        }
245    }
246
247    fn close(self, parser: &mut LaTeXParser<'a, Pos, T, State>) {
248        if let Some(l) = self.previous_letters {
249            parser.tokenizer.letters = l;
250        }
251        for (n, r) in self.macro_rule_changes {
252            if let Some(r) = r {
253                parser.macro_rules.insert(n, r);
254            } else {
255                parser.macro_rules.remove(&n);
256            }
257        }
258    }
259}
260
261pub trait ParserState<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>>: Sized {
262    type Group: GroupState<'a, Pos, T, Self>;
263    type MacroArg: Clone;
264    #[inline]
265    fn from_comment(&self, r: StringRange<Pos>) -> Option<T> {
266        T::from_comment(r)
267    }
268    #[inline]
269    fn from_group(&self, r: StringRange<Pos>, children: Vec<T>) -> Option<T> {
270        T::from_group(r, children)
271    }
272    #[inline]
273    fn from_math(&self, display: bool, r: StringRange<Pos>, children: Vec<T>) -> Option<T> {
274        T::from_math(display, r, children)
275    }
276    #[inline]
277    fn from_control_sequence(&self, start: Pos, name: &'a str) -> Option<T> {
278        T::from_control_sequence(start, name)
279    }
280    #[inline]
281    fn from_text(
282        &self,
283        r: StringRange<Pos>,
284        text: &'a str,
285        in_document: bool,
286        in_math: bool,
287        groups: &mut Groups<'a, '_, Pos, T, Self>,
288    ) -> Option<T> {
289        T::from_text(r, text)
290    }
291    #[inline]
292    fn from_macro_application(&self, m: Macro<'a, Pos>) -> Option<T> {
293        T::from_macro_application(m)
294    }
295    #[inline]
296    fn from_environment(&self, e: Environment<'a, Pos, T>) -> Option<T> {
297        T::from_environment(e)
298    }
299}
300
301impl<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>> ParserState<'a, Pos, T> for () {
302    type Group = Group<'a, Pos, T, Self>;
303    type MacroArg = ();
304}
305
306impl<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>, State: ParserState<'a, Pos, T>>
307    Group<'a, Pos, T, State>
308{
309}
310
311pub struct LaTeXParser<
312    'a,
313    Pos: StringPosition,
314    T: FromLaTeXToken<'a, Pos>,
315    State: ParserState<'a, Pos, T>,
316> {
317    pub tokenizer: super::tokenizer::TeXTokenizer<'a, Pos>,
318    macro_rules: HMap<Cow<'a, str>, AnyMacro<'a, Pos, T, State>>,
319    pub groups: Vec<State::Group>,
320    environment_rules: HMap<Cow<'a, str>, AnyEnv<'a, Pos, T, State>>,
321    directives: HMap<&'a str, fn(&mut Self, &'a str)>,
322    buf: Vec<T>,
323    pub state: State,
324    pub in_document: bool,
325}
326
327macro_rules! count {
328    () => (0usize);
329    ( $e:expr; $($n:expr;)* ) => (1usize + count!($($n;)*));
330}
331
332macro_rules! default_rules {
333    ($( $($name:ident)? $(($l:literal,$lname:ident))? ),*) => {
334        #[must_use]
335        pub fn default_rules() -> [(&'static str,MacroRule<'a,Pos, T, State>);count!($( $($name;)? $($lname;)? )*)] {[
336            $($((stringify!($name),rules::$name))?$(($l.into(),rules::$lname))?),*
337        ]}
338    }
339}
340
341macro_rules! default_envs {
342    ($( $($name:ident)? $(($l:literal,$lname:ident))? ),*) => {
343        #[must_use]
344        pub fn default_env_rules() -> [(&'static str,EnvironmentRule<'a,Pos, T, State>);count!($( $($name;)? $($lname;)? )*)] {[
345            $(paste::paste!(
346                $((stringify!($name),(rules::[<$name _open>],rules::[<$name _close>])))?
347                $(($l.into(),(rules::$lname,rules::rules::[<$lname _close>])))?
348            )),*
349        ]}
350    }
351}
352
353pub struct Groups<
354    'a,
355    'b,
356    Pos: StringPosition,
357    T: FromLaTeXToken<'a, Pos>,
358    State: ParserState<'a, Pos, T>,
359> {
360    pub groups: &'b mut Vec<State::Group>,
361    pub rules: &'b mut HMap<Cow<'a, str>, AnyMacro<'a, Pos, T, State>>,
362    pub environment_rules: &'b mut HMap<Cow<'a, str>, AnyEnv<'a, Pos, T, State>>,
363    pub tokenizer: &'b mut super::tokenizer::TeXTokenizer<'a, Pos>,
364}
365
366impl<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>, State: ParserState<'a, Pos, T>>
367    Groups<'a, '_, Pos, T, State>
368{
369    pub fn add_macro_rule(
370        &mut self,
371        name: Cow<'a, str>,
372        rule: Option<AnyMacro<'a, Pos, T, State>>,
373    ) {
374        let old = if let Some(rule) = rule {
375            self.rules.insert(name.clone(), rule)
376        } else {
377            self.rules.remove(&name)
378        };
379        if let Some(g) = self.groups.last_mut() {
380            g.add_macro_rule(name, old);
381        }
382    }
383
384    pub fn add_environment_rule(
385        &mut self,
386        name: Cow<'a, str>,
387        rule: Option<AnyEnv<'a, Pos, T, State>>,
388    ) {
389        let old = if let Some(rule) = rule {
390            self.environment_rules.insert(name.clone(), rule)
391        } else {
392            self.environment_rules.remove(&name)
393        };
394        if let Some(g) = self.groups.last_mut() {
395            g.add_environment_rule(name, old);
396        }
397    }
398}
399
400/*
401*/
402
403impl<'a, Pos: StringPosition, T: FromLaTeXToken<'a, Pos>, State: ParserState<'a, Pos, T>>
404    LaTeXParser<'a, Pos, T, State>
405{
406    pub fn new(
407        input: &'a str,
408        state: State,
409        err: &'a mut dyn FnMut(String, StringRange<Pos>, DiagnosticLevel),
410    ) -> Self {
411        Self::with_rules(
412            input,
413            state,
414            err,
415            Self::default_rules().into_iter(),
416            Self::default_env_rules().into_iter(),
417        )
418    }
419
420    pub fn with_rules(
421        input: &'a str,
422        state: State,
423        err: &'a mut dyn FnMut(String, StringRange<Pos>, DiagnosticLevel),
424        rules: impl Iterator<Item = (&'a str, MacroRule<'a, Pos, T, State>)>,
425        envs: impl Iterator<Item = (&'a str, EnvironmentRule<'a, Pos, T, State>)>,
426    ) -> Self {
427        let mut macro_rules = HMap::default();
428        let mut environment_rules = HMap::default();
429        for (k, v) in rules {
430            macro_rules.insert(Cow::Borrowed(k), AnyMacro::Ptr(v));
431        }
432        for (k, v) in envs {
433            environment_rules.insert(Cow::Borrowed(k), AnyEnv::Ptr(v));
434        }
435        let mut directives = HMap::default();
436        directives.insert("copycmd", directives::copycmd as _);
437        directives.insert("verbcmd", directives::verbcmd as _);
438        directives.insert("verbenv", directives::verbenv as _);
439        directives.insert("nolint", directives::nolint as _);
440        directives.insert("dolint", directives::dolint as _);
441        directives.insert("macro", directives::macro_dir as _);
442        directives.insert("env", directives::env_dir as _);
443
444        LaTeXParser {
445            tokenizer: super::tokenizer::TeXTokenizer::new(input, err),
446            macro_rules,
447            groups: vec![State::Group::new(None)],
448            environment_rules,
449            directives,
450            buf: Vec::new(),
451            state,
452            in_document: false,
453        }
454    }
455
456    #[inline]
457    pub const fn split<'b>(&'b mut self) -> (&'b mut State, Groups<'a, 'b, Pos, T, State>) {
458        (
459            &mut self.state,
460            Groups {
461                groups: &mut self.groups,
462                rules: &mut self.macro_rules,
463                environment_rules: &mut self.environment_rules,
464                tokenizer: &mut self.tokenizer,
465            },
466        )
467    }
468
469    pub fn add_macro_rule(
470        &mut self,
471        name: Cow<'a, str>,
472        rule: Option<AnyMacro<'a, Pos, T, State>>,
473    ) {
474        let old = if let Some(rule) = rule {
475            self.macro_rules.insert(name.clone(), rule)
476        } else {
477            self.macro_rules.remove(&name)
478        };
479        if let Some(g) = self.groups.last_mut() {
480            g.add_macro_rule(name, old);
481        }
482    }
483
484    pub fn add_environment_rule(
485        &mut self,
486        name: Cow<'a, str>,
487        rule: Option<AnyEnv<'a, Pos, T, State>>,
488    ) {
489        let old = if let Some(rule) = rule {
490            self.environment_rules.insert(name.clone(), rule)
491        } else {
492            self.environment_rules.remove(&name)
493        };
494        if let Some(g) = self.groups.last_mut() {
495            g.add_environment_rule(name, old);
496        }
497    }
498
499    default_rules!(
500        begin,
501        end,
502        begingroup,
503        endgroup,
504        makeatletter,
505        makeatother,
506        ExplSyntaxOn,
507        ExplSyntaxOff,
508        lstinline,
509        verb,
510        stexcodeinline,
511        stexinline,
512        newcommand,
513        renewcommand,
514        providecommand,
515        newenvironment,
516        renewenvironment,
517        provideenvironment,
518        NewDocumentCommand,
519        DeclareDocumentCommand,
520        DeclareRobustCommand,
521        NewDocumentEnvironment,
522        DeclareDocumentEnvironment,
523        ("ref", r#ref),
524        label,
525        cite,
526        includegraphics,
527        url,
528        lstdefinelanguage,
529        hbox,
530        vbox,
531        fbox,
532        mvbox,
533        text,
534        texttt,
535        textrm,
536        textbf,
537        ensuremath,
538        scalebox,
539        raisebox,
540        def,
541        edef,
542        gdef,
543        xdef
544    );
545
546    default_envs!(document, verbatim, lstlisting, stexcode);
547
548    #[inline]
549    pub fn curr_pos(&self) -> Pos {
550        self.tokenizer.reader.curr_pos()
551    }
552
553    fn default(&mut self, t: TeXToken<Pos, &'a str>) -> Option<T> {
554        match t {
555            TeXToken::Comment(r) => self.state.from_comment(r),
556            TeXToken::Text { range, text } => {
557                let mut groups = Groups {
558                    groups: &mut self.groups,
559                    rules: &mut self.macro_rules,
560                    environment_rules: &mut self.environment_rules,
561                    tokenizer: &mut self.tokenizer,
562                };
563                self.state.from_text(
564                    range,
565                    text,
566                    self.in_document,
567                    matches!(
568                        groups.tokenizer.mode,
569                        crate::quickparse::tokenizer::Mode::Math { .. }
570                    ),
571                    &mut groups,
572                )
573            }
574            TeXToken::BeginGroupChar(start) => {
575                let children = self.group();
576                self.state.from_group(
577                    StringRange {
578                        start,
579                        end: self.tokenizer.reader.curr_pos(),
580                    },
581                    children,
582                )
583            }
584            TeXToken::BeginMath { display, start } => {
585                let children = self.math(display);
586                self.state.from_math(
587                    display,
588                    StringRange {
589                        start,
590                        end: self.tokenizer.reader.curr_pos(),
591                    },
592                    children,
593                )
594            }
595            TeXToken::Directive(s) => {
596                self.directive(s);
597                None
598            }
599            TeXToken::EndGroupChar(p) => {
600                self.tokenizer
601                    .problem(p, "Unmatched close group", DiagnosticLevel::Error);
602                None
603            }
604            TeXToken::EndMath { start, .. } => {
605                self.tokenizer
606                    .problem(start, "Unmatched math close", DiagnosticLevel::Error);
607                None
608            }
609            TeXToken::ControlSequence { start, name } => self.cs(name, start),
610        }
611    }
612
613    pub fn open_group(&mut self) {
614        let g = State::Group::new(self.groups.last_mut());
615        self.groups.push(g);
616    }
617
618    pub fn close_group(&mut self) {
619        match self.groups.pop() {
620            None => self
621                .tokenizer
622                .problem(self.curr_pos(), "Unmatched }", DiagnosticLevel::Error),
623            Some(g) => g.close(self),
624        }
625    }
626    pub fn add_letters(&mut self, s: &str) {
627        if let Some(g) = self.groups.last_mut() {
628            g.letter_change(&self.tokenizer.letters);
629        }
630        self.tokenizer.letters.push_str(s);
631    }
632    pub fn remove_letters(&mut self, s: &str) {
633        if let Some(g) = self.groups.last_mut() {
634            g.letter_change(&self.tokenizer.letters);
635        }
636        self.tokenizer.letters.retain(|x| !s.contains(x));
637    }
638
639    fn cs(&mut self, name: &'a str, start: Pos) -> Option<T> {
640        match self.macro_rules.get(name).cloned() {
641            Some(r) => {
642                let r#macro = Macro {
643                    range: StringRange {
644                        start,
645                        end: self.curr_pos(),
646                    },
647                    token_range: StringRange {
648                        start,
649                        end: self.curr_pos(),
650                    },
651                    name,
652                    //args: Vec::new(),
653                };
654                match r.call(r#macro, self) {
655                    MacroResult::Success(t) => Some(t),
656                    MacroResult::Simple(m) => self.state.from_macro_application(m),
657                    MacroResult::Other(v) => {
658                        self.buf.extend(v.into_iter().rev());
659                        self.buf.pop()
660                    }
661                }
662            }
663            None => self.state.from_control_sequence(start, name),
664        }
665    }
666
667    pub(in crate::quickparse) fn environment(
668        &mut self,
669        begin: Macro<'a, Pos>,
670        name: &'a str,
671        name_range: StringRange<Pos>,
672    ) -> EnvironmentResult<'a, Pos, T> {
673        if name == "document" {
674            self.in_document = true;
675        }
676        let mut env = Environment {
677            begin,
678            end: None,
679            name,
680            name_range,
681            //args: Vec::new(),
682            children: Vec::new(),
683            //phantom:PhantomData
684        };
685        self.open_group();
686        let close = self.environment_rules.get(env.name).cloned().map(|e| {
687            e.open(&mut env, self);
688            let close = e.close();
689            close
690        });
691        while let Some(next) = self.tokenizer.next() {
692            if let TeXToken::ControlSequence {
693                start,
694                name: endname,
695            } = &next
696            {
697                if *endname == "end" {
698                    let mut end_macro = Macro {
699                        range: StringRange {
700                            start: *start,
701                            end: self.curr_pos(),
702                        },
703                        token_range: StringRange {
704                            start: *start,
705                            end: self.curr_pos(),
706                        },
707                        name: env.name,
708                        //args: Vec::new(),
709                    };
710                    match self.read_name(&mut end_macro).map(|(n, _)| n) {
711                        Some(n) if n == env.name => {
712                            if env.name == "document" {
713                                self.in_document = false;
714                            }
715                            env.end = Some(end_macro);
716                            return if let Some(close) = close {
717                                let ret = close(env, self);
718                                self.close_group();
719                                ret
720                            } else {
721                                self.close_group();
722                                EnvironmentResult::Simple(env)
723                            };
724                        }
725                        Some(n) => {
726                            self.tokenizer.problem(
727                                end_macro.range.start,
728                                format!("Expected \\end{{{}}}, found \\end{{{n}}}", env.name),
729                                DiagnosticLevel::Error,
730                            );
731                            break;
732                        }
733                        None => {
734                            self.tokenizer.problem(
735                                end_macro.range.start,
736                                "Expected environment name after \\end",
737                                DiagnosticLevel::Error,
738                            );
739                            break;
740                        }
741                    }
742                }
743            }
744            if let Some(n) = self.default(next) {
745                env.children.push(n);
746            }
747        }
748        self.close_group();
749        self.tokenizer.problem(
750            env.begin.range.start,
751            "Unclosed environment",
752            DiagnosticLevel::Error,
753        );
754        EnvironmentResult::Simple(env)
755    }
756
757    fn directive(&mut self, s: &'a str) {
758        let name_args = s.trim().split_once(|c: char| c.is_ascii_whitespace());
759        /*
760        let mut str = s.trim();
761        if let Some(i) = str.find(|c: char| c.is_ascii_whitespace()) {
762            str = &str[..i];
763        } */
764        if let Some((d, args)) =
765            name_args.and_then(|(name, args)| self.directives.get(name).map(|d| (d, args)))
766        /*self.directives.get(str)*/
767        {
768            //let len = str.len();
769            //let (_, mut args) = s.split_n(len);
770            //args.trim_ws();
771            d(self, args.trim_start());
772        } else if let Some(d) = self.directives.get(s.trim()) {
773            d(self, "");
774        } else {
775            self.tokenizer.problem(
776                self.curr_pos(),
777                format!("Unknown directive {s}"),
778                DiagnosticLevel::Error,
779            );
780        }
781    }
782
783    fn math(&mut self, _display: bool) -> Vec<T> {
784        let start = self.curr_pos();
785        self.open_group();
786        let mut v = Vec::new();
787        while let Some(next) = self.tokenizer.next() {
788            if matches!(next, TeXToken::EndMath { .. }) {
789                self.close_group();
790                return v;
791            }
792            if let Some(n) = self.default(next) {
793                v.push(n);
794            }
795        }
796        self.tokenizer
797            .problem(start, "Unclosed math group", DiagnosticLevel::Error);
798        self.close_group();
799        v
800    }
801
802    fn group(&mut self) -> Vec<T> {
803        let start = self.curr_pos();
804        self.open_group();
805        let mut v = Vec::new();
806        while let Some(next) = self.tokenizer.next() {
807            if matches!(next, TeXToken::EndGroupChar(_)) {
808                self.close_group();
809                return v;
810            }
811            if let Some(n) = self.default(next) {
812                v.push(n);
813            }
814        }
815        self.tokenizer
816            .problem(start, "Unclosed group", DiagnosticLevel::Error);
817        v
818    }
819
820    fn group_i(&mut self) -> Vec<T> {
821        let start = self.curr_pos();
822        let mut v = Vec::new();
823        while !self.tokenizer.reader.starts_with('}') {
824            let Some(next) = self.tokenizer.next() else {
825                self.tokenizer
826                    .problem(start, "Unclosed group", DiagnosticLevel::Error);
827                return v;
828            };
829            if matches!(next, TeXToken::EndGroupChar(_)) {
830                return v;
831            }
832            if let Some(n) = self.default(next) {
833                v.push(n);
834            }
835        }
836        if self.tokenizer.reader.starts_with('}') {
837            self.tokenizer.reader.next_char();
838        } else {
839            self.tokenizer
840                .problem(start, "Unclosed group", DiagnosticLevel::Error);
841        }
842        v
843    }
844
845    pub fn get_argument(&mut self, in_macro: &mut Macro<'a, Pos>) -> (StringRange<Pos>, Vec<T>) {
846        self.tokenizer.reader.trim_start();
847        let start = self.curr_pos();
848        if self.tokenizer.reader.starts_with('{') {
849            self.tokenizer.reader.next_char();
850            let v = self.group_i();
851            in_macro.range.end = self.curr_pos();
852            let range = StringRange {
853                start,
854                end: self.curr_pos(),
855            };
856            (range, v)
857        } else if self.tokenizer.reader.starts_with('\\') {
858            let t = self.tokenizer.next().unwrap_or_else(|| unreachable!());
859            in_macro.range.end = self.curr_pos();
860            let range = StringRange {
861                start,
862                end: self.curr_pos(),
863            };
864            self.default(t)
865                .map_or_else(|| (range, Vec::new()), |t| (range, vec![t]))
866        } else {
867            let n = self.tokenizer.next();
868            if n.is_none() {
869                self.tokenizer
870                    .problem(start, "Expected argument", DiagnosticLevel::Error);
871            }
872            in_macro.range.end = self.curr_pos();
873            let range = StringRange {
874                start,
875                end: self.curr_pos(),
876            };
877            (range, Vec::new())
878        }
879    }
880
881    pub fn get_argument_with_str(
882        &mut self,
883        in_macro: &mut Macro<'a, Pos>,
884    ) -> (StringRange<Pos>, Vec<T>, &'a str) {
885        self.tokenizer.reader.trim_start();
886        let start = self.curr_pos();
887        if self.tokenizer.reader.starts_with('{') {
888            self.tokenizer.reader.next_char();
889            let full = self.tokenizer.reader.rest();
890            let v = self.group_i();
891            in_macro.range.end = self.curr_pos();
892            let range = StringRange {
893                start,
894                end: self.curr_pos(),
895            };
896            let new_rest = self.tokenizer.reader.rest();
897            let text = full.strip_suffix(new_rest).expect("impossible").trim_end();
898            let text = text.strip_suffix('}').unwrap_or_else(|| text.trim());
899            (range, v, text)
900        } else if self.tokenizer.reader.starts_with('\\') {
901            let full = self.tokenizer.reader.rest();
902            let t = self.tokenizer.next().unwrap_or_else(|| unreachable!());
903            in_macro.range.end = self.curr_pos();
904            let range = StringRange {
905                start,
906                end: self.curr_pos(),
907            };
908            let new_rest = self.tokenizer.reader.rest();
909            let text = full.strip_suffix(new_rest).expect("impossible").trim_end();
910            self.default(t)
911                .map_or_else(|| (range, Vec::new(), text), |t| (range, vec![t], text))
912        } else {
913            let full = self.tokenizer.reader.rest().trim_start();
914            let n = self.tokenizer.next();
915            if n.is_none() {
916                self.tokenizer
917                    .problem(start, "Expected argument", DiagnosticLevel::Error);
918            }
919            in_macro.range.end = self.curr_pos();
920            let range = StringRange {
921                start,
922                end: self.curr_pos(),
923            };
924            let new_rest = self.tokenizer.reader.rest();
925            let text = full.strip_suffix(new_rest).expect("impossible").trim_end();
926            (range, Vec::new(), text)
927        }
928    }
929
930    pub fn read_argument(&mut self, in_macro: &mut Macro<'a, Pos>) {
931        self.tokenizer.reader.trim_start();
932        if self.tokenizer.reader.starts_with('{') {
933            self.tokenizer.reader.next_char();
934            let _v = self.group_i();
935        } else if self.tokenizer.reader.starts_with('\\') {
936            let _t = self.tokenizer.next().unwrap_or_else(|| unreachable!());
937        } else {
938            let _ = self.tokenizer.next();
939        }
940        in_macro.range.end = self.curr_pos();
941    }
942
943    pub fn read_opt_str(&mut self, in_macro: &mut Macro<'a, Pos>) -> OptArg<'a, Pos> {
944        self.tokenizer.reader.trim_start();
945        if self.tokenizer.reader.starts_with('[') {
946            self.tokenizer.reader.next_char();
947            self.tokenizer.reader.trim_start();
948            let tstart = self.curr_pos();
949            let s = self
950                .tokenizer
951                .reader
952                .read_until_byte_with_brackets(b']', b'{', b'}');
953            let range = StringRange {
954                start: tstart,
955                end: self.curr_pos(),
956            };
957            self.tokenizer.reader.next_char();
958            in_macro.range.end = self.curr_pos();
959            OptArg {
960                inner: Some(s),
961                range,
962            }
963        } else {
964            let range = StringRange {
965                start: self.curr_pos(),
966                end: self.curr_pos(),
967            };
968            OptArg { inner: None, range }
969        }
970    }
971
972    pub fn read_name(&mut self, r#in: &mut Macro<'a, Pos>) -> Option<(&'a str, StringRange<Pos>)> {
973        self.tokenizer.reader.trim_start();
974        if self.tokenizer.reader.starts_with('{') {
975            self.tokenizer.reader.next_char();
976            self.tokenizer.reader.trim_start();
977            let tstart = self.curr_pos();
978            let s = self
979                .tokenizer
980                .reader
981                .read_until_byte_with_brackets(b'}', b'{', b'}');
982            let range = StringRange {
983                start: tstart,
984                end: self.curr_pos(),
985            };
986            self.tokenizer.reader.next_char();
987            r#in.range.end = self.curr_pos();
988            Some((s, range))
989        } else {
990            None
991        }
992    }
993
994    pub fn read_names(&mut self, r#in: &mut Macro<'a, Pos>) -> Vec<(&'a str, StringRange<Pos>)> {
995        self.tokenizer.reader.trim_start();
996        if self.tokenizer.reader.starts_with('{') {
997            let mut ret = Vec::new();
998            loop {
999                self.tokenizer.reader.next_char();
1000                self.tokenizer.reader.trim_start();
1001                let tstart = self.curr_pos();
1002                let s = self
1003                    .tokenizer
1004                    .reader
1005                    .read_until_with_brackets('{', '}', |c| c == '}' || c == ',');
1006                let range = StringRange {
1007                    start: tstart,
1008                    end: self.curr_pos(),
1009                };
1010                ret.push((s, range));
1011                if self.tokenizer.reader.starts_with('}') {
1012                    break;
1013                }
1014            }
1015            self.tokenizer.reader.next_char();
1016
1017            r#in.range.end = self.curr_pos();
1018            ret
1019        } else {
1020            Vec::new()
1021        }
1022    }
1023
1024    pub fn skip_opt(&mut self, in_macro: &mut Macro<'a, Pos>) -> bool {
1025        self.tokenizer.reader.trim_start();
1026        if self.tokenizer.reader.starts_with('[') {
1027            self.tokenizer.reader.next_char();
1028            self.tokenizer.reader.trim_start();
1029            let _s = self
1030                .tokenizer
1031                .reader
1032                .read_until_byte_with_brackets(b']', b'{', b'}');
1033            self.tokenizer.reader.next_char();
1034            in_macro.range.end = self.curr_pos();
1035            true
1036        } else {
1037            false
1038        }
1039    }
1040    pub fn skip_arg(&mut self, in_macro: &mut Macro<'a, Pos>) {
1041        self.tokenizer.reader.trim_start();
1042        if self.tokenizer.reader.starts_with('{') {
1043            self.tokenizer.reader.next_char();
1044            self.tokenizer.reader.trim_start();
1045            let _s = self
1046                .tokenizer
1047                .reader
1048                .read_until_byte_with_brackets(b'}', b'{', b'}');
1049            self.tokenizer.reader.next_char();
1050        } else {
1051            let _ = self.tokenizer.next();
1052        }
1053        in_macro.range.end = self.curr_pos();
1054    }
1055
1056    pub fn skip_comments(&mut self) {
1057        self.tokenizer.reader.trim_start();
1058        while self.tokenizer.reader.starts_with('%') {
1059            let _ = self.tokenizer.next();
1060            self.tokenizer.reader.trim_start();
1061        }
1062    }
1063}
1064
1065pub trait KeyValValues<
1066    'a,
1067    Pos: StringPosition,
1068    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1069    State: ParserState<'a, Pos, T>,
1070>: Sized + Default
1071{
1072    fn parse_opt(parser: &mut LaTeXParser<'a, Pos, T, State>) -> Option<Self> {
1073        parser.skip_comments();
1074        if !parser.tokenizer.reader.starts_with('[') {
1075            return None;
1076        }
1077        let mut ret = Self::default();
1078        parser.tokenizer.reader.next_char();
1079        loop {
1080            parser.skip_comments();
1081            let key_start = parser.curr_pos();
1082            let key = parser
1083                .tokenizer
1084                .reader
1085                .read_until(|c| c == ']' || c == ',' || c == '=' || c == '%')
1086                .trim();
1087            let key_end = parser.curr_pos();
1088            parser.skip_comments();
1089            match parser.tokenizer.reader.next_char() {
1090                Some(']') => {
1091                    if !key.is_empty() {
1092                        let kvp = KeyValParser {
1093                            start: parser.curr_pos(),
1094                            key,
1095                            key_range: StringRange {
1096                                start: key_start,
1097                                end: key_end,
1098                            },
1099                            value_end: parser.curr_pos(),
1100                            has_value: false,
1101                            parser,
1102                        };
1103                        ret.next(kvp, key);
1104                    }
1105                    break;
1106                }
1107                Some(',') if !key.is_empty() => {
1108                    let kvp = KeyValParser {
1109                        start: parser.curr_pos(),
1110                        key,
1111                        key_range: StringRange {
1112                            start: key_start,
1113                            end: key_end,
1114                        },
1115                        value_end: parser.curr_pos(),
1116                        has_value: false,
1117                        parser,
1118                    };
1119                    ret.next(kvp, key);
1120                }
1121                Some(',') => (),
1122                Some('=') => {
1123                    parser.skip_comments();
1124                    let start = parser.curr_pos();
1125                    let kvp = KeyValParser {
1126                        start,
1127                        key,
1128                        key_range: StringRange {
1129                            start: key_start,
1130                            end: key_end,
1131                        },
1132                        value_end: parser.curr_pos(),
1133                        has_value: true,
1134                        parser,
1135                    };
1136                    ret.next(kvp, key);
1137                    parser.skip_comments();
1138                    match parser.tokenizer.reader.next_char() {
1139                        Some(',') => (),
1140                        Some(']') => break,
1141                        c => {
1142                            parser.tokenizer.problem(
1143                                start,
1144                                format!("Unexpected end of key-value list: {c:?}"),
1145                                DiagnosticLevel::Error,
1146                            );
1147                            break;
1148                        }
1149                    }
1150                }
1151                _ => {
1152                    parser.tokenizer.problem(
1153                        key_start,
1154                        "Unexpected end of key-value list 2",
1155                        DiagnosticLevel::Error,
1156                    );
1157                    break;
1158                }
1159            }
1160        }
1161        Some(ret)
1162    }
1163    fn next(&mut self, parser: KeyValParser<'a, '_, Pos, T, State>, key: &str);
1164}
1165
1166pub trait KeyValKind<
1167    'a,
1168    Pos: StringPosition,
1169    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1170    State: ParserState<'a, Pos, T>,
1171>: Sized
1172{
1173    fn next_val(parser: &mut KeyValParser<'a, '_, Pos, T, State>, key: &str) -> Option<Self>;
1174}
1175impl<
1176    'a,
1177    Pos: StringPosition,
1178    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1179    State: ParserState<'a, Pos, T>,
1180    K: KeyValKind<'a, Pos, T, State>,
1181> KeyValValues<'a, Pos, T, State> for Vec<K>
1182{
1183    fn next(&mut self, mut parser: KeyValParser<'a, '_, Pos, T, State>, key: &str) {
1184        if let Some(v) = K::next_val(&mut parser, key) {
1185            self.push(v);
1186        } else {
1187            parser.parser.tokenizer.problem(
1188                parser.start,
1189                format!("Unexpected key {key}"),
1190                DiagnosticLevel::Error,
1191            );
1192            parser.skip_value();
1193        }
1194    }
1195}
1196
1197#[derive(Clone, Debug, serde::Serialize)]
1198pub struct ParsedKeyValue<Pos: StringPosition, T: CondSerialize> {
1199    pub key_range: StringRange<Pos>,
1200    pub val_range: StringRange<Pos>,
1201    pub val: T,
1202}
1203
1204pub trait KeyValParsable<
1205    'a,
1206    Pos: StringPosition + 'a,
1207    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1208    State: ParserState<'a, Pos, T>,
1209>: Sized + 'a + CondSerialize
1210{
1211    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self>;
1212    fn parse_key_val(
1213        parser: &mut KeyValParser<'a, '_, Pos, T, State>,
1214    ) -> Option<ParsedKeyValue<Pos, Self>> {
1215        Self::parse_key_val_inner(parser).map(|val| ParsedKeyValue {
1216            key_range: parser.key_range,
1217            val_range: StringRange {
1218                start: parser.start,
1219                end: parser.value_end,
1220            },
1221            val,
1222        })
1223    }
1224}
1225
1226impl<
1227    'a,
1228    Pos: StringPosition + 'a,
1229    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1230    State: ParserState<'a, Pos, T>,
1231> KeyValParsable<'a, Pos, T, State> for ()
1232{
1233    #[inline]
1234    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1235        parser.skip_value();
1236        Some(())
1237    }
1238}
1239
1240impl<
1241    'a,
1242    Pos: StringPosition + 'a,
1243    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1244    State: ParserState<'a, Pos, T>,
1245> KeyValParsable<'a, Pos, T, State> for Language
1246{
1247    #[inline]
1248    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1249        let Some(s) = parser.read_value_str_normalized() else {
1250            parser.problem("Missing value", DiagnosticLevel::Error);
1251            return None;
1252        };
1253        let Ok(l) = s.parse() else {
1254            parser.problem("Invalid language", DiagnosticLevel::Error);
1255            return None;
1256        };
1257        Some(l)
1258    }
1259}
1260impl<
1261    'a,
1262    Pos: StringPosition + 'a,
1263    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1264    State: ParserState<'a, Pos, T>,
1265> KeyValParsable<'a, Pos, T, State> for bool
1266{
1267    #[inline]
1268    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1269        let Some(s) = parser.read_value_str_normalized() else {
1270            parser.problem("Missing value", DiagnosticLevel::Error);
1271            return None;
1272        };
1273        let Ok(l) = s.parse() else {
1274            parser.problem("Invalid boolean", DiagnosticLevel::Error);
1275            return None;
1276        };
1277        Some(l)
1278    }
1279}
1280impl<
1281    'a,
1282    Pos: StringPosition + 'a,
1283    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1284    State: ParserState<'a, Pos, T>,
1285> KeyValParsable<'a, Pos, T, State> for f32
1286{
1287    #[inline]
1288    #[allow(clippy::cast_precision_loss)]
1289    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1290        let Some(s) = parser.read_value_str_normalized() else {
1291            parser.problem("Missing value", DiagnosticLevel::Error);
1292            return None;
1293        };
1294        if s.contains('.') {
1295            let Ok(l) = s.parse() else {
1296                parser.problem("Invalid boolean", DiagnosticLevel::Error);
1297                return None;
1298            };
1299            Some(l)
1300        } else {
1301            let Ok(l) = s.parse::<i32>() else {
1302                parser.problem("Invalid boolean", DiagnosticLevel::Error);
1303                return None;
1304            };
1305            Some(l as _)
1306        }
1307    }
1308}
1309
1310impl<
1311    'a,
1312    Pos: StringPosition + 'a,
1313    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1314    State: ParserState<'a, Pos, T>,
1315> KeyValParsable<'a, Pos, T, State> for Box<str>
1316{
1317    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1318        parser.read_value_str_normalized().map(|s| match s {
1319            Cow::Borrowed(s) => s.to_string().into_boxed_str(),
1320            Cow::Owned(s) => s.into_boxed_str(),
1321        })
1322    }
1323}
1324impl<
1325    'a,
1326    Pos: StringPosition + 'a,
1327    T: FromLaTeXToken<'a, Pos> + CondSerialize + 'a,
1328    State: ParserState<'a, Pos, T>,
1329> KeyValParsable<'a, Pos, T, State> for Vec<T>
1330{
1331    #[inline]
1332    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1333        Some(parser.tokens())
1334    }
1335}
1336impl<
1337    'a,
1338    Pos: StringPosition + 'a,
1339    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1340    State: ParserState<'a, Pos, T>,
1341> KeyValParsable<'a, Pos, T, State> for u8
1342{
1343    fn parse_key_val_inner(parser: &mut KeyValParser<'a, '_, Pos, T, State>) -> Option<Self> {
1344        parser.read_value_str().and_then(|s| s.parse().ok())
1345    }
1346}
1347
1348pub struct KeyValParser<
1349    'a,
1350    'b,
1351    Pos: StringPosition + 'a,
1352    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1353    State: ParserState<'a, Pos, T>,
1354> {
1355    pub start: Pos,
1356    pub key_range: StringRange<Pos>,
1357    pub key: &'a str,
1358    value_end: Pos,
1359    pub has_value: bool,
1360    pub parser: &'b mut LaTeXParser<'a, Pos, T, State>,
1361}
1362impl<
1363    'a,
1364    Pos: StringPosition + 'a,
1365    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1366    State: ParserState<'a, Pos, T>,
1367> KeyValParser<'a, '_, Pos, T, State>
1368{
1369    #[inline]
1370    pub fn parse<R: KeyValParsable<'a, Pos, T, State> + CondSerialize>(
1371        &mut self,
1372    ) -> Option<ParsedKeyValue<Pos, R>> {
1373        R::parse_key_val(self)
1374    }
1375
1376    #[inline]
1377    pub const fn to_key_value<Tp: CondSerialize>(&self, val: Tp) -> ParsedKeyValue<Pos, Tp> {
1378        ParsedKeyValue {
1379            key_range: self.key_range,
1380            val_range: StringRange {
1381                start: self.start,
1382                end: self.value_end,
1383            },
1384            val,
1385        }
1386    }
1387    #[inline]
1388    pub fn problem<D: std::fmt::Display>(&mut self, msg: D, severity: DiagnosticLevel) {
1389        self.parser.tokenizer.problem(self.start, msg, severity);
1390    }
1391    #[inline]
1392    pub fn tokens(&mut self) -> Vec<T> {
1393        self.read_value_str()
1394            .map_or_else(Vec::new, |s| self.parser.reparse(s, self.start))
1395    }
1396    pub fn read_value_str(&mut self) -> Option<&'a str> {
1397        if !self.has_value {
1398            return None;
1399        }
1400        self.parser.skip_comments();
1401        let value_start = self.parser.curr_pos();
1402        let str = self
1403            .parser
1404            .tokenizer
1405            .reader
1406            .read_until_with_brackets('{', '}', |c| c == ']' || c == ',');
1407        self.value_end = self.parser.curr_pos();
1408        Some(str)
1409    }
1410    pub fn read_value_str_normalized(&mut self) -> Option<Cow<'a, str>> {
1411        if !self.has_value {
1412            return None;
1413        }
1414        self.parser.skip_comments();
1415        let had_braces = self.parser.tokenizer.reader.starts_with('{');
1416        if had_braces {
1417            self.parser.tokenizer.reader.next_char();
1418            self.parser.skip_comments();
1419        }
1420        let get_next = if had_braces {
1421            |s: &mut Self| {
1422                s.parser
1423                    .tokenizer
1424                    .reader
1425                    .read_until_with_brackets('{', '}', |c| c == '}' || c == '%')
1426            }
1427        } else {
1428            |s: &mut Self| {
1429                s.parser
1430                    .tokenizer
1431                    .reader
1432                    .read_until_with_brackets('{', '}', |c| c == ']' || c == ',' || c == '%')
1433            }
1434        };
1435        let value_start = self.parser.curr_pos();
1436        let first_str = get_next(self); //self.parser.tokenizer.reader.read_until_with_brackets::<'{','}'>(|c| c == ']' || c == ',' || c == '%');
1437        if self.parser.tokenizer.reader.starts_with('%') {
1438            let mut nexts = SmallVec::<_, 2>::new();
1439            let mut end_pos = self.parser.curr_pos();
1440            loop {
1441                self.parser.skip_comments();
1442                let next = get_next(self);
1443                end_pos = self.parser.curr_pos();
1444                if !next.is_empty() {
1445                    nexts.push(next);
1446                }
1447                if self.parser.tokenizer.reader.starts_with('%') {
1448                    continue;
1449                }
1450                break;
1451            }
1452            self.value_end = end_pos;
1453            if had_braces {
1454                self.parser.tokenizer.reader.next_char();
1455            }
1456            if nexts.iter().all(|s| s.trim().is_empty()) {
1457                Some(normalize_ws(first_str))
1458            } else {
1459                Some(Cow::Owned(join_strs(first_str, nexts)))
1460            }
1461        } else {
1462            self.value_end = self.parser.curr_pos();
1463            if had_braces {
1464                self.parser.tokenizer.reader.next_char();
1465            }
1466            Some(normalize_ws(first_str))
1467        }
1468    }
1469
1470    pub fn read_value_strs_normalized(&mut self) -> Vec<(Cow<'a, str>, StringRange<Pos>)> {
1471        if !self.has_value {
1472            return Vec::new();
1473        }
1474        self.parser.skip_comments();
1475        if !self.parser.tokenizer.reader.starts_with('{') {
1476            return self.read_value_str_normalized().map_or_else(Vec::new, |s| {
1477                vec![(
1478                    s,
1479                    StringRange {
1480                        start: self.start,
1481                        end: self.value_end,
1482                    },
1483                )]
1484            });
1485        }
1486        self.parser.tokenizer.reader.next_char();
1487        self.parser.skip_comments();
1488        let mut ret = Vec::new();
1489        loop {
1490            let value_start = self.parser.curr_pos();
1491            let first_str = self
1492                .parser
1493                .tokenizer
1494                .reader
1495                .read_until_with_brackets('{', '}', |c| c == '}' || c == '%' || c == ',');
1496            if self.parser.tokenizer.reader.starts_with('%') {
1497                let mut nexts = SmallVec::<_, 2>::new();
1498                let mut end_pos = self.parser.curr_pos();
1499                loop {
1500                    self.parser.skip_comments();
1501                    let next =
1502                        self.parser
1503                            .tokenizer
1504                            .reader
1505                            .read_until_with_brackets('{', '}', |c| {
1506                                c == '}' || c == '%' || c == ','
1507                            });
1508                    end_pos = self.parser.curr_pos();
1509                    nexts.push(next);
1510                    if self.parser.tokenizer.reader.starts_with('%') {
1511                        continue;
1512                    }
1513                    break;
1514                }
1515                let range = StringRange {
1516                    start: value_start,
1517                    end: end_pos,
1518                };
1519                if nexts.iter().all(|s| s.trim().is_empty()) {
1520                    ret.push((normalize_ws(first_str), range));
1521                } else {
1522                    ret.push((Cow::Owned(join_strs(first_str, nexts)), range));
1523                }
1524                if self
1525                    .parser
1526                    .tokenizer
1527                    .reader
1528                    .next_char()
1529                    .is_some_and(|c| c == ',')
1530                {
1531                    continue;
1532                }
1533                break;
1534            }
1535            let range = StringRange {
1536                start: value_start,
1537                end: self.parser.curr_pos(),
1538            };
1539            ret.push((normalize_ws(first_str), range));
1540            if self
1541                .parser
1542                .tokenizer
1543                .reader
1544                .next_char()
1545                .is_some_and(|c| c == ',')
1546            {
1547                continue;
1548            }
1549            break;
1550        }
1551        self.value_end = self.parser.curr_pos();
1552        ret
1553    }
1554
1555    pub fn skip_value(&mut self) {
1556        self.read_value_str();
1557    }
1558}
1559
1560impl<
1561    'a,
1562    Pos: StringPosition,
1563    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1564    State: ParserState<'a, Pos, T>,
1565> LaTeXParser<'a, Pos, T, State>
1566{
1567    pub fn reparse(&mut self, s: &'a str, at: Pos) -> Vec<T> {
1568        let mut new = StrParser::new(s);
1569        new.pos = at;
1570        let mut old = std::mem::replace(&mut self.tokenizer.reader, new);
1571        let mut val = Vec::new();
1572        while self.tokenizer.reader.peek_head().is_some() {
1573            let Some(next) = self.tokenizer.next() else {
1574                self.tokenizer
1575                    .problem(at, "Unclosed optional argument", DiagnosticLevel::Error);
1576                break;
1577            };
1578            if let Some(n) = self.default(next) {
1579                val.push(n);
1580            }
1581            self.tokenizer.reader.trim_start();
1582        }
1583        old.pos = self.curr_pos();
1584        self.tokenizer.reader = old;
1585        val
1586    }
1587
1588    #[allow(clippy::too_many_lines)]
1589    pub fn read_opt_map(&mut self, in_macro: &mut Macro<'a, Pos>) -> OptMap<'a, Pos, T> {
1590        self.skip_comments();
1591        if self.tokenizer.reader.starts_with('[') {
1592            self.tokenizer.reader.next_char();
1593            let mut map = VecMap::new();
1594            loop {
1595                self.skip_comments();
1596                let key_start = self.curr_pos();
1597                let key = self
1598                    .tokenizer
1599                    .reader
1600                    .read_until(|c| c == ']' || c == ',' || c == '=' || c == '%')
1601                    .trim();
1602                let key_end = self.curr_pos();
1603                self.skip_comments();
1604                match self.tokenizer.reader.next_char() {
1605                    Some(']') => {
1606                        if !key.is_empty() {
1607                            map.insert(
1608                                key,
1609                                OptMapVal {
1610                                    key_range: StringRange {
1611                                        start: key_start,
1612                                        end: key_end,
1613                                    },
1614                                    val_range: StringRange {
1615                                        start: self.curr_pos(),
1616                                        end: self.curr_pos(),
1617                                    },
1618                                    val: Vec::new(),
1619                                    str: "",
1620                                },
1621                            );
1622                        }
1623                        break;
1624                    }
1625                    Some(',') if !key.is_empty() => {
1626                        map.insert(
1627                            key,
1628                            OptMapVal {
1629                                key_range: StringRange {
1630                                    start: key_start,
1631                                    end: key_end,
1632                                },
1633                                val_range: StringRange {
1634                                    start: self.curr_pos(),
1635                                    end: self.curr_pos(),
1636                                },
1637                                val: Vec::new(),
1638                                str: "",
1639                            },
1640                        );
1641                    }
1642                    Some(',') => (),
1643                    Some('=') => {
1644                        self.skip_comments();
1645                        let value_start = self.curr_pos();
1646                        let str = self
1647                            .tokenizer
1648                            .reader
1649                            .read_until_with_brackets('{', '}', |c| c == ']' || c == ',');
1650                        let val = self.reparse(str, value_start);
1651                        map.insert(
1652                            key,
1653                            OptMapVal {
1654                                key_range: StringRange {
1655                                    start: key_start,
1656                                    end: key_end,
1657                                },
1658                                val_range: StringRange {
1659                                    start: value_start,
1660                                    end: self.curr_pos(),
1661                                },
1662                                val,
1663                                str,
1664                            },
1665                        );
1666                    }
1667                    _ => {
1668                        self.tokenizer.problem(
1669                            key_start,
1670                            format!(
1671                                "value for key \"{key}\" in {} ended unexpectedly",
1672                                in_macro.name
1673                            ),
1674                            DiagnosticLevel::Error,
1675                        );
1676                        break;
1677                    }
1678                }
1679            }
1680            OptMap { inner: map }
1681        } else {
1682            OptMap {
1683                inner: VecMap::new(),
1684            }
1685        }
1686    }
1687
1688    pub fn read_opt_name_normalized(
1689        &mut self,
1690        r#in: &mut Macro<'a, Pos>,
1691    ) -> Option<(Cow<'a, str>, StringRange<Pos>)> {
1692        self.skip_comments();
1693        if self.tokenizer.reader.starts_with('[') {
1694            self.tokenizer.reader.next_char();
1695            self.tokenizer.reader.trim_start();
1696            let tstart = self.curr_pos();
1697            let first_str = self
1698                .tokenizer
1699                .reader
1700                .read_until_with_brackets('{', '}', |c| c == ']' || c == '%');
1701            let first_end = self.curr_pos();
1702            if self.tokenizer.reader.starts_with('%') {
1703                let mut nexts = SmallVec::<_, 2>::new();
1704                let mut end_pos = self.curr_pos();
1705                loop {
1706                    self.skip_comments();
1707                    let next = self
1708                        .tokenizer
1709                        .reader
1710                        .read_until_with_brackets('{', '}', |c| c == ']' || c == '%');
1711                    end_pos = self.curr_pos();
1712                    nexts.push(next);
1713                    if self.tokenizer.reader.starts_with('%') {
1714                        continue;
1715                    }
1716                    self.tokenizer.reader.next_char();
1717                    break;
1718                }
1719                let range = StringRange {
1720                    start: tstart,
1721                    end: end_pos,
1722                };
1723                r#in.range.end = self.curr_pos();
1724                if nexts.iter().all(|s| s.trim().is_empty()) {
1725                    Some((normalize_ws(first_str), range))
1726                } else {
1727                    Some((Cow::Owned(join_strs(first_str, nexts)), range))
1728                }
1729            } else {
1730                self.tokenizer.reader.next_char();
1731                let range = StringRange {
1732                    start: tstart,
1733                    end: first_end,
1734                };
1735                r#in.range.end = self.curr_pos();
1736                Some((normalize_ws(first_str), range))
1737            }
1738        } else {
1739            None
1740        }
1741    }
1742
1743    pub fn read_name_normalized(
1744        &mut self,
1745        r#in: &mut Macro<'a, Pos>,
1746    ) -> Option<(Cow<'a, str>, StringRange<Pos>)> {
1747        self.skip_comments();
1748        if self.tokenizer.reader.starts_with('{') {
1749            self.tokenizer.reader.next_char();
1750            self.skip_comments();
1751            let tstart = self.curr_pos();
1752            let first_str = self
1753                .tokenizer
1754                .reader
1755                .read_until_with_brackets('{', '}', |c| c == '}' || c == '%');
1756            let first_end = self.curr_pos();
1757            if self.tokenizer.reader.starts_with('%') {
1758                let mut nexts = SmallVec::<_, 2>::new();
1759                let mut end_pos = self.curr_pos();
1760                loop {
1761                    self.skip_comments();
1762                    let next = self
1763                        .tokenizer
1764                        .reader
1765                        .read_until_with_brackets('{', '}', |c| c == '}' || c == '%');
1766                    end_pos = self.curr_pos();
1767                    nexts.push(next);
1768                    if self.tokenizer.reader.starts_with('%') {
1769                        continue;
1770                    }
1771                    self.tokenizer.reader.next_char();
1772                    break;
1773                }
1774                let range = StringRange {
1775                    start: tstart,
1776                    end: end_pos,
1777                };
1778                r#in.range.end = self.curr_pos();
1779                if nexts.iter().all(|s| s.trim().is_empty()) {
1780                    Some((normalize_ws(first_str), range))
1781                } else {
1782                    Some((Cow::Owned(join_strs(first_str, nexts)), range))
1783                }
1784            } else {
1785                self.tokenizer.reader.next_char();
1786                let range = StringRange {
1787                    start: tstart,
1788                    end: first_end,
1789                };
1790                r#in.range.end = self.curr_pos();
1791                Some((normalize_ws(first_str), range))
1792            }
1793        } else {
1794            let start = self.curr_pos();
1795            let c = self.tokenizer.reader.read_n(1);
1796            Some((
1797                Cow::Borrowed(c),
1798                StringRange {
1799                    start,
1800                    end: self.curr_pos(),
1801                },
1802            ))
1803        }
1804    }
1805
1806    pub fn read_names_normalized(
1807        &mut self,
1808        r#in: &mut Macro<'a, Pos>,
1809    ) -> Vec<(Cow<'a, str>, StringRange<Pos>)> {
1810        self.skip_comments();
1811        if self.tokenizer.reader.starts_with('{') {
1812            self.tokenizer.reader.next_char();
1813            let mut ret = Vec::new();
1814            loop {
1815                self.skip_comments();
1816                let tstart = self.curr_pos();
1817                let first_str = self
1818                    .tokenizer
1819                    .reader
1820                    .read_until_with_brackets('{', '}', |c| c == '}' || c == ',' || c == '%');
1821                let first_end = self.curr_pos();
1822                if self.tokenizer.reader.starts_with('%') {
1823                    let mut nexts = SmallVec::<_, 2>::new();
1824                    let mut end_pos = self.curr_pos();
1825                    loop {
1826                        self.skip_comments();
1827                        let next = self
1828                            .tokenizer
1829                            .reader
1830                            .read_until_with_brackets('{', '}', |c| {
1831                                c == '}' || c == '%' || c == ','
1832                            });
1833                        end_pos = self.curr_pos();
1834                        nexts.push(next);
1835                        if self.tokenizer.reader.starts_with('%') {
1836                            continue;
1837                        }
1838                        break;
1839                    }
1840                    let range = StringRange {
1841                        start: tstart,
1842                        end: end_pos,
1843                    };
1844                    if nexts.iter().all(|s| s.trim().is_empty()) {
1845                        ret.push((normalize_ws(first_str), range));
1846                    } else {
1847                        ret.push((Cow::Owned(join_strs(first_str, nexts)), range));
1848                    }
1849                    if self.tokenizer.reader.next_char().is_some_and(|c| c == ',') {
1850                        continue;
1851                    }
1852                    break;
1853                }
1854                let range = StringRange {
1855                    start: tstart,
1856                    end: first_end,
1857                };
1858                ret.push((normalize_ws(first_str), range));
1859                if self.tokenizer.reader.next_char().is_some_and(|c| c == ',') {
1860                    continue;
1861                }
1862                break;
1863            }
1864            r#in.range.end = self.curr_pos();
1865            ret
1866        } else {
1867            Vec::new()
1868        }
1869    }
1870}
1871
1872fn normalize_ws(s: &str) -> Cow<'_, str> {
1873    if s.contains(['\t', ' ', '\r', '\n']) {
1874        let v = s
1875            .trim()
1876            .split_ascii_whitespace()
1877            .collect::<SmallVec<_, 2>>();
1878        Cow::Owned(v.join(" "))
1879    } else {
1880        Cow::Borrowed(s)
1881    }
1882}
1883
1884fn join_strs(first: &str, rest: SmallVec<&str, 2>) -> String {
1885    let mut ret_str = first.trim_start().to_string();
1886    for r in rest {
1887        ret_str.push_str(r.trim_start());
1888    }
1889    let v = ret_str
1890        .trim_end()
1891        .split_ascii_whitespace()
1892        .collect::<SmallVec<_, 2>>();
1893    v.join(" ")
1894}
1895
1896impl<
1897    'a,
1898    Pos: StringPosition,
1899    T: FromLaTeXToken<'a, Pos> + CondSerialize,
1900    State: ParserState<'a, Pos, T>,
1901> Iterator for LaTeXParser<'a, Pos, T, State>
1902{
1903    type Item = T;
1904    fn next(&mut self) -> Option<T> {
1905        if let Some(t) = self.buf.pop() {
1906            return Some(t);
1907        }
1908        while let Some(t) = self.tokenizer.next() {
1909            if let Some(n) = self.default(t) {
1910                return Some(n);
1911            }
1912        }
1913        None
1914    }
1915}
1916
1917/*
1918#[test]
1919fn test() {
1920    use std::path::PathBuf;
1921    tracing::subscriber::set_global_default(
1922        tracing_subscriber::FmtSubscriber::builder()
1923            .with_max_level(tracing::Level::TRACE)
1924            .finish(),
1925    );
1926    let path = PathBuf::from("/home/jazzpirate/work/MathHub/courses/FAU/IWGS/problems/source/regex/prob/regex_scientific.de.tex");
1927    let str = std::fs::read_to_string(&path).unwrap();
1928    let reader = flams_utils::parsing::ParseStr::<flams_utils::sourcerefs::LSPLineCol>::new(&str);
1929    let parser = LaTeXParser::<'_,_,_,LaTeXToken<'_,_,_>,_>::new(reader, Some(&path),(),|e,p| tracing::error!("Error {e} ({p:?})"));
1930    for tk in parser {
1931        tracing::info!("{tk:?}");
1932    }
1933}
1934*/