1pub mod error;
9mod lex;
10mod macros;
11mod primitives;
12mod state;
13pub mod storage;
14mod tables;
15
16use std::ops::Range;
17
18use macros::MacroContext;
19
20use crate::event::{Event, Grouping, ScriptPosition, ScriptType};
21
22use self::{state::ParserState, storage::Storage};
23
24pub(crate) use error::{ErrorKind, InnerResult, ParserError};
25
26const MAX_EXPANSION_DEPTH: usize = 64;
31const MAX_EXPANSION_BYTES: usize = 1024 * 1024; #[derive(Debug)]
43pub struct Parser<'store> {
44 instruction_stack: Vec<Instruction<'store>>,
53
54 buffer: Vec<Instruction<'store>>,
59
60 macro_context: MacroContext<'store>,
62
63 storage: &'store bumpalo::Bump,
65
66 span_stack: SpanStack<'store>,
68}
69
70impl<'store> Parser<'store> {
71 pub fn new<'input>(input: &'input str, storage: &'store Storage) -> Self
73 where
74 'input: 'store,
75 {
76 let mut instruction_stack = Vec::with_capacity(32);
77 instruction_stack.push(Instruction::SubGroup {
78 content: input,
79 allowed_alignment_count: None,
80 });
81 let buffer = Vec::with_capacity(16);
82 Self {
83 instruction_stack,
84 buffer,
85 macro_context: MacroContext::new(),
86 storage: &storage.0,
87 span_stack: SpanStack::from_input(input),
88 }
89 }
90}
91
92impl<'store> Iterator for Parser<'store> {
93 type Item = Result<Event<'store>, ParserError>;
94
95 fn next(&mut self) -> Option<Self::Item> {
96 match self.instruction_stack.last_mut() {
97 Some(Instruction::Event(_)) => Some(Ok(self
98 .instruction_stack
99 .pop()
100 .and_then(|i| match i {
101 Instruction::Event(e) => Some(e),
102 _ => None,
103 })
104 .expect("there is something in the stack"))),
105 Some(Instruction::SubGroup { content, .. }) if content.trim_start().is_empty() => {
106 self.instruction_stack.pop();
107 self.next()
108 }
109 Some(Instruction::SubGroup {
110 content,
111 allowed_alignment_count,
112 ..
113 }) => {
114 let state = ParserState {
115 allowed_alignment_count: allowed_alignment_count.as_mut(),
116 ..Default::default()
117 };
118
119 let inner = InnerParser {
120 content,
121 buffer: &mut self.buffer,
122 state,
123 macro_context: &mut self.macro_context,
124 storage: self.storage,
125 span_stack: &mut self.span_stack,
126 };
127
128 let (desc, rest) = inner.parse_next();
129 *content = rest;
130
131 let script_event = match desc {
132 Err(e) => {
133 let content_str = *content;
134 return Some(Err(ParserError::new(
135 e,
136 content_str.as_ptr(),
137 &mut self.span_stack,
138 )));
139 }
140 Ok(Some((e, desc))) => {
141 if desc.subscript_start > desc.superscript_start {
142 let content = self.buffer.drain(desc.superscript_start..).rev();
143 let added_len = content.len();
144
145 self.instruction_stack.reserve(added_len);
146 let spare =
147 &mut self.instruction_stack.spare_capacity_mut()[..added_len];
148 let mut idx = desc.subscript_start - desc.superscript_start;
149
150 for e in content {
151 if idx == added_len {
152 idx = 0;
153 }
154 spare[idx].write(e);
155 idx += 1;
156 }
157
158 unsafe {
162 self.instruction_stack
163 .set_len(self.instruction_stack.len() + added_len)
164 };
165 } else {
166 self.instruction_stack
167 .extend(self.buffer.drain(desc.subscript_start..).rev());
168 }
169 Some(e)
170 }
171 Ok(None) => None,
172 };
173
174 self.instruction_stack.extend(self.buffer.drain(..).rev());
175 if let Some(e) = script_event {
176 self.instruction_stack.push(Instruction::Event(e));
177 }
178 self.next()
179 }
180 None => None,
181 }
182 }
183}
184
185#[derive(Debug)]
186struct InnerParser<'b, 'store> {
187 content: &'store str,
188 buffer: &'b mut Vec<Instruction<'store>>,
189 state: ParserState<'b>,
190 macro_context: &'b mut MacroContext<'store>,
191 storage: &'store bumpalo::Bump,
192 span_stack: &'b mut SpanStack<'store>,
193}
194
195impl<'b, 'store> InnerParser<'b, 'store> {
196 fn handle_argument(&mut self, argument: Argument<'store>) -> InnerResult<()> {
200 match argument {
201 Argument::Token(token) => {
202 self.state.handling_argument = true;
203 match token {
204 Token::ControlSequence(cs) => self.handle_primitive(cs)?,
205 Token::Character(c) => self.handle_char_token(c)?,
206 };
207 }
208 Argument::Group(group) => {
209 self.buffer.extend([
210 Instruction::Event(Event::Begin(Grouping::Normal)),
211 Instruction::SubGroup {
212 content: group,
213 allowed_alignment_count: None,
214 },
215 Instruction::Event(Event::End),
216 ]);
217 }
218 };
219 Ok(())
220 }
221
222 fn parse(&mut self) -> InnerResult<Option<(Event<'store>, ScriptDescriptor)>> {
231 let original_content = self.content.trim_start();
233 let token = match lex::token(&mut self.content) {
234 Ok(token) => token,
235 Err(ErrorKind::Token) => return Ok(None),
236 Err(e) => return Err(e),
237 };
238 match token {
239 Token::ControlSequence(cs) => {
240 if let Some(result) =
241 self.macro_context
242 .try_expand_in(cs, self.content, self.storage)
243 {
244 if self.span_stack.expansions.len() >= MAX_EXPANSION_DEPTH
245 || self.span_stack.total_expansion_bytes >= MAX_EXPANSION_BYTES
246 {
247 return Err(ErrorKind::MacroRecursionLimit);
248 }
249
250 let (new_content, arguments_consumed_length) = result?;
251 self.span_stack.total_expansion_bytes += new_content.len();
252
253 let call_site_length = cs.len() + arguments_consumed_length + 1;
254 self.span_stack
255 .add(new_content, original_content, call_site_length);
256
257 self.content = new_content;
258 return self.parse();
259 }
260
261 self.handle_primitive(cs)?
262 }
263 Token::Character(c) => self.handle_char_token(c)?,
264 };
265
266 if self.state.skip_scripts {
268 return Ok(None);
269 }
270
271 if self.state.allow_script_modifiers {
272 if let Some(limits) = lex::limit_modifiers(&mut self.content) {
273 if limits {
274 self.state.script_position = ScriptPosition::AboveBelow;
275 } else {
276 self.state.script_position = ScriptPosition::Right;
277 }
278 }
279 }
280
281 self.content = self.content.trim_start();
282 let subscript_first = match self.content.chars().next() {
283 Some('^') => false,
284 Some('_') => true,
285 _ => return Ok(None),
286 };
287 self.content = &self.content[1..];
288
289 let first_script_start = self.buffer.len();
290 let arg = lex::argument(&mut self.content)?;
291 self.handle_argument(arg)?;
292 let second_script_start = self.buffer.len();
293 let next_char = self.content.chars().next();
294 if (next_char == Some('_') && !subscript_first)
295 || (next_char == Some('^') && subscript_first)
296 {
297 self.content = &self.content[1..];
298 let arg = lex::argument(&mut self.content)?;
299 self.handle_argument(arg)?;
300
301 match self.content.chars().next() {
302 Some('_') => return Err(ErrorKind::DoubleSubscript),
303 Some('^') => return Err(ErrorKind::DoubleSuperscript),
304 _ => {}
305 }
306 } else if next_char == Some('_') || next_char == Some('^') {
307 return Err(if subscript_first {
308 ErrorKind::DoubleSubscript
309 } else {
310 ErrorKind::DoubleSuperscript
311 });
312 }
313 let second_script_end = self.buffer.len();
314
315 Ok(Some(if second_script_start == second_script_end {
316 if subscript_first {
317 (
318 Event::Script {
319 ty: ScriptType::Subscript,
320 position: self.state.script_position,
321 },
322 ScriptDescriptor {
323 subscript_start: first_script_start,
324 superscript_start: second_script_start,
325 },
326 )
327 } else {
328 (
329 Event::Script {
330 ty: ScriptType::Superscript,
331 position: self.state.script_position,
332 },
333 ScriptDescriptor {
334 subscript_start: second_script_start,
335 superscript_start: first_script_start,
336 },
337 )
338 }
339 } else {
340 (
341 Event::Script {
342 ty: ScriptType::SubSuperscript,
343 position: self.state.script_position,
344 },
345 if subscript_first {
346 ScriptDescriptor {
347 subscript_start: first_script_start,
348 superscript_start: second_script_start,
349 }
350 } else {
351 ScriptDescriptor {
352 subscript_start: second_script_start,
353 superscript_start: first_script_start,
354 }
355 },
356 )
357 }))
358 }
359
360 fn parse_next(
361 mut self,
362 ) -> (
363 InnerResult<Option<(Event<'store>, ScriptDescriptor)>>,
364 &'store str,
365 ) {
366 (self.parse(), self.content)
367 }
368}
369
370struct ScriptDescriptor {
371 subscript_start: usize,
372 superscript_start: usize,
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
376pub(crate) enum Token<'a> {
377 ControlSequence(&'a str),
378 Character(CharToken<'a>),
379}
380
381#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
382pub(crate) struct CharToken<'a> {
383 char: &'a str,
384}
385
386impl<'a> CharToken<'a> {
388 fn from_str(s: &'a str) -> Self {
389 debug_assert!(
390 s.chars().next().is_some(),
391 "CharToken must be constructed from a non-empty string"
392 );
393 Self { char: s }
394 }
395
396 fn as_str(&self) -> &'a str {
397 self.char
398 }
399}
400
401impl From<CharToken<'_>> for char {
402 fn from(token: CharToken) -> char {
403 token.char.chars().next().unwrap()
404 }
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
408enum Argument<'a> {
409 Token(Token<'a>),
410 Group(&'a str),
411}
412
413#[derive(Debug, Clone)]
414enum Instruction<'a> {
415 Event(Event<'a>),
417 SubGroup {
419 content: &'a str,
420 allowed_alignment_count: Option<AlignmentCount>,
421 },
422}
423
424#[derive(Debug, Clone)]
425struct AlignmentCount {
426 count: u16,
427 max: u16,
428}
429
430impl AlignmentCount {
431 fn new(max: u16) -> Self {
432 Self { count: 0, max }
433 }
434
435 fn reset(&mut self) {
436 self.count = 0;
437 }
438
439 fn increment(&mut self) {
440 self.count += 1;
441 }
442
443 fn can_increment(&self) -> bool {
444 self.count < self.max
445 }
446}
447
448#[derive(Debug, Clone)]
452struct SpanStack<'store> {
453 input: &'store str,
455 expansions: Vec<ExpansionSpan<'store>>,
457 total_expansion_bytes: usize,
459}
460
461impl<'store> SpanStack<'store> {
462 fn from_input(input: &'store str) -> Self {
463 Self {
464 input,
465 expansions: Vec::new(),
466 total_expansion_bytes: 0,
467 }
468 }
469
470 fn add(&mut self, full_expansion: &'store str, call_site: &str, call_site_length: usize) {
471 let call_site_start = self.reach_original_call_site(call_site.as_ptr());
472 let expansion_length = (call_site_length as isize
473 - (call_site.len() as isize - full_expansion.len() as isize))
474 as usize;
475
476 self.expansions.push(ExpansionSpan {
477 full_expansion,
478 expansion_length,
479 call_site_in_origin: call_site_start..call_site_start + call_site_length,
480 });
481 }
482
483 fn reach_original_call_site(&mut self, substr_start: *const u8) -> usize {
486 let ptr_val = substr_start as isize;
487
488 while let Some(expansion) = self.expansions.last() {
489 let expansion_ptr = expansion.full_expansion.as_ptr() as isize;
490
491 if ptr_val >= expansion_ptr
492 && ptr_val <= expansion_ptr + expansion.full_expansion.len() as isize
493 {
494 return (ptr_val - expansion_ptr) as usize;
495 }
496 self.expansions.pop();
497 }
498 let input_start = self.input.as_ptr() as isize;
499
500 assert!(ptr_val >= input_start && ptr_val <= input_start + self.input.len() as isize);
501 (ptr_val - input_start) as usize
502 }
503}
504
505#[derive(Debug, Clone)]
514struct ExpansionSpan<'a> {
515 full_expansion: &'a str,
519 expansion_length: usize,
522 call_site_in_origin: Range<usize>,
527}
528
529#[cfg(test)]
530mod tests {
531 use crate::event::{Content, DelimiterType, Dimension, DimensionUnit, RelationContent, Visual};
532
533 use super::*;
534
535 #[test]
536 fn substr_instructions() {
537 let store = Storage::new();
538 let parser = Parser::new("\\bar{y}", &store);
539
540 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
541
542 assert_eq!(
543 events,
544 vec![
545 Event::Script {
546 ty: ScriptType::Superscript,
547 position: ScriptPosition::AboveBelow
548 },
549 Event::Begin(Grouping::Normal),
550 Event::Content(Content::Ordinary {
551 content: 'y',
552 stretchy: false
553 }),
554 Event::End,
555 Event::Content(Content::Ordinary {
556 content: '‾',
557 stretchy: false,
558 }),
559 ]
560 );
561 }
562
563 #[test]
564 fn subsuperscript() {
565 let store = Storage::new();
566 let parser = Parser::new(r"a^{1+3}_2", &store);
567 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
568
569 assert_eq!(
570 events,
571 vec![
572 Event::Script {
573 ty: ScriptType::SubSuperscript,
574 position: ScriptPosition::Right
575 },
576 Event::Content(Content::Ordinary {
577 content: 'a',
578 stretchy: false,
579 }),
580 Event::Content(Content::Number("2")),
581 Event::Begin(Grouping::Normal),
582 Event::Content(Content::Number("1")),
583 Event::Content(Content::BinaryOp {
584 content: '+',
585 small: false
586 }),
587 Event::Content(Content::Number("3")),
588 Event::End,
589 ]
590 );
591 }
592 #[test]
593 fn subscript_torture() {
594 let store = Storage::new();
595 let parser = Parser::new(r"a_{5_{5_{5_{5_{5_{5_{5_{5_{5_{5_{5_5}}}}}}}}}}}", &store);
596 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
597
598 assert_eq!(
599 events,
600 vec![
601 Event::Script {
602 ty: ScriptType::Subscript,
603 position: ScriptPosition::Right
604 },
605 Event::Content(Content::Ordinary {
606 content: 'a',
607 stretchy: false,
608 }),
609 Event::Begin(Grouping::Normal),
610 Event::Script {
611 ty: ScriptType::Subscript,
612 position: ScriptPosition::Right
613 },
614 Event::Content(Content::Number("5")),
615 Event::Begin(Grouping::Normal),
616 Event::Script {
617 ty: ScriptType::Subscript,
618 position: ScriptPosition::Right
619 },
620 Event::Content(Content::Number("5")),
621 Event::Begin(Grouping::Normal),
622 Event::Script {
623 ty: ScriptType::Subscript,
624 position: ScriptPosition::Right
625 },
626 Event::Content(Content::Number("5")),
627 Event::Begin(Grouping::Normal),
628 Event::Script {
629 ty: ScriptType::Subscript,
630 position: ScriptPosition::Right
631 },
632 Event::Content(Content::Number("5")),
633 Event::Begin(Grouping::Normal),
634 Event::Script {
635 ty: ScriptType::Subscript,
636 position: ScriptPosition::Right
637 },
638 Event::Content(Content::Number("5")),
639 Event::Begin(Grouping::Normal),
640 Event::Script {
641 ty: ScriptType::Subscript,
642 position: ScriptPosition::Right
643 },
644 Event::Content(Content::Number("5")),
645 Event::Begin(Grouping::Normal),
646 Event::Script {
647 ty: ScriptType::Subscript,
648 position: ScriptPosition::Right
649 },
650 Event::Content(Content::Number("5")),
651 Event::Begin(Grouping::Normal),
652 Event::Script {
653 ty: ScriptType::Subscript,
654 position: ScriptPosition::Right
655 },
656 Event::Content(Content::Number("5")),
657 Event::Begin(Grouping::Normal),
658 Event::Script {
659 ty: ScriptType::Subscript,
660 position: ScriptPosition::Right
661 },
662 Event::Content(Content::Number("5")),
663 Event::Begin(Grouping::Normal),
664 Event::Script {
665 ty: ScriptType::Subscript,
666 position: ScriptPosition::Right
667 },
668 Event::Content(Content::Number("5")),
669 Event::Begin(Grouping::Normal),
670 Event::Script {
671 ty: ScriptType::Subscript,
672 position: ScriptPosition::Right
673 },
674 Event::Content(Content::Number("5")),
675 Event::Content(Content::Number("5")),
676 Event::End,
677 Event::End,
678 Event::End,
679 Event::End,
680 Event::End,
681 Event::End,
682 Event::End,
683 Event::End,
684 Event::End,
685 Event::End,
686 Event::End,
687 ]
688 )
689 }
690
691 #[test]
692 fn fraction() {
693 let store = Storage::new();
694 let parser = Parser::new(r"\frac{1}{2}_2^4", &store);
695 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
696
697 assert_eq!(
698 events,
699 vec![
700 Event::Script {
701 ty: ScriptType::SubSuperscript,
702 position: ScriptPosition::Right
703 },
704 Event::Visual(Visual::Fraction(None)),
705 Event::Begin(Grouping::Normal),
706 Event::Content(Content::Number("1")),
707 Event::End,
708 Event::Begin(Grouping::Normal),
709 Event::Content(Content::Number("2")),
710 Event::End,
711 Event::Content(Content::Number("2")),
712 Event::Content(Content::Number("4")),
713 ]
714 );
715 }
716
717 #[test]
718 fn multidigit_number() {
719 let store = Storage::new();
720 let parser = Parser::new("123", &store);
721 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
722
723 assert_eq!(events, vec![Event::Content(Content::Number("123"))]);
724 }
725
726 #[test]
727 fn non_greedy_number_argument() {
728 let store = Storage::new();
732 let parser = Parser::new(r"\frac12", &store);
733 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
734
735 assert_eq!(
736 events,
737 vec![
738 Event::Visual(Visual::Fraction(None)),
739 Event::Content(Content::Number("1")),
740 Event::Content(Content::Number("2")),
741 ]
742 );
743 }
744
745 #[test]
746 fn non_greedy_number_argument_sqrt() {
747 let store = Storage::new();
749 let parser = Parser::new(r"\sqrt12", &store);
750 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
751
752 assert_eq!(
753 events,
754 vec![
755 Event::Visual(Visual::SquareRoot),
756 Event::Content(Content::Number("1")),
757 Event::Content(Content::Number("2")),
758 ]
759 );
760 }
761
762 #[test]
763 fn non_greedy_decimal_argument() {
764 let store = Storage::new();
768 let parser = Parser::new(r"\frac1.5{x}", &store);
769 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
770
771 assert_eq!(
772 events,
773 vec![
774 Event::Visual(Visual::Fraction(None)),
775 Event::Content(Content::Number("1")),
776 Event::Content(Content::Punctuation('.')),
777 Event::Content(Content::Number("5")),
778 Event::Begin(Grouping::Normal),
779 Event::Content(Content::Ordinary {
780 content: 'x',
781 stretchy: false
782 }),
783 Event::End,
784 ]
785 );
786 }
787
788 #[test]
789 fn error() {
790 let store = Storage::new();
791 let parser = Parser::new(
792 r"\def\blah#1#2{\fra#1#2} \def\abc#1{\blah{a}#1} \abc{b}",
793 &store,
794 );
795 let events = parser.collect::<Vec<_>>();
796
797 assert!(events[0].is_err());
798 }
799
800 #[test]
801 fn no_limits() {
802 let store = Storage::new();
803 let parser = Parser::new(r#"\lim \nolimits _{x \to 0} f(x)"#, &store);
804 let events = parser.collect::<Result<Vec<_>, ParserError>>().unwrap();
805 assert_eq!(
806 events,
807 vec![
808 Event::Script {
809 ty: ScriptType::Subscript,
810 position: ScriptPosition::Right
811 },
812 Event::Content(Content::Function("lim")),
813 Event::Begin(Grouping::Normal),
814 Event::Content(Content::Ordinary {
815 content: 'x',
816 stretchy: false
817 }),
818 Event::Content(Content::Relation {
819 content: RelationContent::single_char('→'),
820 small: false
821 }),
822 Event::Content(Content::Number("0")),
823 Event::End,
824 Event::Content(Content::Ordinary {
825 content: 'f',
826 stretchy: false
827 }),
828 Event::Content(Content::Delimiter {
829 content: '(',
830 size: None,
831 ty: DelimiterType::Open
832 }),
833 Event::Content(Content::Ordinary {
834 content: 'x',
835 stretchy: false
836 }),
837 Event::Content(Content::Delimiter {
838 content: ')',
839 size: None,
840 ty: DelimiterType::Close
841 }),
842 ]
843 );
844 }
845
846 #[test]
847 fn struts() {
848 let store = Storage::new();
849
850 for (input, height) in [(r"\mathstrut", 0.7), (r"\strut", 1.0)] {
851 let events = Parser::new(input, &store)
852 .collect::<Result<Vec<_>, ParserError>>()
853 .unwrap();
854
855 assert_eq!(
856 events,
857 vec![Event::Space {
858 width: None,
859 height: Some(Dimension::new(height, DimensionUnit::Em)),
860 depth: None,
861 }]
862 );
863 }
864 }
865
866 #[test]
867 fn expansions_in_groups() {
868 let store = Storage::new();
869 let mut parser = Parser::new(
870 r"\def\abc#1{#1} {\abc{a} + \abc{b}} = c \shoulderror",
871 &store,
872 );
873 assert!(parser.by_ref().collect::<Result<Vec<_>, _>>().is_err());
874 assert!(parser.span_stack.expansions.is_empty());
875 }
876}
877
878