1use std::collections::HashMap;
2
3use ratex_lexer::token::{SourceLocation, Token};
4use ratex_lexer::Lexer;
5
6use crate::error::{ParseError, ParseResult};
7use crate::functions::FUNCTIONS;
8use crate::parse_node::Mode;
9use crate::stack_safety::{DepthBudget, MAX_INPUT_DEPTH};
10
11pub static IMPLICIT_COMMANDS: &[&str] = &["^", "_", "\\limits", "\\nolimits"];
14
15pub type FnMacroHandler = fn(&mut MacroExpander) -> ParseResult<Vec<Token>>;
18
19#[derive(Clone)]
21pub enum MacroDefinition {
22 Text(String),
24 Tokens { tokens: Vec<Token>, num_args: usize },
26 Function(FnMacroHandler),
28}
29
30impl std::fmt::Debug for MacroDefinition {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 Self::Text(s) => write!(f, "Text({:?})", s),
34 Self::Tokens { tokens, num_args } => {
35 write!(f, "Tokens {{ {} tokens, {} args }}", tokens.len(), num_args)
36 }
37 Self::Function(_) => write!(f, "Function(...)"),
38 }
39 }
40}
41
42struct MacroExpansion {
44 tokens: Vec<Token>,
45 num_args: usize,
46 unexpandable: bool,
47}
48
49pub struct MacroExpander<'a> {
57 pub lexer: Lexer<'a>,
58 pub mode: Mode,
59 stack: Vec<Token>,
60 macros: MacroNamespace,
61 expansion_count: usize,
62 max_expand: usize,
63 depth_budget: DepthBudget,
64 expand_tokens_depth: usize,
65}
66
67struct MacroNamespace {
69 current: HashMap<String, MacroDefinition>,
70 group_stack: Vec<HashMap<String, Option<MacroDefinition>>>,
71}
72
73impl MacroNamespace {
74 fn new() -> Self {
75 Self {
76 current: HashMap::new(),
77 group_stack: Vec::new(),
78 }
79 }
80
81 fn get(&self, name: &str) -> Option<&MacroDefinition> {
82 self.current.get(name)
83 }
84
85 fn set(&mut self, name: String, def: MacroDefinition) {
86 if let Some(undo) = self.group_stack.last_mut() {
87 undo.entry(name.clone())
88 .or_insert_with(|| self.current.get(&name).cloned());
89 }
90 self.current.insert(name, def);
91 }
92
93 fn set_global(&mut self, name: String, def: MacroDefinition) {
94 self.current.insert(name, def);
95 }
96
97 fn has(&self, name: &str) -> bool {
98 self.current.contains_key(name)
99 }
100
101 fn begin_group(&mut self) {
102 self.group_stack.push(HashMap::new());
103 }
104
105 fn end_group(&mut self) {
106 if let Some(undo) = self.group_stack.pop() {
107 for (name, old_val) in undo {
108 match old_val {
109 Some(def) => {
110 self.current.insert(name, def);
111 }
112 None => {
113 self.current.remove(&name);
114 }
115 }
116 }
117 }
118 }
119
120 fn end_groups(&mut self) {
121 while !self.group_stack.is_empty() {
122 self.end_group();
123 }
124 }
125}
126
127fn lex_string_to_stack_tokens(text: &str) -> Vec<Token> {
129 let mut body_lexer = Lexer::new(text);
130 let mut tokens = Vec::new();
131 loop {
132 let tok = body_lexer.lex();
133 if tok.is_eof() {
134 break;
135 }
136 tokens.push(tok);
137 }
138 tokens.reverse();
139 tokens
140}
141
142fn dotsc_space_after(next: &str) -> bool {
143 matches!(
144 next,
145 ")" | "]"
146 | "\\rbrack"
147 | "\\}"
148 | "\\rbrace"
149 | "\\rangle"
150 | "\\rceil"
151 | "\\rfloor"
152 | "\\rgroup"
153 | "\\rmoustache"
154 | "\\right"
155 | "\\bigr"
156 | "\\biggr"
157 | "\\Bigr"
158 | "\\Biggr"
159 | "$"
160 | ";"
161 | "."
162 )
163}
164
165fn dotso_space_after(next: &str) -> bool {
166 next == "," || dotsc_space_after(next)
167}
168
169fn contextual_dots_for(next: &str) -> &'static str {
170 if next == "," {
171 "\\dotsc"
172 } else if matches!(
173 next,
174 "\\not"
175 | "+"
176 | "="
177 | "<"
178 | ">"
179 | "-"
180 | "*"
181 | ":"
182 | "\\DOTSB"
183 | "\\coprod"
184 | "\\bigvee"
185 | "\\bigwedge"
186 | "\\biguplus"
187 | "\\bigcap"
188 | "\\bigcup"
189 | "\\prod"
190 | "\\sum"
191 | "\\bigotimes"
192 | "\\bigoplus"
193 | "\\bigodot"
194 | "\\bigsqcup"
195 | "\\And"
196 | "\\longrightarrow"
197 | "\\Longrightarrow"
198 | "\\longleftarrow"
199 | "\\Longleftarrow"
200 | "\\longleftrightarrow"
201 | "\\Longleftrightarrow"
202 | "\\mapsto"
203 | "\\longmapsto"
204 | "\\hookrightarrow"
205 | "\\doteq"
206 | "\\mathbin"
207 | "\\mathrel"
208 | "\\relbar"
209 | "\\Relbar"
210 | "\\xrightarrow"
211 | "\\xleftarrow"
212 ) || next.starts_with("\\not")
213 || ratex_font::get_symbol(next, ratex_font::Mode::Math).is_some_and(|symbol| {
214 matches!(
215 symbol.group,
216 ratex_font::symbols::Group::Bin | ratex_font::symbols::Group::Rel
217 )
218 })
219 {
220 "\\dotsb"
221 } else if matches!(
222 next,
223 "\\DOTSI" | "\\int" | "\\oint" | "\\iint" | "\\iiint" | "\\iiiint" | "\\idotsint"
224 ) {
225 "\\dotsi"
226 } else if next == "\\DOTSX" {
227 "\\dotsx"
228 } else {
229 "\\dotso"
230 }
231}
232
233impl<'a> MacroExpander<'a> {
234 pub fn new(input: &'a str, mode: Mode) -> Self {
235 Self::new_with_budget(input, mode, DepthBudget::new(MAX_INPUT_DEPTH))
236 }
237
238 pub(crate) fn new_with_budget(input: &'a str, mode: Mode, depth_budget: DepthBudget) -> Self {
239 let mut me = Self {
240 lexer: Lexer::new(input),
241 mode,
242 stack: Vec::new(),
243 macros: MacroNamespace::new(),
244 expansion_count: 0,
245 max_expand: 1000,
246 depth_budget,
247 expand_tokens_depth: 0,
248 };
249 me.load_builtins();
250 me
251 }
252
253 fn load_builtins(&mut self) {
254 let builtins: &[(&str, &str)] = &[
255 ("\\bgroup", "{"),
257 ("\\egroup", "}"),
258
259 ("\\lq", "`"),
261 ("\\rq", "'"),
262 ("\\aa", "\\r a"),
264 ("\\AA", "\\r A"),
265
266 ("~", "\\nobreakspace"),
268
269 ("\\hphantom", "\\smash{\\phantom{#1}}"),
271
272 ("\\not", "\\html@mathml{\\mathrel{\\mathrlap\\@not}\\nobreak}{\\char\"338}"),
274 ("\\neq", "\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}"),
275 ("\\ne", "\\neq"),
276 ("\u{2260}", "\\neq"),
277 ("\\notin", "\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}{\\mathrel{\\char`∉}}"),
278 ("\u{2209}", "\\notin"),
279 ("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u{220C}}}"),
280 ("\u{220C}", "\\notni"),
281 ("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"),
285 ("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"),
286 ("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"),
287
288 ("\\varGamma", "\\mathit{\\Gamma}"),
290 ("\\varDelta", "\\mathit{\\Delta}"),
291 ("\\varTheta", "\\mathit{\\Theta}"),
292 ("\\varLambda", "\\mathit{\\Lambda}"),
293 ("\\varXi", "\\mathit{\\Xi}"),
294 ("\\varPi", "\\mathit{\\Pi}"),
295 ("\\varSigma", "\\mathit{\\Sigma}"),
296 ("\\varUpsilon", "\\mathit{\\Upsilon}"),
297 ("\\varPhi", "\\mathit{\\Phi}"),
298 ("\\varPsi", "\\mathit{\\Psi}"),
299 ("\\varOmega", "\\mathit{\\Omega}"),
300
301 ("\\,", "\\TextOrMath{\\kern{.1667em}}{\\mskip{3mu}}"),
303 ("\\thinspace", "\\,"),
304 ("\\>", "\\mskip{4mu}"),
305 ("\\:", "\\TextOrMath{\\kern{.2222em}}{\\mskip{4mu}}"),
306 ("\\medspace", "\\:"),
307 ("\\;", "\\TextOrMath{\\kern{.2777em}}{\\mskip{5mu}}"),
308 ("\\thickspace", "\\;"),
309 ("\\!", "\\TextOrMath{\\kern{-.1667em}}{\\mskip{-3mu}}"),
310 ("\\negthinspace", "\\!"),
311 ("\\negmedspace", "\\TextOrMath{\\kern{-.2222em}}{\\mskip{-4mu}}"),
312 ("\\negthickspace", "\\TextOrMath{\\kern{-.2777em}}{\\mskip{-5mu}}"),
313 ("\\enspace", "\\kern.5em "),
314 ("\\enskip", "\\hskip.5em\\relax"),
315 ("\\quad", "\\hskip1em\\relax"),
316 ("\\qquad", "\\hskip2em\\relax"),
317
318 ("\\newline", "\\\\\\relax"),
320
321 ("\\@hspace", "\\hskip #1\\relax"),
323 ("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"),
324
325 ("\\llap", "\\mathllap{\\textrm{#1}}"),
327 ("\\rlap", "\\mathrlap{\\textrm{#1}}"),
328 ("\\clap", "\\mathclap{\\textrm{#1}}"),
329
330 ("\\TeX", "\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}"),
332 ("\\LaTeX", "\\textrm{\\html@mathml{L\\kern-.36em\\raisebox{0.21em}{\\scriptstyle A}\\kern-.15em\\TeX}{LaTeX}}"),
333 ("\\KaTeX", "\\textrm{\\html@mathml{K\\kern-.17em\\raisebox{0.21em}{\\scriptstyle A}\\kern-.15em\\TeX}{KaTeX}}"),
334
335 ("\\imath", "\\html@mathml{\\@imath}{\u{0131}}"),
337 ("\\jmath", "\\html@mathml{\\@jmath}{\u{0237}}"),
338
339 ("\\minuso", "\\mathbin{\\html@mathml{{\\mathrlap{\\mathchoice{\\kern{0.145em}}{\\kern{0.145em}}{\\kern{0.1015em}}{\\kern{0.0725em}}\\circ}{-}}}{\\char`\u{29B5}}}"),
341 ("\\clap", "\\mathclap{\\textrm{#1}}"),
342
343 ("\\mathstrut", "\\vphantom{(}"),
345 ("\\underbar", "\\underline{\\text{#1}}"),
346
347 ("\\Bbbk", "\\Bbb{k}"),
349
350 ("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"),
352
353 ("\\boxed", "\\fbox{$\\displaystyle{#1}$}"),
355
356 ("\\colon", "\\nobreak\\mskip2mu\\mathpunct{}\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu\\relax"),
358
359 ("\\cdots", "\\@cdots"),
361 ("\\dotsb", "\\cdots"),
362 ("\\dotsm", "\\cdots"),
363 ("\\dotsi", "\\!\\cdots"),
364 ("\\dotsx", "\\ldots\\,"),
365 ("\\DOTSI", "\\relax"),
366 ("\\DOTSB", "\\relax"),
367 ("\\DOTSX", "\\relax"),
368
369 ("\\gvertneqq", "\\@gvertneqq"),
371 ("\\lvertneqq", "\\@lvertneqq"),
372 ("\\ngeqq", "\\@ngeqq"),
373 ("\\ngeqslant", "\\@ngeqslant"),
374 ("\\nleqq", "\\@nleqq"),
375 ("\\nleqslant", "\\@nleqslant"),
376 ("\\nshortmid", "\\@nshortmid"),
377 ("\\nshortparallel", "\\@nshortparallel"),
378 ("\\nsubseteqq", "\\@nsubseteqq"),
379 ("\\nsupseteqq", "\\@nsupseteqq"),
380 ("\\ulcorner", "\\@ulcorner"),
381 ("\\urcorner", "\\@urcorner"),
382 ("\\llcorner", "\\@llcorner"),
383 ("\\lrcorner", "\\@lrcorner"),
384 ("\\varsubsetneq", "\\@varsubsetneq"),
385 ("\\varsubsetneqq", "\\@varsubsetneqq"),
386 ("\\varsupsetneq", "\\@varsupsetneq"),
387 ("\\varsupsetneqq", "\\@varsupsetneqq"),
388
389 ("\\lBrace", "\\mathopen{\\{\\mkern-3.2mu[}"),
392 ("\\rBrace", "\\mathclose{]\\mkern-3.2mu\\}}"),
393 ("\\llbracket", "\\mathopen{[\\mkern-3.2mu[}"),
394 ("\\rrbracket", "\\mathclose{]\\mkern-3.2mu]}"),
395 ("\\copyright", "\\textcircled{c}"),
396 ("\\textregistered", "\\textcircled{\\scriptsize R}"),
397 ("\\textcopyright", "\\html@mathml{\\textcircled{c}}{\\char`©}"),
398
399 ("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),
402
403 ("\u{2258}", "\\mathrel{\u{E258}}"),
409 ("\u{2259}", "\\stackrel{\\tiny\\wedge}{=}"),
410 ("\u{225A}", "\\stackrel{\\tiny\\vee}{=}"),
411 ("\u{225B}", "\\stackrel{\\scriptsize\\star}{=}"),
412 ("\u{225D}", "\\stackrel{\\tiny\\mathrm{def}}{=}"),
413 ("\u{225E}", "\\mathrel{\u{E25E}}"),
414 ("\u{225F}", "\\stackrel{\\tiny?}{=}"),
415 ("\u{27C2}", "\\perp"),
417 ("\u{203C}", "\\mathclose{!\\mkern-0.8mu!}"),
418 ("\u{231C}", "\\ulcorner"),
419 ("\u{231D}", "\\urcorner"),
420 ("\u{231E}", "\\llcorner"),
421 ("\u{231F}", "\\lrcorner"),
422 ("\u{00A9}", "\\copyright"),
423 ("\u{00AE}", "\\textregistered"),
424 ("\u{2237}", "\\dblcolon"),
426 ("\u{2239}", "\\eqcolon"),
427 ("\u{2254}", "\\coloneqq"),
428 ("\u{2255}", "\\eqqcolon"),
429 ("\u{2A74}", "\\Coloneqq"),
430 ("\u{27E6}", "\\llbracket"),
432 ("\u{27E7}", "\\rrbracket"),
433 ("\u{2983}", "\\lBrace"),
434 ("\u{2984}", "\\rBrace"),
435 ("\u{29B5}", "\\minuso"),
437
438 ("\\vdots", "{\\varvdots\\rule{0pt}{15pt}}"),
440 ("\u{22ee}", "\\vdots"),
441
442 ("\\bmod", "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"),
444 ("\\pod", "\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),
445 ("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"),
446 ("\\mod", "\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),
447
448 ("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"),
450 ("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"),
451 ("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"),
452 ("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"),
453 ("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\mathrm{lim}}}"),
454 ("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\mathrm{lim}}}"),
455 ("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\mathrm{lim}}}"),
456 ("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\mathrm{lim}}}"),
457
458 ("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"),
460 ("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"),
461 ("\\plim", "\\DOTSB\\mathop{\\operatorname{plim}}\\limits"),
462
463 ("\\ordinarycolon", ":"),
465 ("\\vcentcolon", "\\mathrel{\\mathop\\ordinarycolon}"),
466 ("\\dblcolon", "\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char\"2237}}"),
467 ("\\coloneqq", "\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char\"2254}}"),
468 ("\\Coloneqq", "\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char\"2237\\char\"3d}}"),
469 ("\\coloneq", "\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char\"3a\\char\"2212}}"),
470 ("\\Coloneq", "\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char\"2237\\char\"2212}}"),
471 ("\\eqqcolon", "\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char\"2255}}"),
472 ("\\Eqqcolon", "\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char\"3d\\char\"2237}}"),
473 ("\\eqcolon", "\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char\"2239}}"),
474 ("\\Eqcolon", "\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char\"2212\\char\"2237}}"),
475 ("\\colonapprox", "\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char\"3a\\char\"2248}}"),
476 ("\\Colonapprox", "\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char\"2237\\char\"2248}}"),
477 ("\\colonsim", "\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char\"3a\\char\"223c}}"),
478 ("\\Colonsim", "\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char\"2237\\char\"223c}}"),
479
480 ("\\ratio", "\\vcentcolon"),
482 ("\\coloncolon", "\\dblcolon"),
483 ("\\colonequals", "\\coloneqq"),
484 ("\\coloncolonequals", "\\Coloneqq"),
485 ("\\equalscolon", "\\eqqcolon"),
486 ("\\equalscoloncolon", "\\Eqqcolon"),
487 ("\\colonminus", "\\coloneq"),
488 ("\\coloncolonminus", "\\Coloneq"),
489 ("\\minuscolon", "\\eqcolon"),
490 ("\\minuscoloncolon", "\\Eqcolon"),
491 ("\\coloncolonapprox", "\\Colonapprox"),
492 ("\\coloncolonsim", "\\Colonsim"),
493 ("\\simcolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),
494 ("\\simcoloncolon", "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"),
495 ("\\approxcolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),
496 ("\\approxcoloncolon", "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"),
497
498 ("\\bra", "\\mathinner{\\langle{#1}|}"),
500 ("\\ket", "\\mathinner{|{#1}\\rangle}"),
501 ("\\braket", "\\mathinner{\\langle{#1}\\rangle}"),
502 ("\\Braket", "\\bra@ket{\\left\\langle}{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"),
503 ("\\Bra", "\\left\\langle#1\\right|"),
504 ("\\Ket", "\\left|#1\\right\\rangle"),
505
506 ("\\darr", "\\downarrow"),
508 ("\\dArr", "\\Downarrow"),
509 ("\\Darr", "\\Downarrow"),
510 ("\\lang", "\\langle"),
511 ("\\rang", "\\rangle"),
512 ("\\uarr", "\\uparrow"),
513 ("\\uArr", "\\Uparrow"),
514 ("\\Uarr", "\\Uparrow"),
515 ("\\N", "\\mathbb{N}"),
516 ("\\R", "\\mathbb{R}"),
517 ("\\Z", "\\mathbb{Z}"),
518 ("\\alef", "\\aleph"),
519 ("\\alefsym", "\\aleph"),
520 ("\\Alpha", "\\mathrm{A}"),
521 ("\\Beta", "\\mathrm{B}"),
522 ("\\bull", "\\bullet"),
523 ("\\Chi", "\\mathrm{X}"),
524 ("\\clubs", "\\clubsuit"),
525 ("\\cnums", "\\mathbb{C}"),
526 ("\\Complex", "\\mathbb{C}"),
527 ("\\Dagger", "\\ddagger"),
528 ("\\diamonds", "\\diamondsuit"),
529 ("\\empty", "\\emptyset"),
530 ("\\Epsilon", "\\mathrm{E}"),
531 ("\\Eta", "\\mathrm{H}"),
532 ("\\exist", "\\exists"),
533 ("\\harr", "\\leftrightarrow"),
534 ("\\hArr", "\\Leftrightarrow"),
535 ("\\Harr", "\\Leftrightarrow"),
536 ("\\hearts", "\\heartsuit"),
537 ("\\image", "\\Im"),
538 ("\\infin", "\\infty"),
539 ("\\Iota", "\\mathrm{I}"),
540 ("\\isin", "\\in"),
541 ("\\Kappa", "\\mathrm{K}"),
542 ("\\larr", "\\leftarrow"),
543 ("\\lArr", "\\Leftarrow"),
544 ("\\Larr", "\\Leftarrow"),
545 ("\\lrarr", "\\leftrightarrow"),
546 ("\\lrArr", "\\Leftrightarrow"),
547 ("\\Lrarr", "\\Leftrightarrow"),
548 ("\\Mu", "\\mathrm{M}"),
549 ("\\natnums", "\\mathbb{N}"),
550 ("\\Nu", "\\mathrm{N}"),
551 ("\\Omicron", "\\mathrm{O}"),
552 ("\\plusmn", "\\pm"),
553 ("\\rarr", "\\rightarrow"),
554 ("\\rArr", "\\Rightarrow"),
555 ("\\Rarr", "\\Rightarrow"),
556 ("\\real", "\\Re"),
557 ("\\reals", "\\mathbb{R}"),
558 ("\\Reals", "\\mathbb{R}"),
559 ("\\Rho", "\\mathrm{P}"),
560 ("\\sdot", "\\cdot"),
561 ("\\sect", "\\S"),
562 ("\\spades", "\\spadesuit"),
563 ("\\sub", "\\subset"),
564 ("\\sube", "\\subseteq"),
565 ("\\supe", "\\supseteq"),
566 ("\\Tau", "\\mathrm{T}"),
567 ("\\thetasym", "\\vartheta"),
568 ("\\weierp", "\\wp"),
569 ("\\Zeta", "\\mathrm{Z}"),
570
571 ("\\blue", "\\textcolor{##6495ed}{#1}"),
573 ("\\orange", "\\textcolor{##ffa500}{#1}"),
574 ("\\pink", "\\textcolor{##ff00af}{#1}"),
575 ("\\red", "\\textcolor{##df0030}{#1}"),
576 ("\\green", "\\textcolor{##28ae7b}{#1}"),
577 ("\\gray", "\\textcolor{gray}{#1}"),
578 ("\\purple", "\\textcolor{##9d38bd}{#1}"),
579
580 ("\u{212C}", "\\mathscr{B}"),
582 ("\u{2130}", "\\mathscr{E}"),
583 ("\u{2131}", "\\mathscr{F}"),
584 ("\u{210B}", "\\mathscr{H}"),
585 ("\u{2110}", "\\mathscr{I}"),
586 ("\u{2112}", "\\mathscr{L}"),
587 ("\u{2133}", "\\mathscr{M}"),
588 ("\u{211B}", "\\mathscr{R}"),
589 ("\u{212D}", "\\mathfrak{C}"),
590 ("\u{210C}", "\\mathfrak{H}"),
591 ("\u{2128}", "\\mathfrak{Z}"),
592
593 ("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u{220C}}}"),
595
596 ("\\angln", "{\\angl n}"),
598
599 ("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"),
601 ("\\Set", "\\bra@set{\\left\\{\\:}{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"),
602
603 (
605 "\\tripledash",
606 "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}",
607 ),
608 ];
609
610 for &(name, expansion) in builtins {
611 self.macros.set(
612 name.to_string(),
613 MacroDefinition::Text(expansion.to_string()),
614 );
615 }
616
617 self.load_function_macros();
618 }
619
620 fn load_function_macros(&mut self) {
621 self.macros.set(
623 "\\noexpand".to_string(),
624 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
625 let mut tok = me.pop_token();
626 if me.is_expandable(&tok.text) {
627 tok.noexpand = true;
628 tok.treat_as_relax = true;
629 }
630 Ok(vec![tok])
631 }),
632 );
633
634 self.macros.set(
638 "\\@firstoftwo".to_string(),
639 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
640 let args = me.consume_args(2)?;
641 Ok(args.into_iter().next().unwrap())
642 }),
643 );
644
645 self.macros.set(
647 "\\@secondoftwo".to_string(),
648 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
649 let args = me.consume_args(2)?;
650 Ok(args.into_iter().nth(1).unwrap())
651 }),
652 );
653
654 self.macros.set(
656 "\\@ifnextchar".to_string(),
657 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
658 let args = me.consume_args(3)?;
659 me.consume_spaces();
660 let next = me.future().text.clone();
661 let char_arg = &args[0];
662 let char_text = char_arg.first().map_or("", |t| t.text.as_str());
664 if next == char_text {
665 Ok(args[1].clone())
666 } else {
667 Ok(args[2].clone())
668 }
669 }),
670 );
671
672 self.macros.set(
674 "\\@ifstar".to_string(),
675 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
676 let args = me.consume_args(2)?;
677 let next = me.future().text.clone();
678 if next == "*" {
679 me.pop_token();
680 Ok(args[0].clone())
681 } else {
682 Ok(args[1].clone())
683 }
684 }),
685 );
686
687 self.macros.set(
689 "\\TextOrMath".to_string(),
690 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
691 let args = me.consume_args(2)?;
692 if me.mode == Mode::Text {
693 Ok(args[0].clone())
694 } else {
695 Ok(args[1].clone())
696 }
697 }),
698 );
699
700 self.macros.set(
703 "\\dots".to_string(),
704 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
705 let _guard = me
706 .depth_budget
707 .enter()
708 .map_err(|_| ParseError::recursion_limit_exceeded())?;
709 me.expand_once(false)?;
710 let next = me.future().text.clone();
711 Ok(lex_string_to_stack_tokens(contextual_dots_for(&next)))
712 }),
713 );
714
715 self.macros.set(
718 "\\dotso".to_string(),
719 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
720 let next = me.future().text.clone();
721 let text = if dotso_space_after(&next) {
722 "\\ldots\\,"
723 } else {
724 "\\ldots"
725 };
726 Ok(lex_string_to_stack_tokens(text))
727 }),
728 );
729
730 self.macros.set(
731 "\\dotsc".to_string(),
732 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
733 let next = me.future().text.clone();
734 let text = if dotsc_space_after(&next) {
735 "\\ldots\\,"
736 } else {
737 "\\ldots"
738 };
739 Ok(lex_string_to_stack_tokens(text))
740 }),
741 );
742
743 self.macros.set(
744 "\\cdots".to_string(),
745 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
746 let next = me.future().text.clone();
747 let text = if dotso_space_after(&next) {
748 "\\@cdots\\,"
749 } else {
750 "\\@cdots"
751 };
752 Ok(lex_string_to_stack_tokens(text))
753 }),
754 );
755
756 self.macros.set(
760 "\\newcommand".to_string(),
761 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
762 handle_newcommand(me, false, true)
763 }),
764 );
765
766 self.macros.set(
768 "\\renewcommand".to_string(),
769 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
770 handle_newcommand(me, true, false)
771 }),
772 );
773
774 self.macros.set(
776 "\\providecommand".to_string(),
777 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
778 handle_newcommand(me, true, true)
779 }),
780 );
781
782 self.macros.set(
784 "\\char".to_string(),
785 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
786 let mut tok = me.pop_token();
787 let mut number: i64;
788 let base: Option<u32>;
789
790 if tok.text == "'" {
791 base = Some(8);
792 tok = me.pop_token();
793 } else if tok.text == "\"" {
794 base = Some(16);
795 tok = me.pop_token();
796 } else if tok.text == "`" {
797 tok = me.pop_token();
798 if tok.text.starts_with('\\') {
799 number = tok.text.chars().nth(1).map_or(0, |c| c as i64);
800 } else {
801 number = tok.text.chars().next().map_or(0, |c| c as i64);
802 }
803 let s = number.to_string();
805 let loc = tok.loc.clone();
806 let mut result = vec![Token::new("}", loc.start, loc.end)];
807 for ch in s.chars().rev() {
808 result.push(Token::new(ch.to_string(), loc.start, loc.end));
809 }
810 result.push(Token::new("{", loc.start, loc.end));
811 result.push(Token::new("\\@char", loc.start, loc.end));
812 return Ok(result);
813 } else {
814 base = Some(10);
815 }
816
817 if let Some(b) = base {
818 number = i64::from_str_radix(&tok.text, b).unwrap_or(0);
819 loop {
820 let next = me.future().text.clone();
821 if let Ok(d) = i64::from_str_radix(&next, b) {
822 me.pop_token();
823 number = number * (b as i64) + d;
824 } else {
825 break;
826 }
827 }
828 } else {
829 number = 0;
830 }
831
832 let s = number.to_string();
833 let loc = tok.loc.clone();
834 let mut result = vec![Token::new("}", loc.start, loc.end)];
835 for ch in s.chars().rev() {
836 result.push(Token::new(ch.to_string(), loc.start, loc.end));
837 }
838 result.push(Token::new("{", loc.start, loc.end));
839 result.push(Token::new("\\@char", loc.start, loc.end));
840 Ok(result)
841 }),
842 );
843
844 self.macros.set(
846 "\\operatorname".to_string(),
847 MacroDefinition::Text("\\@ifstar\\operatornamewithlimits\\operatorname@".to_string()),
848 );
849
850 self.macros.set(
852 "\\message".to_string(),
853 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
854 let _args = me.consume_args(1)?;
855 Ok(vec![])
856 }),
857 );
858
859 self.macros.set(
861 "\\errmessage".to_string(),
862 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
863 let _args = me.consume_args(1)?;
864 Ok(vec![])
865 }),
866 );
867
868 for name in &["\\htmlClass", "\\htmlData", "\\htmlId"] {
872 let name = (*name).to_string();
873 self.macros.set(
874 name.clone(),
875 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
876 let args = me.consume_args(2)?;
877 let content = args[1].iter().cloned().rev().collect::<Vec<_>>();
878 Ok(content)
879 }),
880 );
881 }
882
883 self.macros.set(
885 "\\bra@ket".to_string(),
886 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
887 let args = me.consume_args(4)?;
888 let left = args[0].clone();
889 let middle = args[1].clone();
890 let middle_double = args[2].clone();
891 let right = args[3].clone();
892
893 let content = me.consume_args(1)?;
894 let content = content.into_iter().next().unwrap();
895
896 let logical: Vec<Token> = content.into_iter().rev().collect();
899 let mut new_logical: Vec<Token> = Vec::new();
900 let mut depth: i32 = 0;
901 let mut i = 0;
902 while i < logical.len() {
903 let t = &logical[i];
904 if t.text == "{" {
905 depth += 1;
906 new_logical.push(t.clone());
907 } else if t.text == "}" {
908 depth -= 1;
909 new_logical.push(t.clone());
910 } else if depth == 0 && t.text == "|" {
911 if !middle_double.is_empty()
913 && i + 1 < logical.len()
914 && logical[i + 1].text == "|"
915 {
916 new_logical.extend(middle_double.iter().rev().cloned());
918 i += 2;
919 continue;
920 }
921 new_logical.extend(middle.iter().rev().cloned());
923 } else {
924 new_logical.push(t.clone());
925 }
926 i += 1;
927 }
928
929 let content_rev: Vec<Token> = new_logical.into_iter().rev().collect();
931
932 let mut to_expand = Vec::new();
934 to_expand.extend(right);
935 to_expand.extend(content_rev);
936 to_expand.extend(left);
937
938 me.begin_group();
939 let expanded = me.expand_tokens(to_expand);
940 me.end_group();
941 let expanded = expanded?;
942
943 Ok(expanded)
944 }),
945 );
946
947 self.macros.set(
950 "\\bra@set".to_string(),
951 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
952 let args = me.consume_args(4)?;
953 let left = args[0].clone();
954 let middle = args[1].clone();
955 let middle_double = args[2].clone();
956 let right = args[3].clone();
957
958 let content = me.consume_args(1)?;
959 let mut content = content.into_iter().next().unwrap();
960
961 let mut depth: i32 = 0;
964 let mut _first_pipe_idx: Option<usize> = None;
965 for i in (0..content.len()).rev() {
967 let t = &content[i];
968 if t.text == "{" {
969 depth += 1;
970 } else if t.text == "}" {
971 depth -= 1;
972 } else if depth == 0 && t.text == "|" {
973 if !middle_double.is_empty() && i > 0 && content[i - 1].text == "|" {
975 _first_pipe_idx = Some(i);
976 content.remove(i);
978 content.remove(i - 1);
979 let insert_at = if i >= 2 { i - 1 } else { 0 };
980 for (j, tok) in middle_double.iter().enumerate() {
981 content.insert(insert_at + j, tok.clone());
982 }
983 break;
984 }
985 _first_pipe_idx = Some(i);
986 content.remove(i);
987 for (j, tok) in middle.iter().enumerate() {
988 content.insert(i + j, tok.clone());
989 }
990 break;
991 }
992 }
993
994 let mut to_expand = Vec::new();
996 to_expand.extend(right);
997 to_expand.extend(content);
998 to_expand.extend(left);
999
1000 me.begin_group();
1001 let expanded = me.expand_tokens(to_expand);
1002 me.end_group();
1003 let expanded = expanded?;
1004
1005 Ok(expanded)
1006 }),
1007 );
1008
1009 self.macros.set(
1011 "\\ce".to_string(),
1012 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
1013 let args = me.consume_args(1)?;
1014 let s = crate::mhchem::mhchem_arg_tokens_to_string(&args[0]);
1015 let tex =
1016 crate::mhchem::chem_parse_str_with_budget(&s, "ce", me.depth_budget.clone())
1017 .map_err(|e| ParseError::msg(format!("\\ce: {e}")))?;
1018 Ok(lex_string_to_stack_tokens(&tex))
1019 }),
1020 );
1021 self.macros.set(
1022 "\\pu".to_string(),
1023 MacroDefinition::Function(|me: &mut MacroExpander| -> ParseResult<Vec<Token>> {
1024 let args = me.consume_args(1)?;
1025 let s = crate::mhchem::mhchem_arg_tokens_to_string(&args[0]);
1026 let tex =
1027 crate::mhchem::chem_parse_str_with_budget(&s, "pu", me.depth_budget.clone())
1028 .map_err(|e| ParseError::msg(format!("\\pu: {e}")))?;
1029 Ok(lex_string_to_stack_tokens(&tex))
1030 }),
1031 );
1032 }
1033
1034 pub fn set_macro(&mut self, name: String, def: MacroDefinition) {
1035 self.macros.set(name, def);
1036 }
1037
1038 pub fn set_macro_global(&mut self, name: String, def: MacroDefinition) {
1039 self.macros.set_global(name, def);
1040 }
1041
1042 pub fn set_text_macro(&mut self, name: &str, text: &str) {
1043 self.macros
1044 .set(name.to_string(), MacroDefinition::Text(text.to_string()));
1045 }
1046
1047 pub fn get_macro(&self, name: &str) -> Option<&MacroDefinition> {
1048 self.macros.get(name)
1049 }
1050
1051 pub fn expand_tokens(&mut self, tokens: Vec<Token>) -> ParseResult<Vec<Token>> {
1053 let nested = self.expand_tokens_depth > 0;
1054 let _guard = if nested {
1055 Some(
1056 self.depth_budget
1057 .enter()
1058 .map_err(|_| ParseError::recursion_limit_exceeded())?,
1059 )
1060 } else {
1061 None
1062 };
1063
1064 self.expand_tokens_depth += 1;
1065 let saved_stack = std::mem::take(&mut self.stack);
1066 self.stack = tokens;
1067
1068 let result = (|| {
1069 let mut result = Vec::new();
1070 loop {
1071 if self.stack.is_empty() {
1072 break;
1073 }
1074 let expanded = self.expand_once(false)?;
1075 if !expanded {
1076 if let Some(tok) = self.stack.pop() {
1077 if tok.is_eof() {
1078 break;
1079 }
1080 result.push(tok);
1081 }
1082 }
1083 }
1084 result.reverse();
1085 Ok(result)
1086 })();
1087
1088 self.stack = saved_stack;
1089 self.expand_tokens_depth -= 1;
1090 result
1091 }
1092
1093 pub fn switch_mode(&mut self, new_mode: Mode) {
1094 self.mode = new_mode;
1095 }
1096
1097 pub fn begin_group(&mut self) {
1098 self.macros.begin_group();
1099 }
1100
1101 pub fn end_group(&mut self) {
1102 self.macros.end_group();
1103 }
1104
1105 pub fn end_groups(&mut self) {
1106 self.macros.end_groups();
1107 }
1108
1109 pub fn future(&mut self) -> &Token {
1111 if self.stack.is_empty() {
1112 let tok = self.lexer.lex();
1113 self.stack.push(tok);
1114 }
1115 self.stack.last().unwrap()
1116 }
1117
1118 pub fn pop_token(&mut self) -> Token {
1120 self.future();
1121 self.stack.pop().unwrap()
1122 }
1123
1124 pub fn set_top_text(&mut self, text: String) {
1126 self.future();
1127 if let Some(tok) = self.stack.last_mut() {
1128 tok.text = text;
1129 }
1130 }
1131
1132 pub fn push_token(&mut self, token: Token) {
1134 self.stack.push(token);
1135 }
1136
1137 pub fn push_tokens(&mut self, tokens: Vec<Token>) {
1139 self.stack.extend(tokens);
1140 }
1141
1142 pub fn consume_spaces(&mut self) {
1144 loop {
1145 let is_space = self.future().text == " ";
1146 if is_space {
1147 self.stack.pop();
1148 } else {
1149 break;
1150 }
1151 }
1152 }
1153
1154 fn expand_once(&mut self, expandable_only: bool) -> ParseResult<bool> {
1157 let top_token = self.pop_token();
1158 let name = &top_token.text;
1159
1160 if top_token.noexpand {
1161 self.push_token(top_token);
1162 return Ok(false);
1163 }
1164
1165 if let Some(MacroDefinition::Function(handler)) = self.macros.get(name).cloned() {
1167 self.count_expansion(1)?;
1168 let tokens = handler(self)?;
1169 self.stack.extend(tokens);
1170 return Ok(true);
1171 }
1172
1173 let expansion = self.get_expansion(name);
1174 match expansion {
1175 None => {
1176 if expandable_only && name.starts_with('\\') && !self.is_defined(name) {
1177 return Err(ParseError::new(
1178 format!("Undefined control sequence: {}", name),
1179 Some(&top_token),
1180 ));
1181 }
1182 self.push_token(top_token);
1183 Ok(false)
1184 }
1185 Some(exp) if expandable_only && exp.unexpandable => {
1186 self.push_token(top_token);
1187 Ok(false)
1188 }
1189 Some(exp) => {
1190 self.count_expansion(1)?;
1191 let mut tokens = exp.tokens;
1192 if exp.num_args > 0 {
1193 let args = self.consume_args(exp.num_args)?;
1194 tokens = self.substitute_args(tokens, &args);
1195 }
1196 self.stack.extend(tokens);
1197 Ok(true)
1198 }
1199 }
1200 }
1201
1202 fn substitute_args(&self, mut tokens: Vec<Token>, args: &[Vec<Token>]) -> Vec<Token> {
1203 let mut i = tokens.len();
1204 while i > 0 {
1205 i -= 1;
1206 if tokens[i].text == "#" && i > 0 {
1207 let next = &tokens[i - 1];
1208 if next.text == "#" {
1209 tokens.remove(i);
1210 i -= 1;
1211 } else if let Ok(n) = next.text.parse::<usize>() {
1212 if n >= 1 && n <= args.len() {
1213 tokens.remove(i);
1214 tokens.remove(i - 1);
1215 let arg_tokens = &args[n - 1];
1216 for (j, t) in arg_tokens.iter().enumerate() {
1217 tokens.insert(i - 1 + j, t.clone());
1218 }
1219 i = i.saturating_sub(1);
1220 }
1221 }
1222 }
1223 }
1224 tokens
1225 }
1226
1227 fn get_expansion(&self, name: &str) -> Option<MacroExpansion> {
1228 let def = self.macros.get(name)?;
1229
1230 if name.len() == 1 {
1231 let ch = name.chars().next().unwrap();
1232 let catcode = self.lexer_catcode(ch);
1233 if catcode != 0 && catcode != 13 {
1234 return None;
1235 }
1236 }
1237
1238 match def {
1239 MacroDefinition::Text(text) => {
1240 let mut num_args = 0;
1241 let stripped = text.replace("##", "");
1242 while stripped.contains(&format!("#{}", num_args + 1)) {
1243 num_args += 1;
1244 }
1245 let mut body_lexer = Lexer::new(text);
1246 let mut tokens = Vec::new();
1247 loop {
1248 let tok = body_lexer.lex();
1249 if tok.is_eof() {
1250 break;
1251 }
1252 tokens.push(tok);
1253 }
1254 tokens.reverse();
1255 Some(MacroExpansion {
1256 tokens,
1257 num_args,
1258 unexpandable: false,
1259 })
1260 }
1261 MacroDefinition::Tokens { tokens, num_args } => Some(MacroExpansion {
1262 tokens: tokens.clone(),
1263 num_args: *num_args,
1264 unexpandable: false,
1265 }),
1266 MacroDefinition::Function(_) => {
1267 Some(MacroExpansion {
1269 tokens: vec![],
1270 num_args: 0,
1271 unexpandable: false,
1272 })
1273 }
1274 }
1275 }
1276
1277 fn lexer_catcode(&self, ch: char) -> u8 {
1278 self.lexer.get_catcode(ch)
1279 }
1280
1281 fn count_expansion(&mut self, amount: usize) -> ParseResult<()> {
1282 self.expansion_count += amount;
1283 if self.expansion_count > self.max_expand {
1284 Err(ParseError::msg(
1285 "Too many expansions: infinite loop or need to increase maxExpand setting",
1286 ))
1287 } else {
1288 Ok(())
1289 }
1290 }
1291
1292 pub fn expand_next_token(&mut self) -> ParseResult<Token> {
1294 loop {
1295 let expanded = self.expand_once(false)?;
1296 if !expanded {
1297 let mut token = self.stack.pop().unwrap();
1298 if token.treat_as_relax {
1299 token.text = "\\relax".to_string();
1300 }
1301 return Ok(token);
1302 }
1303 }
1304 }
1305
1306 pub fn consume_arg(&mut self, delims: Option<&[&str]>) -> ParseResult<ConsumedArg> {
1308 let is_delimited = delims.is_some_and(|d| !d.is_empty());
1309 if !is_delimited {
1310 self.consume_spaces();
1311 }
1312
1313 let start = self.future().clone();
1314 let mut tokens = Vec::new();
1315 let mut depth: i32 = 0;
1316 let mut end_tok;
1317
1318 loop {
1319 let tok = self.pop_token();
1320 end_tok = tok.clone();
1321 tokens.push(tok.clone());
1322
1323 if tok.text == "{" {
1324 depth += 1;
1325 } else if tok.text == "}" {
1326 depth -= 1;
1327 if depth == -1 {
1328 return Err(ParseError::new("Extra }", Some(&tok)));
1329 }
1330 } else if tok.is_eof() {
1331 return Err(ParseError::new(
1332 "Unexpected end of input in a macro argument",
1333 Some(&tok),
1334 ));
1335 }
1336
1337 if depth == 0 && !is_delimited {
1338 break;
1339 }
1340
1341 if let Some(delims) = delims {
1342 if is_delimited && depth == 0 {
1343 if let Some(last) = delims.last() {
1344 if tok.text == *last {
1345 tokens.pop();
1346 break;
1347 }
1348 }
1349 }
1350 }
1351 }
1352
1353 if start.text == "{" && tokens.last().is_some_and(|t| t.text == "}") {
1354 tokens.pop();
1355 tokens.remove(0);
1356 }
1357
1358 tokens.reverse();
1359
1360 Ok(ConsumedArg {
1361 tokens,
1362 start,
1363 end: end_tok,
1364 })
1365 }
1366
1367 fn consume_args(&mut self, num_args: usize) -> ParseResult<Vec<Vec<Token>>> {
1369 let mut args = Vec::with_capacity(num_args);
1370 for _ in 0..num_args {
1371 let arg = self.consume_arg(None)?;
1372 args.push(arg.tokens);
1373 }
1374 Ok(args)
1375 }
1376
1377 pub fn scan_argument(&mut self, is_optional: bool) -> ParseResult<Option<Token>> {
1380 if is_optional {
1381 self.consume_spaces();
1382 if self.future().text != "[" {
1383 return Ok(None);
1384 }
1385 let start = self.pop_token();
1386 let arg = self.consume_arg(Some(&["]"]))?;
1387 let end = &arg.end;
1388 let end_loc = end.loc.clone();
1389
1390 self.push_token(Token::new("EOF", end_loc.start, end_loc.end));
1391 self.push_tokens(arg.tokens);
1392
1393 let result = Token {
1394 text: String::new(),
1395 loc: SourceLocation::range(&start.loc, &end_loc),
1396 noexpand: false,
1397 treat_as_relax: false,
1398 };
1399 Ok(Some(result))
1400 } else {
1401 let arg = self.consume_arg(None)?;
1402 let end_loc = arg.end.loc.clone();
1403
1404 self.push_token(Token::new("EOF", end_loc.start, end_loc.end));
1405 self.push_tokens(arg.tokens);
1406
1407 let result = Token {
1408 text: String::new(),
1409 loc: SourceLocation::range(&arg.start.loc, &end_loc),
1410 noexpand: false,
1411 treat_as_relax: false,
1412 };
1413 Ok(Some(result))
1414 }
1415 }
1416
1417 pub fn is_defined(&self, name: &str) -> bool {
1419 self.macros.has(name)
1420 || FUNCTIONS.contains_key(name)
1421 || is_known_symbol(name)
1422 || IMPLICIT_COMMANDS.contains(&name)
1423 }
1424
1425 pub fn is_expandable(&self, name: &str) -> bool {
1427 if let Some(_def) = self.macros.get(name) {
1428 return true;
1429 }
1430 if let Some(func) = FUNCTIONS.get(name) {
1431 return !func.primitive;
1432 }
1433 false
1434 }
1435}
1436
1437pub struct ConsumedArg {
1438 pub tokens: Vec<Token>,
1439 pub start: Token,
1440 pub end: Token,
1441}
1442
1443fn handle_newcommand(
1444 me: &mut MacroExpander,
1445 exists_ok: bool,
1446 nonexists_ok: bool,
1447) -> ParseResult<Vec<Token>> {
1448 let name_arg = me.consume_arg(None)?;
1449 let name = name_arg
1451 .tokens
1452 .last()
1453 .map_or_else(String::new, |t| t.text.clone());
1454
1455 let exists = me.is_defined(&name);
1456 if exists && !exists_ok {
1457 return Err(ParseError::msg(format!(
1458 "\\newcommand{{{}}} attempting to redefine {}; use \\renewcommand",
1459 name, name
1460 )));
1461 }
1462 if !exists && !nonexists_ok {
1463 return Err(ParseError::msg(format!(
1464 "\\renewcommand{{{}}} when command {} does not yet exist; use \\newcommand",
1465 name, name
1466 )));
1467 }
1468
1469 me.consume_spaces();
1470 let mut num_args = 0usize;
1471 if me.future().text == "[" {
1472 me.pop_token();
1473 let narg_tok = me.pop_token();
1474 num_args = narg_tok.text.parse().unwrap_or(0);
1475 let close = me.pop_token();
1476 if close.text != "]" {
1477 return Err(ParseError::msg("Expected ] in \\newcommand"));
1478 }
1479 }
1480
1481 let body_arg = me.consume_arg(None)?;
1482 let tokens = body_arg.tokens;
1483
1484 me.set_macro(name, MacroDefinition::Tokens { tokens, num_args });
1485 Ok(vec![])
1486}
1487
1488fn is_known_symbol(name: &str) -> bool {
1489 use ratex_font::symbols;
1490 symbols::get_symbol(name, symbols::Mode::Math).is_some()
1491 || symbols::get_symbol(name, symbols::Mode::Text).is_some()
1492}