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