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 _t = p.tokenizer.reader.read_until(|c| c == end);
237 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 _t = p.tokenizer.reader.read_until_str(end_str);
267 }
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!) {}{}!);