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