flams_stex/quickparse/latex/
rules.rs

1use crate::quickparse::{latex::{
2    FromLaTeXToken, LaTeXParser, Macro
3}, stex::DiagnosticLevel};
4use flams_utils::{parsing::{ParseSource, StringOrStr}, sourcerefs::{SourcePos, SourceRange}};
5
6use super::{Environment, ParserState};
7
8
9#[derive(Debug)]
10pub enum MacroResult<'a, 
11    Pos:SourcePos, 
12    Str:StringOrStr<'a>, 
13    T:FromLaTeXToken<'a,Pos, Str>
14> {
15    Success(T),
16    Simple(Macro<'a, Pos, Str>),
17    Other(Vec<T>),
18}
19
20#[derive(Debug)]
21pub enum EnvironmentResult<'a, 
22    Pos:SourcePos, 
23    Str:StringOrStr<'a>, 
24    T:FromLaTeXToken<'a,Pos, Str>
25> {
26    Success(T),
27    Simple(Environment<'a, Pos, Str, T>),
28    Other(Vec<T>),
29}
30
31pub type MacroRule<'a,
32    Pa: ParseSource<'a>,
33    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
34    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
35    State: ParserState<'a,Pa,T,Err>
36> =
37    fn(
38        Macro<'a, Pa::Pos, Pa::Str>,
39        &mut LaTeXParser<'a, Pa,T,Err,State>
40    ) -> MacroResult<'a, Pa::Pos,Pa::Str,T>;
41
42pub type EnvOpenRule<'a,
43    Pa: ParseSource<'a>,
44    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
45    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
46    State: ParserState<'a,Pa,T,Err>
47> = for<'b, 'c> fn(
48    &'b mut Environment<'a, Pa::Pos,Pa::Str,T>, 
49    &'c mut LaTeXParser<'a, Pa,T,Err,State>
50);
51
52pub type EnvCloseRule<'a,
53    Pa: ParseSource<'a>,
54    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
55    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
56    State: ParserState<'a,Pa,T,Err>
57> =
58    for<'b> fn(
59        Environment<'a, Pa::Pos,Pa::Str,T>,
60        &'b mut LaTeXParser<'a, Pa,T,Err,State>
61    ) -> EnvironmentResult<'a, Pa::Pos,Pa::Str,T>;
62
63pub type EnvironmentRule<'a,
64    Pa: ParseSource<'a>,
65    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
66    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
67    State: ParserState<'a,Pa,T,Err>
68> = (EnvOpenRule<'a, Pa,T,Err,State>, EnvCloseRule<'a, Pa,T,Err,State>);
69
70
71#[allow(clippy::type_complexity)]
72pub struct DynMacro<'a,
73    Pa: ParseSource<'a>,
74    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
75    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
76    State: ParserState<'a,Pa,T,Err>,
77    Arg
78> {
79    pub ptr:fn(
80        &Arg,
81        Macro<'a, Pa::Pos, Pa::Str>,
82        &mut LaTeXParser<'a, Pa, T, Err,State>
83    ) -> MacroResult<'a, Pa::Pos, Pa::Str, T>,
84    pub arg:Arg
85}
86
87#[allow(clippy::type_complexity)]
88pub struct DynEnv<'a,
89    Pa: ParseSource<'a>,
90    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
91    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
92    State: ParserState<'a,Pa,T,Err>,
93    Arg
94> {
95    pub open:for<'b, 'c> fn(
96        &Arg,
97        &'b mut Environment<'a, Pa::Pos, Pa::Str, T>, 
98        &'c mut LaTeXParser<'a, Pa, T, Err,State>
99    ),
100    pub close:for<'b> fn(
101        Environment<'a, Pa::Pos, Pa::Str, T>,
102        &'b mut LaTeXParser<'a, Pa, T, Err, State>
103    ) -> EnvironmentResult<'a, Pa::Pos, Pa::Str, T>,
104    pub arg:Arg
105}
106
107pub enum AnyMacro<'a,
108    Pa: ParseSource<'a>,
109    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
110    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
111    State: ParserState<'a,Pa,T,Err>
112> {
113    Ptr(MacroRule<'a,Pa,T,Err,State>),
114    Str(DynMacro<'a,Pa,T,Err,State,Pa::Str>),
115    Ext(DynMacro<'a,Pa,T,Err,State,State::MacroArg>)
116}
117
118impl<'a,
119    Pa: ParseSource<'a>,
120    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
121    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
122    State: ParserState<'a,Pa,T,Err>
123> AnyMacro<'a,Pa,T,Err,State> {
124    pub fn call(&self,
125        m:Macro<'a, Pa::Pos, Pa::Str>,
126        p:&mut LaTeXParser<'a, Pa, T, Err, State>
127    ) -> MacroResult<'a, Pa::Pos, Pa::Str, T> {
128        match self {
129            Self::Ptr(ptr) => ptr(m,p),
130            Self::Str(str) => (str.ptr)(&str.arg,m,p),
131            Self::Ext(ext) => (ext.ptr)(&ext.arg,m,p)
132        }
133    }
134}
135
136impl<'a,
137    Pa: ParseSource<'a>,
138    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
139    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
140    State: ParserState<'a,Pa,T,Err>
141> Clone for AnyMacro<'a,Pa,T,Err,State> {
142    fn clone(&self) -> Self {
143        match self {
144            Self::Ptr(ptr) => Self::Ptr(*ptr),
145            Self::Str(str) => Self::Str(
146                DynMacro {
147                    ptr:str.ptr,
148                    arg:str.arg.clone()
149                }
150            ),
151            Self::Ext(ext) => Self::Ext(
152                DynMacro {
153                    ptr:ext.ptr,
154                    arg:ext.arg.clone()
155                }
156            )
157        }
158    }
159}
160
161pub enum AnyEnv<'a,
162    Pa: ParseSource<'a>,
163    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
164    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
165    State: ParserState<'a,Pa,T,Err>
166> {
167    Ptr(EnvironmentRule<'a,Pa,T,Err,State>),
168    Str(DynEnv<'a,Pa,T,Err,State,Pa::Str>),
169    Ext(DynEnv<'a,Pa,T,Err,State,State::MacroArg>)
170}
171
172impl<'a,
173    Pa: ParseSource<'a>,
174    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
175    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
176    State: ParserState<'a,Pa,T,Err>
177> AnyEnv<'a,Pa,T,Err,State> {
178    pub fn open<'b, 'c>(&self,
179        e:&'b mut Environment<'a, Pa::Pos,Pa::Str,T>, 
180        p:&'c mut LaTeXParser<'a, Pa, T, Err, State>
181    ) {
182        match self {
183            Self::Ptr((ptr,_)) => ptr(e,p),
184            Self::Str(str) => (str.open)(&str.arg,e,p),
185            Self::Ext(ext) => (ext.open)(&ext.arg,e,p)
186        }
187    }
188    pub fn close(self) -> EnvCloseRule<'a, Pa,T,Err,State> {
189        match self {
190            Self::Ptr((_,close)) => close,
191            Self::Str(str) => str.close,
192            Self::Ext(ext) => ext.close
193        }
194    }
195}
196
197impl<'a,
198    Pa: ParseSource<'a>,
199    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
200    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
201    State: ParserState<'a,Pa,T,Err>
202> Clone for AnyEnv<'a,Pa,T,Err,State> {
203    fn clone(&self) -> Self {
204        match self {
205            Self::Ptr(ptr) => Self::Ptr(*ptr),
206            Self::Str(str) => Self::Str(
207                DynEnv {
208                    open:str.open,
209                    close:str.close,
210                    arg:str.arg.clone()
211                }
212            ),
213            Self::Ext(ext) => Self::Ext(
214                DynEnv {
215                    open:ext.open,
216                    close:ext.close,
217                    arg:ext.arg.clone()
218                }
219            )
220        }
221    }
222}
223
224
225pub fn read_verbatim_char<'a,
226    Pa: ParseSource<'a>,
227    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
228    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
229    State: ParserState<'a,Pa,T,Err>
230>(
231    mac: &mut Macro<'a, Pa::Pos, Pa::Str>,
232    p: &mut LaTeXParser<'a, Pa, T, Err, State>,
233    end: char,
234) {
235    //let tstart = p.curr_pos();
236    let _t = p.tokenizer.reader.read_until(|c| c == end);
237    /*if let Some(text) = T::from_text(
238        SourceRange {
239            start: tstart,
240            end: p.curr_pos(),
241        },
242        t,
243    ) {
244        mac.args.push(text);
245    }*/
246    if let Some(h2) = p.tokenizer.reader.pop_head() {
247        if h2 != end {
248            p.tokenizer.problem(mac.range.start,"Expected end of verbatim",DiagnosticLevel::Error);
249        }
250    } else {
251        p.tokenizer.problem(mac.range.start,"Expected end of verbatim",DiagnosticLevel::Error);
252    }
253}
254
255pub fn read_verbatim_str<'a,
256    Pa: ParseSource<'a>,
257    T: FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
258    Err:FnMut(String,SourceRange<Pa::Pos>,DiagnosticLevel),
259    State: ParserState<'a,Pa,T,Err>
260>(
261    _env: &mut Environment<'a, Pa::Pos, Pa::Str, T>,
262    p: &mut LaTeXParser<'a, Pa, T, Err, State>,
263    end_str: &str,
264) {
265    //let tstart = p.curr_pos();
266    let _t = p.tokenizer.reader.read_until_str(end_str);
267    /*if let Some(text) = T::from_text(
268        SourceRange {
269            start: tstart,
270            end: p.curr_pos(),
271        },
272        t,
273    ) {
274        env.args.push(text);
275    }*/
276}
277
278#[macro_export]
279macro_rules! texrules {
280    ($name:ident <= $(($($rl:tt)*))*) => {
281        $(
282            $crate::tex!($($rl)*)
283        )*
284        paste!{
285            pub fn [<$name _macros>]<'a, Pa: ParseSource<'a>, T: FromLaTeXToken<'a, Pa::Str, Pa::Pos>>() ->
286            [(Pa::Str,MacroRule<'a,Pa,T>);texrules!( $( ($($rl)*) )* )] {[
287                todo!()
288            ]}
289        }
290    };
291    (@count ) => (0usize);
292    (@count ($($i:tt)*) $($r:tt)* ) => {
293        (1usize + texrules!(@count $($r)*))
294    }
295}
296
297#[macro_export]
298macro_rules! tex {
299    ($p:ident => $name:ident$($args:tt)*) => {
300        #[allow(unused_mut,non_snake_case)]
301        pub fn $name<'a,
302            Pa: ::flams_utils::parsing::ParseSource<'a>,
303            T: $crate::quickparse::latex::FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
304            Err:FnMut(String,::flams_utils::sourcerefs::SourceRange<Pa::Pos>,DiagnosticLevel),
305            State: $crate::quickparse::latex::ParserState<'a,Pa,T,Err>
306        >(
307            mut $name:$crate::quickparse::latex::Macro<'a,Pa::Pos,Pa::Str>,
308            $p:&mut $crate::quickparse::latex::LaTeXParser<'a, Pa, T, Err, State>
309        ) -> $crate::quickparse::latex::rules::MacroResult<'a, Pa::Pos, Pa::Str,T> {
310            tex!{@args $p:$name$($args)*}
311        }
312    };
313
314    ($p:ident => @begin{$name:ident}$( ($($args:tt)* ) )? {$($start:tt)*} $($end:tt)*) => {paste::paste!(
315        #[allow(unused,unused_mut,non_snake_case)]
316        pub fn [<$name _open>]<'a,
317            Pa: ::flams_utils::parsing::ParseSource<'a>,
318            T: $crate::quickparse::latex::FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
319            Err:FnMut(String,::flams_utils::sourcerefs::SourceRange<Pa::Pos>,DiagnosticLevel),
320            State: $crate::quickparse::latex::ParserState<'a,Pa,T,Err>
321        >(
322            $name:&mut $crate::quickparse::latex::Environment<'a, Pa::Pos, Pa::Str, T>,
323            $p:&mut $crate::quickparse::latex::LaTeXParser<'a, Pa, T, Err, State>
324        ) {
325            $( tex!{@envargs $p:$name $($args)* } )?
326            $($start)*
327        }
328        #[allow(unused,unused_mut,non_snake_case)]
329        pub fn [<$name _close>]<'a,
330            Pa: ::flams_utils::parsing::ParseSource<'a>,
331            T: $crate::quickparse::latex::FromLaTeXToken<'a, Pa::Pos, Pa::Str>,
332            Err:FnMut(String,::flams_utils::sourcerefs::SourceRange<Pa::Pos>,DiagnosticLevel),
333            State: $crate::quickparse::latex::ParserState<'a,Pa,T,Err>
334        >(
335            mut $name:$crate::quickparse::latex::Environment<'a,Pa::Pos, Pa::Str, T>,
336            $p:&mut $crate::quickparse::latex::LaTeXParser<'a, Pa, T, Err, State>
337        ) -> $crate::quickparse::latex::rules::EnvironmentResult<'a,Pa::Pos,Pa::Str,T> {
338            tex!{@end $name $($end)*}
339        }
340    );};
341
342    (<{$($tks:tt)+} M{$($mtks:tt)+} P{$($ptks:tt)+} R{$($rtks:tt)+}> $p:ident => $name:ident $($args:tt)*) => {
343        #[allow(unused_mut,non_snake_case)]
344        pub fn $name<$($tks)*>(
345            mut $name:$crate::quickparse::latex::Macro<$($mtks)*>,
346            $p:&mut $crate::quickparse::latex::LaTeXParser<$($ptks)*>
347        ) -> $crate::quickparse::latex::rules::MacroResult<$($rtks)*> {
348            tex!{@args $p:$name$($args)*}
349        }
350    };
351
352    (<{$($tks:tt)+} E{$($mtks:tt)+} P{$($ptks:tt)+} R{$($rtks:tt)+}> $p:ident => @begin{$name:ident}$( ($($args:tt)* ) )? {$($start:tt)*} $($end:tt)*) => {paste::paste!(
353        #[allow(unused,unused_mut,non_snake_case)]
354        pub fn [<$name _open>]<$($tks)*>(
355            $name:&mut $crate::quickparse::latex::Environment<$($mtks)*>,
356            $p:&mut $crate::quickparse::latex::LaTeXParser<$($ptks)*>
357        ) {
358            $( tex!{@envargs $p:$name $($args)* } )?
359            $($start)*
360        }
361        #[allow(unused,unused_mut,non_snake_case)]
362        pub fn [<$name _close>]<$($tks)*>(
363            mut $name:$crate::quickparse::latex::Environment<$($mtks)*>,
364            $p:&mut $crate::quickparse::latex::LaTeXParser<$($ptks)*>
365        ) -> $crate::quickparse::latex::rules::EnvironmentResult<$($rtks)*> {
366            tex!{@end $name $($end)*}
367        }
368    );};
369
370    (@end $name:ident $b:block !) => {
371        $b
372        $crate::quickparse::latex::rules::EnvironmentResult::Simple($name)
373    };
374    (@end $name:ident !) => {
375        $crate::quickparse::latex::rules::EnvironmentResult::Simple($name)
376    };
377    (@end $name:ident $b:block) => {$b};
378
379    (@envargs $p:ident:$name:ident{$arg:ident:name}$($args:tt)*) => {
380        let Some($arg) = $p.read_name(&mut $name.begin) else {
381            $p.tokenizer.problem($name.begin.range.start,concat!("Expected { after \\",stringify!($name)),DiagnosticLevel::Error);
382            return;
383        };
384        tex!{@envargs $p:$name $($args)*}
385    };
386    (@envargs $p:ident:$name:ident{$arg:ident:!name}$($args:tt)*) => {
387        let Some($arg) = $p.read_name_normalized(&mut $name.begin) else {
388            $p.tokenizer.problem($name.begin.range.start,concat!("Expected { after \\",stringify!($name)),DiagnosticLevel::Error);
389            return;
390        };
391        tex!{@envargs $p:$name $($args)*}
392    };
393    (@envargs $p:ident:$name:ident{$arg:ident:name+}$($args:tt)*) => {
394        let $arg = $p.read_names(&mut $name.begin);
395        if $arg.is_empty() {
396            $p.tokenizer.problem($name.begin.range.start,concat!("Expected { after \\",stringify!($name)),DiagnosticLevel::Error);
397            return;
398        };
399        tex!{@envargs $p:$name $($args)*}
400    };
401    (@envargs $p:ident:$name:ident{$arg:ident:!name+}$($args:tt)*) => {
402        let $arg = $p.read_names_normalized(&mut $name.begin);
403        if $arg.is_empty() {
404            $p.tokenizer.problem($name.begin.range.start,concat!("Expected { after \\",stringify!($name)),DiagnosticLevel::Error);
405            return;
406        };
407        tex!{@envargs $p:$name $($args)*}
408    };
409    (@envargs $p:ident:$name:ident{$arg:ident:T}$($args:tt)*) => {
410        let mode = $p.tokenizer.mode;
411        $p.open_group();
412        $p.tokenizer.mode = $crate::quickparse::tokenizer::Mode::Text;
413        let $arg = $p.get_argument(&mut $name.begin);
414        $p.tokenizer.mode = mode;
415        $p.close_group();
416        tex!{@envargs $p:$name $($args)*}
417    };
418    (@envargs $p:ident:$name:ident{_:T}$($args:tt)*) => {
419        let mode = $p.tokenizer.mode;
420        $p.open_group();
421        $p.tokenizer.mode = $crate::quickparse::tokenizer::Mode::Text;
422        $p.read_argument(&mut $name.begin);
423        $p.tokenizer.mode = mode;
424        $p.close_group();
425        tex!{@envargs $p:$name $($args)*}
426    };
427    (@envargs $p:ident:$name:ident{$arg:ident:M}$($args:tt)*) => {
428        let mode = $p.tokenizer.mode;
429        let $arg = if matches!($p.tokenizer.mode,$crate::quickparse::tokenizer::Mode::Math{..}) {
430            $p.get_argument(&mut $name.begin)
431        } else {
432            $p.tokenizer.open_math(false);
433            let r = $p.get_argument(&mut $name.begin);
434            $p.tokenizer.close_math();
435            r
436        };
437        tex!{@envargs $p:$name $($args)*}
438    };
439    (@envargs $p:ident:$name:ident{_:M}$($args:tt)*) => {
440        let mode = $p.tokenizer.mode;
441        if matches!($p.tokenizer.mode,$crate::quickparse::tokenizer::Mode::Math{..}) {
442            $p.read_argument(&mut $name.begin);
443        } else {
444            $p.tokenizer.open_math(false);
445            $p.read_argument(&mut $name.begin);
446            $p.tokenizer.close_math();
447        }
448        tex!{@envargs $p:$name $($args)*}
449    };
450    (@envargs $p:ident:$name:ident{_}$($args:tt)*) => {
451        $p.skip_arg(&mut $name.begin);
452        tex!{@envargs $p:$name $($args)*}
453    };
454    (@envargs $p:ident:$name:ident[_?$opt:ident]$($args:tt)*) => {
455        let $opt = $p.skip_opt(&mut $name.begin);
456        tex!{@envargs $p:$name $($args)*}
457    };
458    (@envargs $p:ident:$name:ident[_]$($args:tt)*) => {
459        $p.skip_opt(&mut $name.begin);
460        tex!{@envargs $p:$name $($args)*}
461    };
462    (@envargs $p:ident:$name:ident[$opt:ident:str]$($args:tt)*) => {
463        let $opt = $p.read_opt_str(&mut $name.begin).into_name();
464        tex!{@envargs $p:$name $($args)*}
465    };
466    (@envargs $p:ident:$name:ident[$opt:ident:!name]$($args:tt)*) => {
467        let $opt = $p.read_opt_name_normalized(&mut $name.begin);
468        tex!{@envargs $p:$name $($args)*}
469    };
470    (@envargs $p:ident:$name:ident[$opt:ident]$($args:tt)*) => {
471        let $opt = $p.read_opt_str(&mut $name.begin);
472        tex!{@envargs $p:$name $($args)*}
473    };
474    (@envargs $p:ident:$name:ident[mut $opt:ident:Map]$($args:tt)*) => {
475        let mut $opt = $p.read_opt_map(&mut $name.begin);
476        tex!{@envargs $p:$name $($args)*}
477    };
478    (@envargs $p:ident:$name:ident[$opt:ident:Map]$($args:tt)*) => {
479        let $opt = $p.read_opt_map(&mut $name.begin);
480        tex!{@envargs $p:$name $($args)*}
481    };
482    (@envargs $p:ident:$name:ident[$opt:ident:type $tp:ty]$($args:tt)*) => {
483        let $opt = <Vec<$tp> as crate::quickparse::latex::KeyValValues<_,_,_,_>>::parse_opt($p);
484        tex!{@envargs $p:$name $($args)*}
485    };
486    (@envargs $p:ident:$name:ident V:C($c:expr) $($args:tt)*) => {
487        $crate::quickparse::latex::rules::read_verbatim_char(&mut $name.begin,$p,$c);
488        tex!{@envargs $p:$name $($args)*}
489    };
490    (@envargs $p:ident:$name:ident V) => {
491        $crate::quickparse::latex::rules::read_verbatim_str($name,$p,concat!("\\end{",stringify!($name),"}"));
492    };
493    (@envargs $p:ident:$name:ident V!) => {
494        $crate::quickparse::latex::rules::read_verbatim_str($name,$p,&format!("\\end{{{}}}",$name.name));
495    };
496    (@envargs $p:ident:$name:ident($c:literal?$t:ident)$($args:tt)*) => {
497        let $t = $p.tokenizer.reader.starts_with($c) && {
498            $p.tokenizer.reader.pop_head();true
499        };
500        tex!{@envargs $p:$name $($args)*}
501    };
502    (@envargs $p:ident:$name:ident($t:ident)$($args:tt)*) => {
503        if let Some($t) = $p.tokenizer.reader.pop_head() {
504            tex!{@envargs $p:$name $($args)*}
505        } else {
506            $p.tokenizer.problem("Expected character",DiagnosticLevel::Error);
507        }
508    };
509    (@envargs $p:ident:$name:ident => $b:block) => {$b};
510    (@envargs $p:ident:$name:ident) => {};
511
512    (@args $p:ident:$name:ident{$arg:ident:name}$($args:tt)*) => {
513        let Some($arg) = $p.read_name(&mut $name) else {
514            $p.tokenizer.problem($name.range.start,concat!("Expected { after \\",stringify!($name)),DiagnosticLevel::Error);
515            return $crate::quickparse::latex::rules::MacroResult::Simple($name);
516        };
517        tex!{@args $p:$name $($args)*}
518    };
519    (@args $p:ident:$name:ident{$arg:ident:!name}$($args:tt)*) => {
520        let Some($arg) = $p.read_name_normalized(&mut $name) else {
521            $p.tokenizer.problem($name.range.start,concat!("Expected { after \\",stringify!($name)),DiagnosticLevel::Error);
522            return $crate::quickparse::latex::rules::MacroResult::Simple($name);
523        };
524        tex!{@args $p:$name $($args)*}
525    };
526    (@args $p:ident:$name:ident{$arg:ident}$($args:tt)*) => {
527        let $arg = $p.get_argument(&mut $name);
528        tex!{@args $p:$name $($args)*}
529    };
530    (@args $p:ident:$name:ident{$arg:ident:T}$($args:tt)*) => {
531        let mode = $p.tokenizer.mode;
532        $p.open_group();
533        $p.tokenizer.mode = $crate::quickparse::tokenizer::Mode::Text;
534        let $arg = $p.get_argument(&mut $name);
535        $p.tokenizer.mode = mode;
536        $p.close_group();
537        tex!{@args $p:$name $($args)*}
538    };
539    (@args $p:ident:$name:ident{_:T}$($args:tt)*) => {
540        let mode = $p.tokenizer.mode;
541        $p.open_group();
542        $p.tokenizer.mode = $crate::quickparse::tokenizer::Mode::Text;
543        $p.read_argument(&mut $name);
544        $p.tokenizer.mode = mode;
545        $p.close_group();
546        tex!{@args $p:$name $($args)*}
547    };
548    (@args $p:ident:$name:ident{$arg:ident:M}$($args:tt)*) => {
549        let mode = $p.tokenizer.mode;
550        let $arg = if matches!($p.tokenizer.mode,$crate::quickparse::tokenizer::Mode::Math{..}) {
551            $p.get_argument(&mut $name)
552        } else {
553            $p.tokenizer.open_math(false);
554            let r = $p.get_argument(&mut $name);
555            $p.tokenizer.close_math();
556            r
557        };
558        tex!{@args $p:$name $($args)*}
559    };
560    (@args $p:ident:$name:ident{_:M}$($args:tt)*) => {
561        if matches!($p.tokenizer.mode,$crate::quickparse::tokenizer::Mode::Math{..}) {
562            $p.read_argument(&mut $name);
563        } else {
564            $p.tokenizer.open_math(false);
565            $p.read_argument(&mut $name);
566            $p.tokenizer.close_math();
567        }
568        tex!{@args $p:$name $($args)*}
569    };
570    (@args $p:ident:$name:ident{_}$($args:tt)*) => {
571        $p.skip_arg(&mut $name);
572        tex!{@args $p:$name $($args)*}
573    };
574    (@args $p:ident:$name:ident[_?$opt:ident]$($args:tt)*) => {
575        let $opt = $p.skip_opt(&mut $name);
576        tex!{@args $p:$name $($args)*}
577    };
578    (@args $p:ident:$name:ident[_]$($args:tt)*) => {
579        $p.skip_opt(&mut $name);
580        tex!{@args $p:$name $($args)*}
581    };
582    (@args $p:ident:$name:ident[$opt:ident:str]$($args:tt)*) => {
583        let $opt = $p.read_opt_str(&mut $name).into_name();
584        tex!{@args $p:$name $($args)*}
585    };
586    (@args $p:ident:$name:ident[$opt:ident:!name]$($args:tt)*) => {
587        let $opt = $p.read_opt_name_normalized(&mut $name);
588        tex!{@args $p:$name $($args)*}
589    };
590    (@args $p:ident:$name:ident[$opt:ident]$($args:tt)*) => {
591        let $opt = $p.read_opt_str(&mut $name);
592        tex!{@args $p:$name $($args)*}
593    };
594    (@args $p:ident:$name:ident[mut $opt:ident:Map]$($args:tt)*) => {
595        let mut $opt = $p.read_opt_map(&mut $name);
596        tex!{@args $p:$name $($args)*}
597    };
598    (@args $p:ident:$name:ident[$opt:ident:Map]$($args:tt)*) => {
599        let $opt = $p.read_opt_map(&mut $name);
600        tex!{@args $p:$name $($args)*}
601    };
602    (@args $p:ident:$name:ident[$opt:ident:type $tp:ty]$($args:tt)*) => {
603        let $opt = <Vec<$tp> as crate::quickparse::latex::KeyValValues<_,_,_,_>>::parse_opt($p);
604        tex!{@args $p:$name $($args)*}
605    };
606    (@args $p:ident:$name:ident V:C($c:expr) $($args:tt)*) => {
607        $crate::quickparse::latex::rules::read_verbatim_char(&mut $name,$p,$c);
608        tex!{@args $p:$name $($args)*}
609    };
610    (@args $p:ident:$name:ident($c:literal?$t:ident)$($args:tt)*) => {
611        let $t = $p.tokenizer.reader.starts_with($c) && {
612            $p.tokenizer.reader.pop_head();true
613        };
614        tex!{@args $p:$name $($args)*}
615    };
616    (@args $p:ident:$name:ident($t:ident)$($args:tt)*) => {
617        if let Some($t) = $p.tokenizer.reader.pop_head() {
618            tex!{@args $p:$name $($args)*}
619        } else {
620            $p.tokenizer.problem($name.range.start,"Expected character",DiagnosticLevel::Error);
621            $crate::quickparse::latex::rules::MacroResult::Simple($name)
622        }
623    };
624    (@args $p:ident:$name:ident !) => {
625        $crate::quickparse::latex::rules::MacroResult::Simple($name)
626    };
627    (@args $p:ident:$name:ident => $b:block !) => {
628        $b;
629        $crate::quickparse::latex::rules::MacroResult::Simple($name)
630    };
631    (@args $p:ident:$name:ident => $b:block) => {$b};
632}
633
634tex!(p => begin{n:name} => {
635    match p.environment(begin,n.0,n.1) {
636        EnvironmentResult::Success(e) => MacroResult::Success(e),
637        EnvironmentResult::Other(v) => MacroResult::Other(v),
638        EnvironmentResult::Simple(e) => T::from_environment(e).map_or_else(
639            || MacroResult::Other(Vec::new()),
640            MacroResult::Success
641        )
642    }
643});
644
645tex!(p => end{n:name} => {
646    p.tokenizer.problem(end.range.start,format!("environment {} not open",n.0.as_ref()),DiagnosticLevel::Error);
647}!);
648
649tex!(p => lstinline[_](c)V:C(c)!);
650tex!(p => verb[_](c)V:C(c)!);
651tex!(p => stexcodeinline[_](c)V:C(c)!);
652tex!(p => stexinline[_](c)V:C(c)!);
653tex!(p => begingroup => { p.open_group() }!);
654tex!(p => endgroup => { p.close_group() }!);
655tex!(p => makeatletter => { p.add_letters("@") }!);
656tex!(p => makeatother => { p.remove_letters("@") }!);
657tex!(p => ExplSyntaxOn => { p.add_letters(":_") }!);
658tex!(p => ExplSyntaxOff => { p.remove_letters(":_") }!);
659tex!(p => lstdefinelanguage{_}[_?o]{_} => {
660    if o {p.skip_arg(&mut lstdefinelanguage);}
661}!);
662tex!(p => r#ref{_}!);
663tex!(p => label{_}!);
664tex!(p => cite{_}!);
665tex!(p => includegraphics[_]{_}!);
666tex!(p => url[_]{_}!);
667
668tex!(p => newcommand{_}[_][_]{_}!);
669tex!(p => providecommand{_}[_][_]{_}!);
670tex!(p => renewcommand{_}[_][_]{_}!);
671tex!(p => NewDocumentCommand{_}{_}{_}!);
672tex!(p => DeclareDocumentCommand{_}{_}{_}!);
673tex!(p => DeclareRobustCommand{_}{_}{_}!);
674tex!(p => newenvironment{_}[_][_]{_}{_}!);
675tex!(p => renewenvironment{_}[_][_]{_}{_}!);
676tex!(p => provideenvironment{_}[_][_]{_}{_}!);
677tex!(p => NewDocumentEnvironment{_}{_}{_}{_}!);
678tex!(p => DeclareDocumentEnvironment{_}{_}{_}{_}!);
679
680tex!(p => hbox{t:T} => { MacroResult::Other(t.1) });
681tex!(p => vbox{t:T} => { MacroResult::Other(t.1) });
682tex!(p => fbox{t:T} => { MacroResult::Other(t.1) });
683tex!(p => mvbox{t:T} => { MacroResult::Other(t.1) });
684tex!(p => text{t:T} => { MacroResult::Other(t.1) });
685tex!(p => texttt{t:T} => { MacroResult::Other(t.1) });
686tex!(p => textrm{t:T} => { MacroResult::Other(t.1) });
687tex!(p => textbf{t:T} => { MacroResult::Other(t.1) });
688tex!(p => scalebox{_}{t:T} => { MacroResult::Other(t.1) });
689tex!(p => raisebox{_}{t:T} => { MacroResult::Other(t.1) });
690tex!(p => ensuremath{t:M} => { MacroResult::Other(t.1) });
691
692
693tex!(p => def => {
694    p.tokenizer.reader.read_until(|c| c == '{');
695    p.skip_arg(&mut def);
696}!);
697tex!(p => edef => {def(edef,p)});
698tex!(p => gdef => {def(gdef,p)});
699tex!(p => xdef => {def(xdef,p)});
700
701tex!(p => @begin{document} {}{
702    let _start = p.curr_pos();
703    let _rest = p.tokenizer.reader.read_until_str("this string should never occur FOOBARBAZ BLA BLA asdk<ösndkf.k<asfb.mdv <sdasdjn");
704}!);
705tex!(p => @begin{verbatim}(V) {}{}!);
706tex!(p => @begin{lstlisting}(V) {}{}!);
707tex!(p => @begin{stexcode}(V) {}{}!);
708
709tex!(p => @begin{general_listing}(V!) {}{}!);