1use core::panic;
5
6use crate::event::{
7 ArrayColumn as AC, ColorChange as CC, ColorTarget as CT, ColumnAlignment, Content as C,
8 DelimiterSize, DelimiterType, Dimension, DimensionUnit, EnvironmentFlow, Event as E, Font,
9 Grouping as G, GroupingKind, Line, MatrixType, RelationContent, ScriptPosition as SP,
10 ScriptType as ST, StateChange as SC, Style as S, Visual as V,
11};
12
13use super::{
14 lex,
15 tables::{
16 char_delimiter_map, control_sequence_delimiter_map, is_binary, is_relation, token_to_delim,
17 },
18 AlignmentCount, Argument, CharToken, ErrorKind, InnerParser, InnerResult, Instruction as I,
19 Token,
20};
21
22impl<'b, 'store> InnerParser<'b, 'store> {
23 pub(super) fn handle_char_token(&mut self, token: CharToken<'store>) -> InnerResult<()> {
30 let instruction = I::Event(match token.into() {
31 '\\' => panic!("(internal error: please report) the `\\` character should never be observed as a token"),
32 '%' => panic!("(internal error: please report) the `%` character should never be observed as a token"),
33 '_' => {
34 if self.state.handling_argument {
35 return Err(ErrorKind::ScriptAsArgument)
36 }
37 self.buffer.extend([
38 I::Event(E::Begin(G::Normal)),
39 ]);
40 self.content = token.as_str();
41 E::End
42 }
43 '^' => {
44 if self.state.handling_argument {
45 return Err(ErrorKind::ScriptAsArgument)
46 }
47 self.buffer.extend([
48 I::Event(E::Begin(G::Normal)),
49 ]);
50 self.content = token.as_str();
51 E::End
52 }
53 '$' => return Err(ErrorKind::MathShift),
54 '#' => return Err(ErrorKind::HashSign),
55 '&' if self
56 .state
57 .allowed_alignment_count
58 .as_deref()
59 .is_some_and(AlignmentCount::can_increment) && !self.state.handling_argument => {
60 self
61 .state
62 .allowed_alignment_count
63 .as_mut()
64 .expect("we have checked that `allowed_alignment_count` is Some")
65 .increment();
66 E::EnvironmentFlow(EnvironmentFlow::Alignment)
67 },
68 '&' => return Err(ErrorKind::Alignment),
69 '{' => {
70 let str = &mut self.content;
71 let group = lex::group_content(str, GroupingKind::Normal)?;
72 self.buffer.extend([
73 I::Event(E::Begin(G::Normal)),
74 I::SubGroup { content: group, allowed_alignment_count: None },
75 I::Event(E::End)
76 ]);
77 return Ok(())
78 },
79 '}' => {
80 return Err(ErrorKind::UnbalancedGroup(None))
81 },
82
83 '~' => {
84 E::Content(C::Text(" "))
85 },
86
87 '0'..='9' => {
88 let content = token.as_str();
89 let len = if self.state.handling_argument {
90 1
91 } else {
92 let mut len = content
93 .chars()
94 .skip(1)
95 .take_while(|&c| matches!(c, '.' | ',' | '0'..='9'))
96 .count()
97 + 1;
98 if matches!(content.as_bytes()[len - 1], b'.' | b',') {
99 len -= 1;
100 }
101 len
102 };
103 let (number, rest) = content.split_at(len);
104 self.content = rest;
105 self.buffer
106 .push(I::Event(E::Content(C::Number(number))));
107 return Ok(())
108 }
109 '.' | ',' | ';' => E::Content(C::Punctuation(token.into())),
111 '\'' => ordinary('′'),
112 '-' => binary('−'),
113 '*' => binary('∗'),
114 c if is_binary(c) => binary(c),
115 c if is_relation(c) => relation(c),
116 c if char_delimiter_map(c).is_some() => {
117 let (content, ty) = char_delimiter_map(c).unwrap();
118 if ty == DelimiterType::Fence {
119 ordinary(content)
120 } else {
121 E::Content(C::Delimiter {
122 content,
123 size: None,
124 ty,
125 })
126 }
127 }
128 c => ordinary(c),
129 });
130 self.buffer.push(instruction);
131 Ok(())
132 }
133
134 pub(super) fn handle_primitive(&mut self, control_sequence: &'store str) -> InnerResult<()> {
136 let event = match control_sequence {
137 "arccos" | "cos" | "csc" | "exp" | "ker" | "sinh" | "arcsin" | "cosh" | "deg"
138 | "lg" | "ln" | "arctan" | "cot" | "det" | "hom" | "log" | "sec" | "tan" | "arg"
139 | "coth" | "dim" | "sin" | "tanh" | "sgn" => E::Content(C::Function(control_sequence)),
140 "lim" | "Pr" | "sup" | "max" | "inf" | "gcd" | "min" => {
141 self.state.allow_script_modifiers = true;
142 self.state.script_position = SP::Movable;
143 E::Content(C::Function(control_sequence))
144 }
145 "liminf" => {
146 self.state.allow_script_modifiers = true;
147 self.state.script_position = SP::Movable;
148 E::Content(C::Function("lim inf"))
149 }
150 "limsup" => {
151 self.state.allow_script_modifiers = true;
152 self.state.script_position = SP::Movable;
153 E::Content(C::Function("lim sup"))
154 }
155
156 "operatorname" => {
157 self.state.allow_script_modifiers = true;
158 let argument = lex::argument(&mut self.content)?;
159 match argument {
160 Argument::Token(Token::ControlSequence(_)) => {
161 return Err(ErrorKind::ControlSequenceAsArgument)
162 }
163 Argument::Token(Token::Character(char_)) => {
164 E::Content(C::Function(char_.as_str()))
165 }
166 Argument::Group(content) => E::Content(C::Function(content)),
167 }
168 }
169 "bmod" => E::Content(C::Function("mod")),
170 "pmod" => {
171 let argument = lex::argument(&mut self.content)?;
172 self.buffer.extend([
173 I::Event(E::Space {
174 width: Some(Dimension::new(1., DimensionUnit::Em)),
175 height: None,
176 depth: None,
177 }),
178 I::Event(E::Begin(G::Normal)),
179 I::Event(E::Content(C::Delimiter {
180 content: '(',
181 size: None,
182 ty: DelimiterType::Open,
183 })),
184 I::Event(E::Content(C::Function("mod"))),
185 ]);
186 self.handle_argument(argument)?;
187 self.buffer.extend([
188 I::Event(E::End),
189 I::Event(E::Content(C::Delimiter {
190 content: ')',
191 size: None,
192 ty: DelimiterType::Close,
193 })),
194 ]);
195 return Ok(());
196 }
197
198 "mathord" => return self.atom_group(AtomClass::Ord),
206 "mathop" => {
207 self.state.allow_script_modifiers = true;
208 self.state.script_position = SP::Movable;
209 return self.atom_group(AtomClass::Op);
210 }
211 "mathbin" => return self.atom_group(AtomClass::Bin),
212 "mathrel" => return self.atom_group(AtomClass::Rel),
213 "mathopen" => return self.atom_group(AtomClass::Open),
214 "mathclose" => return self.atom_group(AtomClass::Close),
215 "mathpunct" => return self.atom_group(AtomClass::Punct),
216 "mathinner" => return self.atom_group(AtomClass::Inner),
217
218 "alpha" => ordinary('α'),
223 "beta" => ordinary('β'),
224 "gamma" => ordinary('γ'),
225 "delta" => ordinary('δ'),
226 "epsilon" => ordinary('ϵ'),
227 "zeta" => ordinary('ζ'),
228 "eta" => ordinary('η'),
229 "theta" => ordinary('θ'),
230 "iota" => ordinary('ι'),
231 "kappa" => ordinary('κ'),
232 "lambda" => ordinary('λ'),
233 "mu" => ordinary('µ'),
234 "nu" => ordinary('ν'),
235 "xi" => ordinary('ξ'),
236 "pi" => ordinary('π'),
237 "rho" => ordinary('ρ'),
238 "sigma" => ordinary('σ'),
239 "tau" => ordinary('τ'),
240 "upsilon" => ordinary('υ'),
241 "phi" => ordinary('ϕ'),
242 "chi" => ordinary('χ'),
243 "psi" => ordinary('ψ'),
244 "omega" => ordinary('ω'),
245 "omicron" => ordinary('ο'),
246 "Alpha" => ordinary('Α'),
248 "Beta" => ordinary('Β'),
249 "Gamma" => ordinary('Γ'),
250 "Delta" => ordinary('Δ'),
251 "Epsilon" => ordinary('Ε'),
252 "Zeta" => ordinary('Ζ'),
253 "Eta" => ordinary('Η'),
254 "Theta" => ordinary('Θ'),
255 "Iota" => ordinary('Ι'),
256 "Kappa" => ordinary('Κ'),
257 "Lambda" => ordinary('Λ'),
258 "Mu" => ordinary('Μ'),
259 "Nu" => ordinary('Ν'),
260 "Xi" => ordinary('Ξ'),
261 "Pi" => ordinary('Π'),
262 "Rho" => ordinary('Ρ'),
263 "Sigma" => ordinary('Σ'),
264 "Tau" => ordinary('Τ'),
265 "Upsilon" => ordinary('Υ'),
266 "Phi" => ordinary('Φ'),
267 "Chi" => ordinary('Χ'),
268 "Psi" => ordinary('Ψ'),
269 "Omega" => ordinary('Ω'),
270 "Omicron" => ordinary('Ο'),
271 "varepsilon" => ordinary('ε'),
273 "vartheta" => ordinary('ϑ'),
274 "varkappa" => ordinary('ϰ'),
275 "varrho" => ordinary('ϱ'),
276 "varsigma" => ordinary('ς'),
277 "varpi" => ordinary('ϖ'),
278 "varphi" => ordinary('φ'),
279 "varGamma" => ordinary('𝛤'),
281 "varDelta" => ordinary('𝛥'),
282 "varTheta" => ordinary('𝛩'),
283 "varLambda" => ordinary('𝛬'),
284 "varXi" => ordinary('𝛯'),
285 "varPi" => ordinary('𝛱'),
286 "varSigma" => ordinary('𝛴'),
287 "varUpsilon" => ordinary('𝛶'),
288 "varPhi" => ordinary('𝛷'),
289 "varPsi" => ordinary('𝛹'),
290 "varOmega" => ordinary('𝛺'),
291
292 "aleph" => ordinary('ℵ'),
294 "beth" => ordinary('ℶ'),
295 "gimel" => ordinary('ℷ'),
296 "daleth" => ordinary('ℸ'),
297 "digamma" => ordinary('ϝ'),
299 "eth" => ordinary('ð'),
300 "ell" => ordinary('ℓ'),
301 "nabla" => ordinary('∇'),
302 "partial" => ordinary('∂'),
303 "Finv" => ordinary('Ⅎ'),
304 "Game" => ordinary('ℷ'),
305 "hbar" | "hslash" => ordinary('ℏ'),
306 "imath" => ordinary('ı'),
307 "jmath" => ordinary('ȷ'),
308 "Im" => ordinary('ℑ'),
309 "Re" => ordinary('ℜ'),
310 "wp" => ordinary('℘'),
311 "Bbbk" => ordinary('𝕜'),
312 "Angstrom" => ordinary('Å'),
313 "backepsilon" => ordinary('϶'),
314
315 "dots" => {
319 if self.content.trim_start().starts_with(['.', ',']) {
320 ordinary('…')
321 } else {
322 ordinary('⋯')
323 }
324 }
325 "ldots" | "dotso" | "dotsc" => ordinary('…'),
326 "cdots" | "dotsi" | "dotsm" | "dotsb" | "idotsin" => ordinary('⋯'),
327 "ddots" => ordinary('⋱'),
328 "iddots" => ordinary('⋰'),
329 "vdots" => ordinary('⋮'),
330 "mathellipsis" => ordinary('…'),
331 "infty" => ordinary('∞'),
332 "checkmark" => ordinary('✓'),
333 "ballotx" => ordinary('✗'),
334 "dagger" | "dag" => ordinary('†'),
335 "ddagger" | "ddag" => ordinary('‡'),
336 "angle" => ordinary('∠'),
337 "measuredangle" => ordinary('∡'),
338 "lq" => ordinary('‘'),
339 "Box" => ordinary('□'),
340 "sphericalangle" => ordinary('∢'),
341 "square" => ordinary('□'),
342 "top" => ordinary('⊤'),
343 "rq" => ordinary('′'),
344 "blacksquare" => ordinary('■'),
345 "bot" => ordinary('⊥'),
346 "triangledown" => ordinary('▽'),
347 "Bot" => ordinary('⫫'),
348 "triangleleft" => ordinary('◃'),
349 "triangleright" => ordinary('▹'),
350 "cent" => ordinary('¢'),
351 "colon" | "ratio" | "vcentcolon" => ordinary(':'),
352 "bigtriangledown" => ordinary('▽'),
353 "pounds" | "mathsterling" => ordinary('£'),
354 "bigtriangleup" => ordinary('△'),
355 "blacktriangle" => ordinary('▲'),
356 "blacktriangledown" => ordinary('▼'),
357 "yen" => ordinary('¥'),
358 "blacktriangleleft" => ordinary('◀'),
359 "euro" => ordinary('€'),
360 "blacktriangleright" => ordinary('▶'),
361 "Diamond" => ordinary('◊'),
362 "degree" => ordinary('°'),
363 "lozenge" => ordinary('◊'),
364 "blacklozenge" => ordinary('⧫'),
365 "mho" => ordinary('℧'),
366 "bigstar" => ordinary('★'),
367 "diagdown" => ordinary('╲'),
368 "maltese" => ordinary('✠'),
369 "diagup" => ordinary('╱'),
370 "P" => ordinary('¶'),
371 "clubsuit" => ordinary('♣'),
372 "varclubsuit" => ordinary('♧'),
373 "S" => ordinary('§'),
374 "diamondsuit" => ordinary('♢'),
375 "vardiamondsuit" => ordinary('♦'),
376 "copyright" => ordinary('©'),
377 "heartsuit" => ordinary('♡'),
378 "varheartsuit" => ordinary('♥'),
379 "circledR" => ordinary('®'),
380 "spadesuit" => ordinary('♠'),
381 "varspadesuit" => ordinary('♤'),
382 "circledS" => ordinary('Ⓢ'),
383 "female" => ordinary('♀'),
384 "male" => ordinary('♂'),
385 "astrosun" => ordinary('☉'),
386 "sun" => ordinary('☼'),
387 "leftmoon" => ordinary('☾'),
388 "rightmoon" => ordinary('☽'),
389 "smiley" => ordinary('☺'),
390 "Earth" => ordinary('⊕'),
391 "flat" => ordinary('♭'),
392 "standardstate" => ordinary('⦵'),
393 "natural" => ordinary('♮'),
394 "sharp" => ordinary('♯'),
395 "permil" => ordinary('‰'),
396 "QED" => ordinary('∎'),
397 "lightning" => ordinary('↯'),
398 "diameter" => ordinary('⌀'),
399 "leftouterjoin" => ordinary('⟕'),
400 "rightouterjoin" => ordinary('⟖'),
401 "concavediamond" => ordinary('⟡'),
402 "concavediamondtickleft" => ordinary('⟢'),
403 "concavediamondtickright" => ordinary('⟣'),
404 "fullouterjoin" => ordinary('⟗'),
405 "triangle" | "vartriangle" => ordinary('△'),
406 "whitesquaretickleft" => ordinary('⟤'),
407 "whitesquaretickright" => ordinary('⟥'),
408
409 "bf" => self.font_change(Font::Bold),
414 "cal" => self.font_change(Font::Script),
415 "it" => self.font_change(Font::Italic),
416 "rm" => self.font_change(Font::UpRight),
417 "sf" => self.font_change(Font::SansSerif),
418 "tt" => self.font_change(Font::Monospace),
419 "mathbf" | "symbf" | "mathbfup" | "symbfup" => {
424 return self.font_group(Some(Font::Bold))
425 }
426 "boldsymbol" => return self.font_group(Some(Font::BoldSymbol)),
427 "mathcal" | "symcal" => return self.font_group(Some(Font::Script)),
428 "mathit" | "symit" => return self.font_group(Some(Font::Italic)),
429 "mathrm" | "symrm" | "mathup" | "symup" => return self.font_group(Some(Font::UpRight)),
430 "mathsf" | "symsf" | "mathsfup" | "symsfup" => {
431 return self.font_group(Some(Font::SansSerif))
432 }
433 "mathtt" | "symtt" => return self.font_group(Some(Font::Monospace)),
434 "mathbb" | "symbb" => return self.font_group(Some(Font::DoubleStruck)),
435 "mathbbit" | "symbbit" => return self.font_group(Some(Font::DoubleStruckItalic)),
436 "mathfrak" | "symfrak" => return self.font_group(Some(Font::Fraktur)),
437 "mathbfcal" | "symbfcal" => return self.font_group(Some(Font::BoldScript)),
438 "mathsfit" | "symsfit" => return self.font_group(Some(Font::SansSerifItalic)),
439 "mathbfit" | "symbfit" => return self.font_group(Some(Font::BoldItalic)),
440 "mathbffrak" | "symbffrak" => return self.font_group(Some(Font::BoldFraktur)),
441 "mathbfsfup" | "symbfsfup" => return self.font_group(Some(Font::BoldSansSerif)),
442 "mathbfsfit" | "symbfsfit" => return self.font_group(Some(Font::SansSerifBoldItalic)),
443 "mathnormal" | "symnormal" => return self.font_group(None),
444
445 "displaystyle" => self.style_change(S::Display),
449 "textstyle" => self.style_change(S::Text),
450 "scriptstyle" => self.style_change(S::Script),
451 "scriptscriptstyle" => self.style_change(S::ScriptScript),
452
453 "color" => {
457 let Argument::Group(color) = lex::argument(&mut self.content)? else {
458 return Err(ErrorKind::Argument);
459 };
460 self.state.skip_scripts = true;
461
462 let color = lex::color(color).ok_or(ErrorKind::UnknownColor)?;
463 E::StateChange(SC::Color(CC {
464 color,
465 target: CT::Text,
466 }))
467 }
468 "textcolor" => {
469 let str = &mut self.content;
470 let Argument::Group(color) = lex::argument(str)? else {
471 return Err(ErrorKind::Argument);
472 };
473
474 let color = lex::color(color).ok_or(ErrorKind::UnknownColor)?;
475 let modified = lex::argument(str)?;
476
477 self.buffer.extend([
478 I::Event(E::Begin(G::Normal)),
479 I::Event(E::StateChange(SC::Color(CC {
480 color,
481 target: CT::Text,
482 }))),
483 ]);
484 self.handle_argument(modified)?;
485 E::End
486 }
487 "colorbox" => {
488 let Argument::Group(color) = lex::argument(&mut self.content)? else {
489 return Err(ErrorKind::Argument);
490 };
491
492 let color = lex::color(color).ok_or(ErrorKind::UnknownColor)?;
493 self.buffer.extend([
494 I::Event(E::Begin(G::Normal)),
495 I::Event(E::StateChange(SC::Color(CC {
496 color,
497 target: CT::Background,
498 }))),
499 ]);
500 self.text_argument(None)?;
501 E::End
502 }
503 "fcolorbox" => {
504 let str = &mut self.content;
505 let Argument::Group(frame_color) = lex::argument(str)? else {
506 return Err(ErrorKind::Argument);
507 };
508 let Argument::Group(background_color) = lex::argument(str)? else {
509 return Err(ErrorKind::Argument);
510 };
511
512 let frame_color = lex::color(frame_color).ok_or(ErrorKind::UnknownColor)?;
513 let background_color =
514 lex::color(background_color).ok_or(ErrorKind::UnknownColor)?;
515 self.buffer.extend([
516 I::Event(E::Begin(G::Normal)),
517 I::Event(E::StateChange(SC::Color(CC {
518 color: frame_color,
519 target: CT::Border,
520 }))),
521 I::Event(E::StateChange(SC::Color(CC {
522 color: background_color,
523 target: CT::Background,
524 }))),
525 ]);
526 self.text_argument(None)?;
527 E::End
528 }
529
530 "big" | "bigl" | "bigr" | "bigm" => return self.sized_delim(DelimiterSize::Big),
536 "Big" | "Bigl" | "Bigr" | "Bigm" => return self.sized_delim(DelimiterSize::BIG),
537 "bigg" | "biggl" | "biggr" | "biggm" => return self.sized_delim(DelimiterSize::Bigg),
538 "Bigg" | "Biggl" | "Biggr" | "Biggm" => return self.sized_delim(DelimiterSize::BIGG),
539
540 "left" => {
541 let curr_str = &mut self.content;
542 let opening = if let Some(rest) = curr_str.strip_prefix('.') {
543 *curr_str = rest;
544 None
545 } else {
546 Some(lex::delimiter(curr_str)?.0)
547 };
548
549 let curr_str = &mut self.content;
550 let group_content = lex::group_content(curr_str, GroupingKind::LeftRight)?;
551 let closing = if let Some(rest) = curr_str.strip_prefix('.') {
552 *curr_str = rest;
553 None
554 } else {
555 Some(lex::delimiter(curr_str)?.0)
556 };
557
558 self.buffer.extend([
559 I::Event(E::Begin(G::LeftRight(opening, closing))),
560 I::SubGroup {
561 content: group_content,
562 allowed_alignment_count: None,
563 },
564 I::Event(E::End),
565 ]);
566
567 return Ok(());
568 }
569 "middle" => {
572 let delimiter = lex::delimiter(&mut self.content)?;
573 E::Content(C::Delimiter {
574 content: delimiter.0,
575 size: Some(DelimiterSize::Big),
576 ty: DelimiterType::Fence,
577 })
578 }
579 "right" => {
580 return Err(ErrorKind::UnbalancedGroup(None));
581 }
582
583 "sum" => self.large_op('∑', true),
589 "prod" => self.large_op('∏', true),
590 "coprod" => self.large_op('∐', true),
591 "bigvee" => self.large_op('⋁', true),
592 "bigwedge" => self.large_op('⋀', true),
593 "bigcup" => self.large_op('⋃', true),
594 "bigcap" => self.large_op('⋂', true),
595 "biguplus" => self.large_op('⨄', true),
596 "bigoplus" => self.large_op('⨁', true),
597 "bigotimes" => self.large_op('⨂', true),
598 "bigodot" => self.large_op('⨀', true),
599 "bigsqcup" => self.large_op('⨆', true),
600 "bigsqcap" => self.large_op('⨅', true),
601 "bigtimes" => self.large_op('⨉', true),
602 "intop" => self.large_op('∫', true),
603 "int" => self.large_op('∫', false),
605 "iint" => self.large_op('∬', false),
606 "iiint" => self.large_op('∭', false),
607 "smallint" => {
608 self.state.allow_script_modifiers = true;
609 E::Content(C::LargeOp {
610 content: '∫',
611 small: true,
612 })
613 }
614 "iiiint" => self.large_op('⨌', false),
615 "intcap" => self.large_op('⨙', false),
616 "intcup" => self.large_op('⨚', false),
617 "oint" => self.large_op('∮', false),
618 "varointclockwise" => self.large_op('∲', false),
619 "intclockwise" => self.large_op('∱', false),
620 "oiint" => self.large_op('∯', false),
621 "pointint" => self.large_op('⨕', false),
622 "rppolint" => self.large_op('⨒', false),
623 "scpolint" => self.large_op('⨓', false),
624 "oiiint" => self.large_op('∰', false),
625 "intlarhk" => self.large_op('⨗', false),
626 "sqint" => self.large_op('⨖', false),
627 "intx" => self.large_op('⨘', false),
628 "intbar" => self.large_op('⨍', false),
629 "intBar" => self.large_op('⨎', false),
630 "fint" => self.large_op('⨏', false),
631
632 "acute" => return self.accent('´', false),
636 "bar" | "overline" => return self.accent('‾', false),
637 "underbar" | "underline" => return self.underscript('_'),
638 "breve" => return self.accent('˘', false),
639 "check" => return self.accent('ˇ', false),
640 "dot" => return self.accent('˙', false),
641 "ddot" => return self.accent('¨', false),
642 "grave" => return self.accent('`', false),
643 "hat" => return self.accent('^', false),
644 "tilde" => return self.accent('~', false),
645 "vec" => return self.accent('→', false),
646 "mathring" => return self.accent('˚', false),
647
648 "overleftarrow" => return self.accent('←', true),
650 "underleftarrow" => return self.underscript('←'),
651 "overrightarrow" => return self.accent('→', true),
652 "Overrightarrow" => return self.accent('⇒', true),
653 "underrightarrow" => return self.underscript('→'),
654 "overleftrightarrow" => return self.accent('↔', true),
655 "underleftrightarrow" => return self.underscript('↔'),
656 "overleftharpoon" => return self.accent('↼', true),
657 "overrightharpoon" => return self.accent('⇀', true),
658
659 "widecheck" => return self.accent('ˇ', true),
661 "widehat" => return self.accent('^', true),
662 "widetilde" => return self.accent('~', true),
663 "wideparen" | "overparen" => return self.accent('⏜', true),
664
665 "overgroup" => {
667 self.state.script_position = SP::AboveBelow;
668 return self.accent('⏠', true);
669 }
670 "undergroup" => {
671 self.state.script_position = SP::AboveBelow;
672 return self.underscript('⏡');
673 }
674 "overbrace" => {
675 self.state.script_position = SP::AboveBelow;
676 return self.accent('⏞', true);
677 }
678 "underbrace" => {
679 self.state.script_position = SP::AboveBelow;
680 return self.underscript('⏟');
681 }
682 "underparen" => {
683 self.state.script_position = SP::AboveBelow;
684 return self.underscript('⏝');
685 }
686 "overbracket" => {
687 self.state.script_position = SP::AboveBelow;
688 return self.accent('⎴', true);
689 }
690 "underbracket" => {
691 self.state.script_position = SP::AboveBelow;
692 return self.underscript('⎵');
693 }
694
695 "prime" => ordinary('′'),
697 "dprime" => ordinary('″'),
698 "trprime" => ordinary('‴'),
699 "qprime" => ordinary('⁗'),
700 "backprime" => ordinary('‵'),
701 "backdprime" => ordinary('‶'),
702 "backtrprime" => ordinary('‷'),
703
704 "," | "thinspace" => E::Space {
708 width: Some(Dimension::new(3. / 18., DimensionUnit::Em)),
709 height: None,
710 depth: None,
711 },
712 ">" | ":" | "medspace" => E::Space {
713 width: Some(Dimension::new(4. / 18., DimensionUnit::Em)),
714 height: None,
715 depth: None,
716 },
717 ";" | "thickspace" => E::Space {
718 width: Some(Dimension::new(5. / 18., DimensionUnit::Em)),
719 height: None,
720 depth: None,
721 },
722 "enspace" => E::Space {
723 width: Some(Dimension::new(0.5, DimensionUnit::Em)),
724 height: None,
725 depth: None,
726 },
727 "quad" => E::Space {
728 width: Some(Dimension::new(1., DimensionUnit::Em)),
729 height: None,
730 depth: None,
731 },
732 "qquad" => E::Space {
733 width: Some(Dimension::new(2., DimensionUnit::Em)),
734 height: None,
735 depth: None,
736 },
737 "mathstrut" => E::Space {
738 width: None,
739 height: Some(Dimension::new(0.7, DimensionUnit::Em)),
740 depth: None,
741 },
742 "strut" => E::Space {
743 width: None,
744 height: Some(Dimension::new(1.0, DimensionUnit::Em)),
745 depth: None,
746 },
747 "~" | "nobreakspace" => E::Content(C::Text(" ")),
748 "kern" => {
750 let dimension = lex::dimension_or_braced(&mut self.content)?;
751 E::Space {
752 width: Some(dimension),
753 height: None,
754 depth: None,
755 }
756 }
757 "hskip" => {
758 let glue = lex::glue_or_braced(&mut self.content)?;
759 E::Space {
760 width: Some(glue.0),
761 height: None,
762 depth: None,
763 }
764 }
765 "mkern" => {
766 let dimension = lex::dimension_or_braced(&mut self.content)?;
767 if dimension.unit == DimensionUnit::Mu {
768 E::Space {
769 width: Some(dimension),
770 height: None,
771 depth: None,
772 }
773 } else {
774 return Err(ErrorKind::MathUnit);
775 }
776 }
777 "mskip" => {
778 let glue = lex::glue_or_braced(&mut self.content)?;
779 if glue.0.unit == DimensionUnit::Mu
780 && glue
781 .1
782 .map_or(true, |Dimension { unit, .. }| unit == DimensionUnit::Mu)
783 && glue
784 .2
785 .map_or(true, |Dimension { unit, .. }| unit == DimensionUnit::Mu)
786 {
787 E::Space {
788 width: Some(glue.0),
789 height: None,
790 depth: None,
791 }
792 } else {
793 return Err(ErrorKind::MathUnit);
794 }
795 }
796 "hspace" => {
797 let Argument::Group(mut argument) = lex::argument(&mut self.content)? else {
798 return Err(ErrorKind::DimensionArgument);
799 };
800 let glue = lex::glue(&mut argument)?;
801 E::Space {
802 width: Some(glue.0),
803 height: None,
804 depth: None,
805 }
806 }
807 "Space" => {
809 let Argument::Group(mut width_arg) = lex::argument(&mut self.content)? else {
810 return Err(ErrorKind::DimensionArgument);
811 };
812 let width = lex::dimension(&mut width_arg)?;
813 let Argument::Group(mut height_arg) = lex::argument(&mut self.content)? else {
814 return Err(ErrorKind::DimensionArgument);
815 };
816 let height = lex::dimension(&mut height_arg)?;
817 let Argument::Group(mut depth_arg) = lex::argument(&mut self.content)? else {
818 return Err(ErrorKind::DimensionArgument);
819 };
820 let depth = lex::dimension(&mut depth_arg)?;
821 E::Space {
822 width: Some(width),
823 height: Some(height),
824 depth: Some(depth),
825 }
826 }
827 "!" | "negthinspace" => E::Space {
829 width: Some(Dimension::new(-3. / 18., DimensionUnit::Em)),
830 height: None,
831 depth: None,
832 },
833 "negmedspace" => E::Space {
834 width: Some(Dimension::new(-4. / 18., DimensionUnit::Em)),
835 height: None,
836 depth: None,
837 },
838 "negthickspace" => E::Space {
839 width: Some(Dimension::new(-5. / 18., DimensionUnit::Em)),
840 height: None,
841 depth: None,
842 },
843
844 "forall" => ordinary('∀'),
848 "exists" => ordinary('∃'),
849 "complement" => ordinary('∁'),
850 "nexists" => ordinary('∄'),
851 "neg" | "lnot" => ordinary('¬'),
852
853 "therefore" => relation('∴'),
854 "because" => relation('∵'),
855 "subset" => relation('⊂'),
856 "supset" => relation('⊃'),
857 "strictif" => relation('⥽'),
858 "strictfi" => relation('⥼'),
859 "mapsto" => relation('↦'),
860 "implies" => relation('⟹'),
861 "mid" => relation('∣'),
862 "to" => relation('→'),
863 "impliedby" => relation('⟸'),
864 "in" | "isin" => relation('∈'),
865 "ni" => relation('∋'),
866 "gets" => relation('←'),
867 "iff" => relation('⟺'),
868 "notni" => relation('∌'),
869
870 "land" => binary('∧'),
871
872 "emptyset" => ordinary('∅'),
873 "varnothing" => ordinary('⌀'),
874
875 "ldotp" => binary('.'),
879 "cdotp" => binary('·'),
880 "cdot" => binary('⋅'),
881 "centerdot" => binary('·'),
882 "circ" => binary('∘'),
883 "bullet" => binary('∙'),
884 "circledast" => binary('⊛'),
885 "circledcirc" => binary('⊚'),
886 "circleddash" => binary('⊝'),
887 "bigcirc" => binary('◯'),
888 "leftthreetimes" => binary('⋋'),
889 "rhd" => binary('⊳'),
890 "lhd" => binary('⊲'),
891 "rightthreetimes" => binary('⋌'),
892 "rtimes" => binary('⋊'),
893 "ltimes" => binary('⋉'),
894 "leftmodels" => binary('⊨'),
895 "amalg" => binary('⨿'),
896 "ast" => binary('*'),
897 "asymp" => binary('≍'),
898 "And" | "with" => binary('&'),
899 "lor" => binary('∨'),
900 "setminus" => binary('∖'),
901 "Cup" => binary('⋓'),
902 "cup" => binary('∪'),
903 "sqcup" => binary('⊔'),
904 "sqcap" => binary('⊓'),
905 "lessdot" => binary('⋖'),
906 "smallsetminus" => E::Content(C::BinaryOp {
907 content: '∖',
908 small: false,
909 }),
910 "barwedge" => binary('⌅'),
911 "curlyvee" => binary('⋎'),
912 "curlywedge" => binary('⋏'),
913 "sslash" => binary('⫽'),
914 "div" => binary('÷'),
915 "mp" => binary('∓'),
916 "times" => binary('×'),
917 "boxdot" => binary('⊡'),
918 "divideontimes" => binary('⋇'),
919 "odot" => binary('⊙'),
920 "unlhd" => binary('⊴'),
921 "boxminus" => binary('⊟'),
922 "dotplus" => binary('∔'),
923 "ominus" => binary('⊖'),
924 "unrhd" => binary('⊵'),
925 "boxplus" => binary('⊞'),
926 "doublebarwedge" => binary('⩞'),
927 "oplus" => binary('⊕'),
928 "uplus" => binary('⊎'),
929 "boxtimes" => binary('⊠'),
930 "doublecap" => binary('⋒'),
931 "otimes" => binary('⊗'),
932 "vee" => binary('∨'),
933 "veebar" => binary('⊻'),
934 "Cap" => binary('⋒'),
935 "parr" => binary('⅋'),
936 "wedge" => binary('∧'),
937 "cap" => binary('∩'),
938 "gtrdot" => binary('⋗'),
939 "pm" => binary('±'),
940 "intercal" => binary('⊺'),
941 "wr" => binary('≀'),
942 "circledvert" => binary('⦶'),
943 "blackhourglass" => binary('⧗'),
944 "circlehbar" => binary('⦵'),
945 "operp" => binary('⦹'),
946 "boxast" => binary('⧆'),
947 "boxbox" => binary('⧈'),
948 "oslash" => binary('⊘'),
949 "boxcircle" => binary('⧇'),
950 "diamond" => binary('⋄'),
951 "Otimes" => binary('⨷'),
952 "hourglass" => binary('⧖'),
953 "otimeshat" => binary('⨶'),
954 "triangletimes" => binary('⨻'),
955 "lozengeminus" => binary('⟠'),
956 "star" => binary('⋆'),
957 "obar" => binary('⌽'),
958 "obslash" => binary('⦸'),
959 "triangleminus" => binary('⨺'),
960 "odiv" => binary('⨸'),
961 "triangleplus" => binary('⨹'),
962 "circledequal" => binary('⊜'),
963 "ogreaterthan" => binary('⧁'),
964 "circledparallel" => binary('⦷'),
965 "olessthan" => binary('⧀'),
966
967 "eqcirc" => relation('≖'),
971 "lessgtr" => relation('≶'),
972 "smile" | "sincoh" => relation('⌣'),
973 "eqcolon" | "minuscolon" => relation('∹'),
974 "lesssim" => relation('≲'),
975 "sqsubset" => relation('⊏'),
976 "ll" => relation('≪'),
977 "sqsubseteq" => relation('⊑'),
978 "eqqcolon" => relation('≕'),
979 "lll" => relation('⋘'),
980 "sqsupset" => relation('⊐'),
981 "llless" => relation('⋘'),
982 "sqsupseteq" => relation('⊒'),
983 "approx" => relation('≈'),
984 "eqdef" => relation('≝'),
985 "lt" => relation('<'),
986 "stareq" => relation('≛'),
987 "approxeq" => relation('≊'),
988 "eqsim" => relation('≂'),
989 "measeq" => relation('≞'),
990 "Subset" => relation('⋐'),
991 "arceq" => relation('≘'),
992 "eqslantgtr" => relation('⪖'),
993 "eqslantless" => relation('⪕'),
994 "models" => relation('⊨'),
995 "subseteq" => relation('⊆'),
996 "backcong" => relation('≌'),
997 "equiv" => relation('≡'),
998 "multimap" => relation('⊸'),
999 "subseteqq" => relation('⫅'),
1000 "fallingdotseq" => relation('≒'),
1001 "multimapboth" => relation('⧟'),
1002 "succ" => relation('≻'),
1003 "backsim" => relation('∽'),
1004 "frown" => relation('⌢'),
1005 "multimapinv" => relation('⟜'),
1006 "succapprox" => relation('⪸'),
1007 "backsimeq" => relation('⋍'),
1008 "ge" => relation('≥'),
1009 "origof" => relation('⊶'),
1010 "succcurlyeq" => relation('≽'),
1011 "between" => relation('≬'),
1012 "geq" => relation('≥'),
1013 "owns" => relation('∋'),
1014 "succeq" => relation('⪰'),
1015 "bumpeq" => relation('≏'),
1016 "geqq" => relation('≧'),
1017 "parallel" => relation('∥'),
1018 "succsim" => relation('≿'),
1019 "Bumpeq" => relation('≎'),
1020 "geqslant" => relation('⩾'),
1021 "perp" => relation('⟂'),
1022 "Supset" => relation('⋑'),
1023 "circeq" => relation('≗'),
1024 "gg" => relation('≫'),
1025 "Perp" => relation('⫫'),
1026 "coh" => relation('⌢'),
1027 "ggg" => relation('⋙'),
1028 "pitchfork" => relation('⋔'),
1029 "supseteq" => relation('⊇'),
1030 "gggtr" => relation('⋙'),
1031 "prec" => relation('≺'),
1032 "supseteqq" => relation('⫆'),
1033 "gt" => relation('>'),
1034 "precapprox" => relation('⪷'),
1035 "thickapprox" => relation('≈'),
1036 "gtrapprox" => relation('⪆'),
1037 "preccurlyeq" => relation('≼'),
1038 "thicksim" => relation('∼'),
1039 "gtreqless" => relation('⋛'),
1040 "preceq" => relation('⪯'),
1041 "trianglelefteq" => relation('⊴'),
1042 "coloneqq" | "colonequals" => relation('≔'),
1043 "gtreqqless" => relation('⪌'),
1044 "precsim" => relation('≾'),
1045 "triangleq" => relation('≜'),
1046 "Coloneqq" | "coloncolonequals" => relation('⩴'),
1047 "gtrless" => relation('≷'),
1048 "propto" => relation('∝'),
1049 "trianglerighteq" => relation('⊵'),
1050 "gtrsim" => relation('≳'),
1051 "questeq" => relation('≟'),
1052 "varpropto" => relation('∝'),
1053 "imageof" => relation('⊷'),
1054 "cong" => relation('≅'),
1055 "risingdotseq" => relation('≓'),
1056 "vartriangleleft" => relation('⊲'),
1057 "curlyeqprec" => relation('⋞'),
1058 "scoh" => relation('⌢'),
1059 "vartriangleright" => relation('⊳'),
1060 "curlyeqsucc" => relation('⋟'),
1061 "le" => relation('≤'),
1062 "shortmid" => E::Content(C::Relation {
1063 content: RelationContent::single_char('∣'),
1064 small: true,
1065 }),
1066 "shortparallel" => E::Content(C::Relation {
1067 content: RelationContent::single_char('∥'),
1068 small: true,
1069 }),
1070 "vdash" => relation('⊢'),
1071 "dashv" => relation('⊣'),
1072 "leq" => relation('≤'),
1073 "vDash" => relation('⊨'),
1074 "dblcolon" | "coloncolon" => relation('∷'),
1075 "leqq" => relation('≦'),
1076 "sim" => relation('∼'),
1077 "Vdash" => relation('⊩'),
1078 "doteq" => relation('≐'),
1079 "leqslant" => relation('⩽'),
1080 "simeq" => relation('≃'),
1081 "Dash" => relation('⊫'),
1082 "Doteq" => relation('≑'),
1083 "lessapprox" => relation('⪅'),
1084 "Vvdash" => relation('⊪'),
1085 "doteqdot" => relation('≑'),
1086 "lesseqgtr" => relation('⋚'),
1087 "smallfrown" => relation('⌢'),
1088 "veeeq" => relation('≚'),
1089 "eqeq" => relation('⩵'),
1090 "lesseqqgtr" => relation('⪋'),
1091 "smallsmile" => E::Content(C::Relation {
1092 content: RelationContent::single_char('⌣'),
1093 small: true,
1094 }),
1095 "wedgeq" => relation('≙'),
1096 "bowtie" | "Join" => relation('⋈'),
1097 "gnapprox" => relation('⪊'),
1099 "ngeqslant" => relation('≱'),
1100 "nsubset" => relation('⊄'),
1101 "nVdash" => relation('⊮'),
1102 "gneq" => relation('⪈'),
1103 "ngtr" => relation('≯'),
1104 "nsubseteq" => relation('⊈'),
1105 "precnapprox" => relation('⪹'),
1106 "gneqq" => relation('≩'),
1107 "nleq" => relation('≰'),
1108 "nsubseteqq" => relation('⊈'),
1109 "precneqq" => relation('⪵'),
1110 "gnsim" => relation('⋧'),
1111 "nleqq" => relation('≰'),
1112 "nsucc" => relation('⊁'),
1113 "precnsim" => relation('⋨'),
1114 "nleqslant" => relation('≰'),
1115 "nsucceq" => relation('⋡'),
1116 "subsetneq" => relation('⊊'),
1117 "lnapprox" => relation('⪉'),
1118 "nless" => relation('≮'),
1119 "nsupset" => relation('⊅'),
1120 "subsetneqq" => relation('⫋'),
1121 "lneq" => relation('⪇'),
1122 "nmid" => relation('∤'),
1123 "nsupseteq" => relation('⊉'),
1124 "succnapprox" => relation('⪺'),
1125 "lneqq" => relation('≨'),
1126 "notin" => relation('∉'),
1127 "nsupseteqq" => relation('⊉'),
1128 "succneqq" => relation('⪶'),
1129 "lnsim" => relation('⋦'),
1130 "ntriangleleft" => relation('⋪'),
1131 "succnsim" => relation('⋩'),
1132 "nparallel" => relation('∦'),
1133 "ntrianglelefteq" => relation('⋬'),
1134 "supsetneq" => relation('⊋'),
1135 "ncong" => relation('≆'),
1136 "nprec" => relation('⊀'),
1137 "ntriangleright" => relation('⋫'),
1138 "supsetneqq" => relation('⫌'),
1139 "ne" => relation('≠'),
1140 "npreceq" => relation('⋠'),
1141 "ntrianglerighteq" => relation('⋭'),
1142 "neq" => relation('≠'),
1143 "nshortmid" => E::Content(C::Relation {
1144 content: RelationContent::single_char('∤'),
1145 small: true,
1146 }),
1147 "nvdash" => relation('⊬'),
1148 "ngeq" => relation('≱'),
1149 "nshortparallel" => E::Content(C::Relation {
1150 content: RelationContent::single_char('∦'),
1151 small: true,
1152 }),
1153 "nvDash" => relation('⊭'),
1154 "ngeqq" => relation('≱'),
1155 "nsim" => relation('≁'),
1156 "nVDash" => relation('⊯'),
1157 "varsupsetneqq" => multirelation('⫌', '\u{fe00}'),
1158 "varsubsetneqq" => multirelation('⫋', '\u{fe00}'),
1159 "varsubsetneq" => multirelation('⊊', '\u{fe00}'),
1160 "varsupsetneq" => multirelation('⊋', '\u{fe00}'),
1161 "gvertneqq" => multirelation('≩', '\u{fe00}'),
1162 "lvertneqq" => multirelation('≨', '\u{fe00}'),
1163 "Eqcolon" | "minuscoloncolon" => multirelation('−', '∷'),
1164 "Eqqcolon" => multirelation('=', '∷'),
1165 "approxcolon" => multirelation('≈', ':'),
1166 "colonapprox" => multirelation(':', '≈'),
1167 "approxcoloncolon" => multirelation('≈', '∷'),
1168 "Colonapprox" | "coloncolonapprox" => multirelation('∷', '≈'),
1169 "coloneq" | "colonminus" => multirelation(':', '−'),
1170 "Coloneq" | "coloncolonminus" => multirelation('∷', '−'),
1171 "colonsim" => multirelation(':', '∼'),
1172 "Colonsim" | "coloncolonsim" => multirelation('∷', '∼'),
1173
1174 "circlearrowleft" => relation('↺'),
1178 "Leftrightarrow" => relation('⇔'),
1179 "restriction" => relation('↾'),
1180 "circlearrowright" => relation('↻'),
1181 "leftrightarrows" => relation('⇆'),
1182 "rightarrow" => relation('→'),
1183 "curvearrowleft" => relation('↶'),
1184 "leftrightharpoons" => relation('⇋'),
1185 "Rightarrow" => relation('⇒'),
1186 "curvearrowright" => relation('↷'),
1187 "leftrightsquigarrow" => relation('↭'),
1188 "rightarrowtail" => relation('↣'),
1189 "dashleftarrow" => relation('⇠'),
1190 "Lleftarrow" => relation('⇚'),
1191 "rightharpoondown" => relation('⇁'),
1192 "dashrightarrow" => relation('⇢'),
1193 "longleftarrow" => relation('⟵'),
1194 "rightharpoonup" => relation('⇀'),
1195 "downarrow" => relation('↓'),
1196 "Longleftarrow" => relation('⟸'),
1197 "rightleftarrows" => relation('⇄'),
1198 "Downarrow" => relation('⇓'),
1199 "longleftrightarrow" => relation('⟷'),
1200 "rightleftharpoons" => relation('⇌'),
1201 "downdownarrows" => relation('⇊'),
1202 "Longleftrightarrow" => relation('⟺'),
1203 "rightrightarrows" => relation('⇉'),
1204 "downharpoonleft" => relation('⇃'),
1205 "longmapsto" => relation('⟼'),
1206 "rightsquigarrow" => relation('⇝'),
1207 "downharpoonright" => relation('⇂'),
1208 "longrightarrow" => relation('⟶'),
1209 "Rrightarrow" => relation('⇛'),
1210 "Longrightarrow" => relation('⟹'),
1211 "Rsh" => relation('↱'),
1212 "hookleftarrow" => relation('↩'),
1213 "looparrowleft" => relation('↫'),
1214 "searrow" => relation('↘'),
1215 "hookrightarrow" => relation('↪'),
1216 "looparrowright" => relation('↬'),
1217 "swarrow" => relation('↙'),
1218 "Lsh" => relation('↰'),
1219 "mapsfrom" => relation('↤'),
1220 "twoheadleftarrow" => relation('↞'),
1221 "twoheadrightarrow" => relation('↠'),
1222 "leadsto" => relation('⇝'),
1223 "nearrow" => relation('↗'),
1224 "uparrow" => relation('↑'),
1225 "leftarrow" => relation('←'),
1226 "nleftarrow" => relation('↚'),
1227 "Uparrow" => relation('⇑'),
1228 "Leftarrow" => relation('⇐'),
1229 "nLeftarrow" => relation('⇍'),
1230 "updownarrow" => relation('↕'),
1231 "leftarrowtail" => relation('↢'),
1232 "nleftrightarrow" => relation('↮'),
1233 "Updownarrow" => relation('⇕'),
1234 "leftharpoondown" => relation('↽'),
1235 "nLeftrightarrow" => relation('⇎'),
1236 "upharpoonleft" => relation('↿'),
1237 "leftharpoonup" => relation('↼'),
1238 "nrightarrow" => relation('↛'),
1239 "upharpoonright" => relation('↾'),
1240 "leftleftarrows" => relation('⇇'),
1241 "nRightarrow" => relation('⇏'),
1242 "upuparrows" => relation('⇈'),
1243 "leftrightarrow" => relation('↔'),
1244 "nwarrow" => relation('↖'),
1245 "xleftarrow" => {
1246 let below = lex::optional_argument(&mut self.content);
1247 let above = lex::argument(&mut self.content)?;
1248 self.buffer.extend([
1249 I::Event(E::Script {
1250 ty: if below.is_some() {
1251 ST::SubSuperscript
1252 } else {
1253 ST::Superscript
1254 },
1255 position: SP::AboveBelow,
1256 }),
1257 I::Event(relation('←')),
1258 ]);
1259 if let Some(below) = below {
1260 self.handle_argument(Argument::Group(below))?;
1261 }
1262 self.handle_argument(above)?;
1263 return Ok(());
1264 }
1265 "xrightarrow" => {
1266 let below = lex::optional_argument(&mut self.content);
1267 let above = lex::argument(&mut self.content)?;
1268 self.buffer.extend([
1269 I::Event(E::Script {
1270 ty: if below.is_some() {
1271 ST::SubSuperscript
1272 } else {
1273 ST::Superscript
1274 },
1275 position: SP::AboveBelow,
1276 }),
1277 I::Event(relation('→')),
1278 ]);
1279 if let Some(below) = below {
1280 self.handle_argument(Argument::Group(below))?;
1281 }
1282 self.handle_argument(above)?;
1283 return Ok(());
1284 }
1285
1286 "frac" => {
1290 return self.fraction_like(None, None, None, None);
1291 }
1292 "genfrac" => {
1294 let str = &mut self.content;
1295 let ldelim_argument = lex::argument(str)?;
1296 let ldelim = match ldelim_argument {
1297 Argument::Token(token) => {
1298 Some(token_to_delim(token).ok_or(ErrorKind::Delimiter)?)
1299 }
1300 Argument::Group(group) => {
1301 if group.is_empty() {
1302 None
1303 } else {
1304 return Err(ErrorKind::Delimiter);
1305 }
1306 }
1307 };
1308 let rdelim_argument = lex::argument(str)?;
1309 let rdelim = match rdelim_argument {
1310 Argument::Token(token) => {
1311 Some(token_to_delim(token).ok_or(ErrorKind::Delimiter)?)
1312 }
1313 Argument::Group(group) => {
1314 if group.is_empty() {
1315 None
1316 } else {
1317 return Err(ErrorKind::Delimiter);
1318 }
1319 }
1320 };
1321 let bar_size_argument = lex::argument(str)?;
1322 let bar_size = match bar_size_argument {
1323 Argument::Token(_) => return Err(ErrorKind::DimensionArgument),
1324 Argument::Group("") => None,
1325 Argument::Group(mut group) => lex::dimension(&mut group).and_then(|dim| {
1326 if group.is_empty() {
1327 Ok(Some(dim))
1328 } else {
1329 Err(ErrorKind::DimensionArgument)
1330 }
1331 })?,
1332 };
1333 let display_style_argument = lex::argument(str)?;
1334 let display_style = match display_style_argument {
1335 Argument::Token(t) => match t {
1336 Token::ControlSequence(_) => return Err(ErrorKind::Argument),
1337 Token::Character(c) => Some(match c.into() {
1338 '0' => S::Display,
1339 '1' => S::Text,
1340 '2' => S::Script,
1341 '3' => S::ScriptScript,
1342 _ => return Err(ErrorKind::Argument),
1343 }),
1344 },
1345 Argument::Group(group) => match group {
1346 "0" => Some(S::Display),
1347 "1" => Some(S::Text),
1348 "2" => Some(S::Script),
1349 "3" => Some(S::ScriptScript),
1350 "" => None,
1351 _ => return Err(ErrorKind::Argument),
1352 },
1353 };
1354
1355 self.fraction_like(
1356 ldelim.map(|d| d.0),
1357 rdelim.map(|d| d.0),
1358 bar_size,
1359 display_style,
1360 )?;
1361
1362 return Ok(());
1363 }
1364 "cfrac" | "dfrac" => {
1365 self.fraction_like(None, None, None, Some(S::Display))?;
1366 return Ok(());
1367 }
1368 "tfrac" => {
1369 self.fraction_like(None, None, None, Some(S::Text))?;
1370 return Ok(());
1371 }
1372 "binom" => {
1373 self.fraction_like(
1374 Some('('),
1375 Some(')'),
1376 Some(Dimension::new(0., DimensionUnit::Em)),
1377 None,
1378 )?;
1379 return Ok(());
1380 }
1381 "dbinom" => {
1382 self.fraction_like(
1383 Some('('),
1384 Some(')'),
1385 Some(Dimension::new(0., DimensionUnit::Em)),
1386 Some(S::Display),
1387 )?;
1388 return Ok(());
1389 }
1390 "tbinom" => {
1391 self.fraction_like(
1392 Some('('),
1393 Some(')'),
1394 Some(Dimension::new(0., DimensionUnit::Em)),
1395 Some(S::Text),
1396 )?;
1397 return Ok(());
1398 }
1399 "overset" | "stackrel" => {
1400 self.buffer.push(I::Event(E::Script {
1401 ty: ST::Superscript,
1402 position: SP::AboveBelow,
1403 }));
1404 let before_over_index = self.buffer.len();
1405 let over = lex::argument(&mut self.content)?;
1406 self.handle_argument(over)?;
1407 let over_events = self.buffer.split_off(before_over_index);
1408 let base = lex::argument(&mut self.content)?;
1409 self.handle_argument(base)?;
1410 self.buffer.extend(over_events);
1411 return Ok(());
1412 }
1413 "underset" => {
1414 self.buffer.push(I::Event(E::Script {
1415 ty: ST::Subscript,
1416 position: SP::AboveBelow,
1417 }));
1418 let before_under_index = self.buffer.len();
1419 let under = lex::argument(&mut self.content)?;
1420 self.handle_argument(under)?;
1421 let under_events = self.buffer.split_off(before_under_index);
1422 let base = lex::argument(&mut self.content)?;
1423 self.handle_argument(base)?;
1424 self.buffer.extend(under_events);
1425 return Ok(());
1426 }
1427 "buildrel" => {
1428 let mut over_content = lex::content_with_suffix(&mut self.content, r"\over")?;
1429 self.buffer.push(I::Event(E::Script {
1430 ty: ST::Superscript,
1431 position: SP::AboveBelow,
1432 }));
1433 let before_over_index = self.buffer.len();
1434 let over = lex::argument(&mut over_content)?;
1435 self.handle_argument(over)?;
1436 let over_events = self.buffer.split_off(before_over_index);
1437 let base = lex::argument(&mut self.content)?;
1438 self.handle_argument(base)?;
1439 self.buffer.extend(over_events);
1440 return Ok(());
1441 }
1442 "substack" => {
1443 let content = lex::brace_argument(&mut self.content)?;
1444 self.buffer.push(I::Event(E::Begin(G::SubArray {
1445 alignment: ColumnAlignment::Center,
1446 })));
1447 self.buffer.push(I::SubGroup {
1448 content,
1449 allowed_alignment_count: Some(AlignmentCount::new(0)),
1450 });
1451 self.buffer.push(I::Event(E::End));
1452 return Ok(());
1453 }
1454 "sideset" => {
1455 let _left = lex::argument(&mut self.content)?;
1456 let _right = lex::argument(&mut self.content)?;
1457 let base = lex::argument(&mut self.content)?;
1458 self.handle_argument(base)?;
1459 return Ok(());
1460 }
1461
1462 "sqrt" => {
1466 if let Some(index) = lex::optional_argument(&mut self.content) {
1467 self.buffer.push(I::Event(E::Visual(V::Root)));
1468 let arg = lex::argument(&mut self.content)?;
1469 self.handle_argument(arg)?;
1470 self.buffer.push(I::SubGroup {
1471 content: index,
1472 allowed_alignment_count: None,
1473 });
1474 } else {
1475 self.buffer.push(I::Event(E::Visual(V::SquareRoot)));
1476 let arg = lex::argument(&mut self.content)?;
1477 self.handle_argument(arg)?;
1478 }
1479 return Ok(());
1480 }
1481 "surd" => {
1482 self.buffer.extend([
1483 I::Event(E::Visual(V::SquareRoot)),
1484 I::Event(E::Space {
1485 width: Some(Dimension::new(0., DimensionUnit::Em)),
1486 height: Some(Dimension::new(0.7, DimensionUnit::Em)),
1487 depth: None,
1488 }),
1489 ]);
1490 return Ok(());
1491 }
1492
1493 "backslash" => ordinary('\\'),
1494
1495 "#" | "%" | "&" | "$" | "_" => ordinary(
1499 control_sequence
1500 .chars()
1501 .next()
1502 .expect("the control sequence contains one of the matched characters"),
1503 ),
1504 "|" => ordinary('∥'),
1505 "text" => return self.text_argument(None),
1506 "textrm" => return self.text_argument(Some(Font::UpRight)),
1509 "textbf" => return self.text_argument(Some(Font::Bold)),
1510 "textit" => return self.text_argument(Some(Font::Italic)),
1511 "textsf" => return self.text_argument(Some(Font::SansSerif)),
1512 "texttt" => return self.text_argument(Some(Font::Monospace)),
1513
1514 "not" | "cancel" => {
1515 self.buffer.push(I::Event(E::Visual(V::Negation)));
1516 let argument = lex::argument(&mut self.content)?;
1517 self.handle_argument(argument)?;
1518 return Ok(());
1519 }
1520 "char" => {
1521 let number = lex::unsigned_integer(&mut self.content)?;
1522 if number > 255 {
1523 return Err(ErrorKind::InvalidCharNumber);
1524 }
1525 E::Content(C::Ordinary {
1526 content: char::from_u32(number as u32)
1527 .expect("the number is a valid char since it is less than 256"),
1528 stretchy: false,
1529 })
1530 }
1531 "relax" => {
1532 return if self.state.handling_argument {
1533 Err(ErrorKind::Relax)
1534 } else {
1535 Ok(())
1536 }
1537 }
1538
1539 "begingroup" => {
1540 let group = lex::group_content(&mut self.content, GroupingKind::BeginEnd)?;
1541 self.buffer.extend([
1542 I::Event(E::Begin(G::Normal)),
1543 I::SubGroup {
1544 content: group,
1545 allowed_alignment_count: None,
1546 },
1547 I::Event(E::End),
1548 ]);
1549 return Ok(());
1550 }
1551 "endgroup" => return Err(ErrorKind::UnbalancedGroup(None)),
1552
1553 "begin" => {
1554 let Argument::Group(argument) = lex::argument(&mut self.content)? else {
1555 return Err(ErrorKind::Argument);
1556 };
1557
1558 let mut style = None;
1559 let mut wrap: Option<(char, char)> = None;
1560
1561 let (environment, align_count, grouping_kind) = match argument {
1562 "array" => {
1563 let (grouping, count) = self.array_environment()?;
1564 (grouping, count, GroupingKind::Array { display: false })
1565 }
1566 "darray" => {
1567 style = Some(S::Display);
1568 let (grouping, count) = self.array_environment()?;
1569 (grouping, count, GroupingKind::Array { display: true })
1570 }
1571 "matrix" => (
1572 G::Matrix {
1573 alignment: ColumnAlignment::Center,
1574 },
1575 u16::MAX,
1576 GroupingKind::Matrix {
1577 ty: MatrixType::Normal,
1578 column_spec: false,
1579 },
1580 ),
1581 "matrix*" => (
1582 G::Matrix {
1583 alignment: self
1584 .optional_alignment()?
1585 .unwrap_or(ColumnAlignment::Center),
1586 },
1587 u16::MAX,
1588 GroupingKind::Matrix {
1589 ty: MatrixType::Normal,
1590 column_spec: true,
1591 },
1592 ),
1593 "smallmatrix" => {
1594 style = Some(S::Text);
1595 (
1596 G::Matrix {
1597 alignment: ColumnAlignment::Center,
1598 },
1599 u16::MAX,
1600 GroupingKind::Matrix {
1601 ty: MatrixType::Small,
1602 column_spec: false,
1603 },
1604 )
1605 }
1606 "pmatrix" => {
1607 wrap = Some(('(', ')'));
1608 (
1609 G::Matrix {
1610 alignment: ColumnAlignment::Center,
1611 },
1612 u16::MAX,
1613 GroupingKind::Matrix {
1614 ty: MatrixType::Parens,
1615 column_spec: false,
1616 },
1617 )
1618 }
1619 "pmatrix*" => {
1620 wrap = Some(('(', ')'));
1621 (
1622 G::Matrix {
1623 alignment: self
1624 .optional_alignment()?
1625 .unwrap_or(ColumnAlignment::Center),
1626 },
1627 u16::MAX,
1628 GroupingKind::Matrix {
1629 ty: MatrixType::Parens,
1630 column_spec: true,
1631 },
1632 )
1633 }
1634 "bmatrix" => {
1635 wrap = Some(('[', ']'));
1636 (
1637 G::Matrix {
1638 alignment: ColumnAlignment::Center,
1639 },
1640 u16::MAX,
1641 GroupingKind::Matrix {
1642 ty: MatrixType::Brackets,
1643 column_spec: false,
1644 },
1645 )
1646 }
1647 "bmatrix*" => {
1648 wrap = Some(('[', ']'));
1649 (
1650 G::Matrix {
1651 alignment: self
1652 .optional_alignment()?
1653 .unwrap_or(ColumnAlignment::Center),
1654 },
1655 u16::MAX,
1656 GroupingKind::Matrix {
1657 ty: MatrixType::Brackets,
1658 column_spec: true,
1659 },
1660 )
1661 }
1662 "vmatrix" => {
1663 wrap = Some(('|', '|'));
1664 (
1665 G::Matrix {
1666 alignment: ColumnAlignment::Center,
1667 },
1668 u16::MAX,
1669 GroupingKind::Matrix {
1670 ty: MatrixType::Vertical,
1671 column_spec: false,
1672 },
1673 )
1674 }
1675 "vmatrix*" => {
1676 wrap = Some(('|', '|'));
1677 (
1678 G::Matrix {
1679 alignment: self
1680 .optional_alignment()?
1681 .unwrap_or(ColumnAlignment::Center),
1682 },
1683 u16::MAX,
1684 GroupingKind::Matrix {
1685 ty: MatrixType::Vertical,
1686 column_spec: true,
1687 },
1688 )
1689 }
1690 "Vmatrix" => {
1691 wrap = Some(('‖', '‖'));
1692 (
1693 G::Matrix {
1694 alignment: ColumnAlignment::Center,
1695 },
1696 u16::MAX,
1697 GroupingKind::Matrix {
1698 ty: MatrixType::DoubleVertical,
1699 column_spec: false,
1700 },
1701 )
1702 }
1703 "Vmatrix*" => {
1704 wrap = Some(('‖', '‖'));
1705 (
1706 G::Matrix {
1707 alignment: self
1708 .optional_alignment()?
1709 .unwrap_or(ColumnAlignment::Center),
1710 },
1711 u16::MAX,
1712 GroupingKind::Matrix {
1713 ty: MatrixType::DoubleVertical,
1714 column_spec: true,
1715 },
1716 )
1717 }
1718 "Bmatrix" => {
1719 wrap = Some(('{', '}'));
1720 (
1721 G::Matrix {
1722 alignment: ColumnAlignment::Center,
1723 },
1724 u16::MAX,
1725 GroupingKind::Matrix {
1726 ty: MatrixType::Braces,
1727 column_spec: false,
1728 },
1729 )
1730 }
1731 "Bmatrix*" => {
1732 wrap = Some(('{', '}'));
1733 (
1734 G::Matrix {
1735 alignment: self
1736 .optional_alignment()?
1737 .unwrap_or(ColumnAlignment::Center),
1738 },
1739 u16::MAX,
1740 GroupingKind::Matrix {
1741 ty: MatrixType::Braces,
1742 column_spec: true,
1743 },
1744 )
1745 }
1746 "cases" => (
1747 G::Cases { left: true },
1748 1,
1749 GroupingKind::Cases {
1750 left: true,
1751 display: false,
1752 },
1753 ),
1754 "dcases" => {
1755 style = Some(S::Display);
1756 (
1757 G::Cases { left: true },
1758 1,
1759 GroupingKind::Cases {
1760 left: true,
1761 display: true,
1762 },
1763 )
1764 }
1765 "rcases" => (
1766 G::Cases { left: false },
1767 1,
1768 GroupingKind::Cases {
1769 left: false,
1770 display: false,
1771 },
1772 ),
1773 "drcases" => {
1774 style = Some(S::Display);
1775 (
1776 G::Cases { left: false },
1777 1,
1778 GroupingKind::Cases {
1779 left: false,
1780 display: true,
1781 },
1782 )
1783 }
1784 "equation" => (
1785 G::Equation { eq_numbers: true },
1786 0,
1787 GroupingKind::Equation { eq_numbers: true },
1788 ),
1789 "equation*" => (
1790 G::Equation { eq_numbers: false },
1791 0,
1792 GroupingKind::Equation { eq_numbers: false },
1793 ),
1794 "align" => (
1795 G::Align { eq_numbers: true },
1796 u16::MAX,
1797 GroupingKind::Align { eq_numbers: true },
1798 ),
1799 "align*" => (
1800 G::Align { eq_numbers: false },
1801 u16::MAX,
1802 GroupingKind::Align { eq_numbers: false },
1803 ),
1804 "aligned" => (G::Aligned, u16::MAX, GroupingKind::Aligned),
1805 "gather" => (
1806 G::Gather { eq_numbers: true },
1807 0,
1808 GroupingKind::Gather { eq_numbers: true },
1809 ),
1810 "gather*" => (
1811 G::Gather { eq_numbers: false },
1812 0,
1813 GroupingKind::Gather { eq_numbers: false },
1814 ),
1815 "gathered" => (G::Gathered, 0, GroupingKind::Gathered),
1816 "alignat" => {
1817 let pairs = match lex::argument(&mut self.content)? {
1818 Argument::Group(mut content) => lex::unsigned_integer(&mut content),
1819 _ => Err(ErrorKind::Argument),
1820 }? as u16;
1821 (
1822 G::Alignat {
1823 pairs,
1824 eq_numbers: true,
1825 },
1826 (pairs * 2).saturating_sub(1),
1827 GroupingKind::Alignat { eq_numbers: true },
1828 )
1829 }
1830 "alignat*" => {
1831 let pairs = match lex::argument(&mut self.content)? {
1832 Argument::Group(mut content) => lex::unsigned_integer(&mut content),
1833 _ => Err(ErrorKind::Argument),
1834 }? as u16;
1835 (
1836 G::Alignat {
1837 pairs,
1838 eq_numbers: false,
1839 },
1840 (pairs * 2).saturating_sub(1),
1841 GroupingKind::Alignat { eq_numbers: false },
1842 )
1843 }
1844 "alignedat" => {
1845 let pairs = match lex::argument(&mut self.content)? {
1846 Argument::Group(mut content) => lex::unsigned_integer(&mut content),
1847 _ => Err(ErrorKind::Argument),
1848 }? as u16;
1849 (
1850 G::Alignedat { pairs },
1851 (pairs * 2).saturating_sub(1),
1852 GroupingKind::Alignedat,
1853 )
1854 }
1855 "subarray" => {
1856 let alignment = match lex::argument(&mut self.content)? {
1857 Argument::Group("l") => ColumnAlignment::Left,
1858 Argument::Group("c") => ColumnAlignment::Center,
1859 Argument::Group("r") => ColumnAlignment::Right,
1860 _ => return Err(ErrorKind::Argument),
1861 };
1862 (G::SubArray { alignment }, 0, GroupingKind::SubArray)
1863 }
1864 "multline" => (G::Multline, 0, GroupingKind::Multline),
1865 "split" => (G::Split, 1, GroupingKind::Split),
1866 _ => return Err(ErrorKind::Environment),
1867 };
1868
1869 let wrap_used = if let Some((left, right)) = wrap {
1870 self.buffer
1871 .push(I::Event(E::Begin(G::LeftRight(Some(left), Some(right)))));
1872 true
1873 } else {
1874 false
1875 };
1876
1877 let horizontal_lines = lex::horizontal_lines(&mut self.content);
1878 let content = lex::group_content(&mut self.content, grouping_kind)?;
1879 self.buffer.push(I::Event(E::Begin(environment)));
1880 if let Some(style) = style {
1881 self.buffer.push(I::Event(E::StateChange(SC::Style(style))));
1882 }
1883 if !horizontal_lines.is_empty() {
1884 self.buffer
1885 .push(I::Event(E::EnvironmentFlow(EnvironmentFlow::StartLines {
1886 lines: horizontal_lines,
1887 })));
1888 }
1889 self.buffer.extend([
1890 I::SubGroup {
1891 content,
1892 allowed_alignment_count: Some(AlignmentCount::new(align_count)),
1893 },
1894 I::Event(E::End),
1895 ]);
1896
1897 if wrap_used {
1898 self.buffer.push(I::Event(E::End));
1899 }
1900 return Ok(());
1901 }
1902 "end" => return Err(ErrorKind::UnbalancedGroup(None)),
1903 "\\" | "cr"
1904 if self.state.allowed_alignment_count.is_some()
1905 && !self.state.handling_argument =>
1906 {
1907 self.state.allowed_alignment_count.as_mut().unwrap().reset();
1908 let additional_space =
1909 if let Some(mut arg) = lex::optional_argument(&mut self.content) {
1910 Some(lex::dimension(&mut arg)?)
1911 } else {
1912 None
1913 };
1914
1915 let horizontal_lines = lex::horizontal_lines(&mut self.content);
1916 E::EnvironmentFlow(EnvironmentFlow::NewLine {
1917 spacing: additional_space,
1918 horizontal_lines,
1919 })
1920 }
1921 "\\" | "cr" => return Err(ErrorKind::NewLine),
1922
1923 cs if control_sequence_delimiter_map(cs).is_some() => {
1925 let (content, ty) = control_sequence_delimiter_map(cs).unwrap();
1926 E::Content(C::Delimiter {
1927 content,
1928 size: None,
1929 ty,
1930 })
1931 }
1932
1933 c if c.trim_start().is_empty() => E::Content(C::Text(" ")),
1935
1936 "def" => {
1938 let (cs, parameter_text, replacement_text) = lex::definition(&mut self.content)?;
1939 self.state.skip_scripts = true;
1940 return self
1941 .macro_context
1942 .define(cs, parameter_text, replacement_text);
1943 }
1944 "let" => {
1945 let (cs, token) = lex::let_assignment(&mut self.content)?;
1946 self.state.skip_scripts = true;
1947 self.macro_context.assign(cs, token);
1948 return Ok(());
1949 }
1950 "futurelet" => {
1951 let (cs, token, rest) = lex::futurelet_assignment(&mut self.content)?;
1952 self.state.skip_scripts = true;
1953 self.macro_context.assign(cs, token);
1954 self.content = rest;
1955
1956 return Ok(());
1957 }
1958 "newcommand" => return self.new_command(Some(false)),
1959 "renewcommand" => return self.new_command(Some(true)),
1960 "providecommand" => return self.new_command(None),
1961 _ => return Err(ErrorKind::UnknownPrimitive),
1962 };
1963 self.buffer.push(I::Event(event));
1964 Ok(())
1965 }
1966
1967 fn sized_delim(&mut self, size: DelimiterSize) -> InnerResult<()> {
1969 let current = &mut self.content;
1970 let (content, ty) = lex::delimiter(current)?;
1971 self.buffer.push(I::Event(E::Content(C::Delimiter {
1972 content,
1973 size: Some(size),
1974 ty,
1975 })));
1976 Ok(())
1977 }
1978
1979 fn atom_group(&mut self, class: AtomClass) -> InnerResult<()> {
1994 let argument = lex::argument(&mut self.content)?;
1995
1996 let single_char: Option<char> = match argument {
2000 Argument::Token(Token::Character(char_)) => Some(char_.into()),
2001 Argument::Group(s) => {
2002 let s = s.trim();
2003 let mut chars = s.chars();
2004 let first = chars.next();
2005 match (first, chars.next()) {
2006 (Some(c), None) => Some(c),
2007 _ => None,
2008 }
2009 }
2010 Argument::Token(Token::ControlSequence(_)) => None,
2011 };
2012
2013 if let Some(c) = single_char {
2014 let event = match class {
2015 AtomClass::Ord => ordinary(c),
2016 AtomClass::Op => E::Content(C::LargeOp {
2017 content: c,
2018 small: false,
2019 }),
2020 AtomClass::Bin => binary(c),
2021 AtomClass::Rel => relation(c),
2022 AtomClass::Open => E::Content(C::Delimiter {
2023 content: c,
2024 size: None,
2025 ty: DelimiterType::Open,
2026 }),
2027 AtomClass::Close => E::Content(C::Delimiter {
2028 content: c,
2029 size: None,
2030 ty: DelimiterType::Close,
2031 }),
2032 AtomClass::Punct => E::Content(C::Punctuation(c)),
2033 AtomClass::Inner => ordinary(c),
2034 };
2035 self.buffer.push(I::Event(event));
2036 return Ok(());
2037 }
2038
2039 if matches!(class, AtomClass::Op) {
2048 if let Argument::Group(content) = argument {
2049 self.buffer.push(I::Event(E::Content(C::Function(content))));
2050 return Ok(());
2051 }
2052 }
2053
2054 self.buffer.push(I::Event(E::Begin(G::Normal)));
2055 self.handle_argument(argument)?;
2056 self.buffer.push(I::Event(E::End));
2057 Ok(())
2058 }
2059
2060 fn font_group(&mut self, font: Option<Font>) -> InnerResult<()> {
2062 let argument = lex::argument(&mut self.content)?;
2063 self.buffer.extend([
2064 I::Event(E::Begin(G::Normal)),
2065 I::Event(E::StateChange(SC::Font(font))),
2066 ]);
2067 match argument {
2068 Argument::Token(token) => {
2069 match token {
2070 Token::ControlSequence(cs) => self.handle_primitive(cs)?,
2071 Token::Character(c) => self.handle_char_token(c)?,
2072 };
2073 }
2074 Argument::Group(group) => {
2075 self.buffer.push(I::SubGroup {
2076 content: group,
2077 allowed_alignment_count: None,
2078 });
2079 }
2080 };
2081 self.buffer.push(I::Event(E::End));
2082 Ok(())
2083 }
2084
2085 fn accent(&mut self, accent: char, stretchy: bool) -> InnerResult<()> {
2087 let argument = lex::argument(&mut self.content)?;
2088 self.buffer.push(I::Event(E::Script {
2089 ty: ST::Superscript,
2090 position: SP::AboveBelow,
2091 }));
2092 self.handle_argument(argument)?;
2093 self.buffer.push(I::Event(E::Content(C::Ordinary {
2094 content: accent,
2095 stretchy,
2096 })));
2097 Ok(())
2098 }
2099
2100 fn underscript(&mut self, content: char) -> InnerResult<()> {
2102 let argument = lex::argument(&mut self.content)?;
2103 self.buffer.push(I::Event(E::Script {
2104 ty: ST::Subscript,
2105 position: SP::AboveBelow,
2106 }));
2107 self.handle_argument(argument)?;
2108 self.buffer.push(I::Event(E::Content(C::Ordinary {
2109 content,
2110 stretchy: true,
2111 })));
2112
2113 Ok(())
2114 }
2115
2116 fn large_op(&mut self, op: char, movable: bool) -> E<'store> {
2117 self.state.allow_script_modifiers = true;
2118 self.state.script_position = if movable { SP::Movable } else { SP::Right };
2119 E::Content(C::LargeOp {
2120 content: op,
2121 small: false,
2122 })
2123 }
2124
2125 fn font_change(&mut self, font: Font) -> E<'store> {
2126 self.state.skip_scripts = true;
2127 E::StateChange(SC::Font(Some(font)))
2128 }
2129
2130 fn style_change(&mut self, style: S) -> E<'store> {
2131 self.state.skip_scripts = true;
2132 E::StateChange(SC::Style(style))
2133 }
2134
2135 fn text_argument(&mut self, font: Option<Font>) -> InnerResult<()> {
2136 let argument = lex::argument(&mut self.content)?;
2137 let text = match argument {
2138 Argument::Token(Token::Character(c)) => c.as_str(),
2139 Argument::Group(inner) => inner,
2140 _ => return Err(ErrorKind::ControlSequenceAsArgument),
2141 };
2142 if let Some(font) = font {
2143 self.buffer.extend([
2144 I::Event(E::Begin(G::Normal)),
2145 I::Event(E::StateChange(SC::Font(Some(font)))),
2146 I::Event(E::Content(C::Text(text))),
2147 I::Event(E::End),
2148 ]);
2149 } else {
2150 self.buffer.push(I::Event(E::Content(C::Text(text))));
2151 }
2152 Ok(())
2153 }
2154
2155 fn fraction_like(
2156 &mut self,
2157 open: Option<char>,
2158 close: Option<char>,
2159 bar_size: Option<Dimension>,
2160 style: Option<S>,
2161 ) -> InnerResult<()> {
2162 let open_close_group = open.is_some() || close.is_some();
2163 if open_close_group {
2164 self.buffer
2165 .push(I::Event(E::Begin(G::LeftRight(open, close))));
2166 }
2167 if let Some(style) = style {
2168 if !open_close_group {
2169 self.buffer.push(I::Event(E::Begin(G::Normal)));
2170 }
2171 self.buffer.push(I::Event(E::StateChange(SC::Style(style))));
2172 };
2173
2174 self.buffer.push(I::Event(E::Visual(V::Fraction(bar_size))));
2175 let numerator = lex::argument(&mut self.content)?;
2176 self.handle_argument(numerator)?;
2177 let denominator = lex::argument(&mut self.content)?;
2178 self.handle_argument(denominator)?;
2179 if open_close_group || style.is_some() {
2180 self.buffer.push(I::Event(E::End));
2181 }
2182
2183 Ok(())
2184 }
2185
2186 fn array_environment(&mut self) -> InnerResult<(G, u16)> {
2187 let Argument::Group(array_columns_str) = lex::argument(&mut self.content)? else {
2188 return Err(ErrorKind::Argument);
2189 };
2190
2191 let mut column_count: u16 = 0;
2192 let mut contains_column = false;
2193 let array_columns = array_columns_str
2194 .chars()
2195 .map(|c| {
2196 column_count += 1;
2197 Ok(match c {
2198 'c' => {
2199 contains_column = true;
2200 AC::Column(ColumnAlignment::Center)
2201 }
2202 'l' => {
2203 contains_column = true;
2204 AC::Column(ColumnAlignment::Left)
2205 }
2206 'r' => {
2207 contains_column = true;
2208 AC::Column(ColumnAlignment::Right)
2209 }
2210 '|' => {
2211 column_count -= 1;
2212 AC::Separator(Line::Solid)
2213 }
2214 ':' => {
2215 column_count -= 1;
2216 AC::Separator(Line::Dashed)
2217 }
2218 _ => return Err(ErrorKind::Argument),
2219 })
2220 })
2221 .collect::<Result<_, _>>()?;
2222
2223 if !contains_column {
2224 return Err(ErrorKind::ArrayNoColumns);
2225 }
2226
2227 Ok((G::Array(array_columns), column_count.saturating_sub(1)))
2228 }
2229
2230 fn optional_alignment(&mut self) -> InnerResult<Option<ColumnAlignment>> {
2231 let alignment = lex::optional_argument(&mut self.content);
2232 Ok(match alignment {
2233 Some("c") => Some(ColumnAlignment::Center),
2234 Some("l") => Some(ColumnAlignment::Left),
2235 Some("r") => Some(ColumnAlignment::Right),
2236 None => None,
2237 _ => return Err(ErrorKind::Argument),
2238 })
2239 }
2240
2241 fn new_command(&mut self, should_already_exist: Option<bool>) -> InnerResult<()> {
2242 let mut group = lex::brace_argument(&mut self.content)?;
2243 let cs = lex::control_sequence(&mut group)?;
2244
2245 if should_already_exist.is_some_and(|sae| sae != self.macro_context.contains(cs)) {
2246 return Err(if should_already_exist.unwrap() {
2247 ErrorKind::MacroNotDefined
2248 } else {
2249 ErrorKind::MacroAlreadyDefined
2250 });
2251 }
2252
2253 let arg_count = (lex::optional_argument(&mut self.content).ok_or(ErrorKind::Argument)?)
2254 .parse::<u8>()
2255 .map_err(|_| ErrorKind::Number)?;
2256 let first_arg_default = lex::optional_argument(&mut self.content);
2257 if arg_count > 9 && arg_count >= first_arg_default.is_some() as u8 {
2258 return Err(ErrorKind::TooManyParams);
2259 }
2260
2261 let replacement_text = lex::brace_argument(&mut self.content)?;
2262
2263 if self.macro_context.contains(cs) && should_already_exist.is_none() {
2264 return Ok(());
2265 }
2266 self.macro_context
2267 .insert_command(cs, arg_count, first_arg_default, replacement_text)?;
2268 Ok(())
2269 }
2270}
2271
2272#[inline]
2273fn ordinary(ident: char) -> E<'static> {
2274 E::Content(C::Ordinary {
2275 content: ident,
2276 stretchy: false,
2277 })
2278}
2279
2280#[inline]
2281fn relation(rel: char) -> E<'static> {
2282 E::Content(C::Relation {
2283 content: RelationContent::single_char(rel),
2284 small: false,
2285 })
2286}
2287
2288fn multirelation(first: char, second: char) -> E<'static> {
2289 E::Content(C::Relation {
2290 content: RelationContent::double_char(first, second),
2291 small: false,
2292 })
2293}
2294
2295#[inline]
2296fn binary(op: char) -> E<'static> {
2297 E::Content(C::BinaryOp {
2298 content: op,
2299 small: false,
2300 })
2301}
2302
2303#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2311enum AtomClass {
2312 Ord,
2313 Op,
2314 Bin,
2315 Rel,
2316 Open,
2317 Close,
2318 Punct,
2319 Inner,
2320}
2321
2322