inline: get rid of verbatim state

This commit is contained in:
Noah Hellman 2022-12-11 21:43:22 +01:00
parent 8957907141
commit 81a4edb884
2 changed files with 82 additions and 97 deletions

View file

@ -63,8 +63,6 @@ pub struct Parser<I> {
lexer: lex::Lexer<I>, lexer: lex::Lexer<I>,
/// Span of current event. /// Span of current event.
span: Span, span: Span,
/// The kind, opener_len and opener_event of the current verbatim container if within one.
verbatim: Option<(Container, usize, usize)>,
/// Stack with kind and index of _potential_ openers for typesetting containers. /// Stack with kind and index of _potential_ openers for typesetting containers.
typesets: Vec<(Container, usize)>, typesets: Vec<(Container, usize)>,
/// Stack with index of _potential_ span/link openers. /// Stack with index of _potential_ span/link openers.
@ -80,7 +78,6 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
Self { Self {
lexer: lex::Lexer::new(chars), lexer: lex::Lexer::new(chars),
span: Span::new(0, 0), span: Span::new(0, 0),
verbatim: None,
typesets: Vec::new(), typesets: Vec::new(),
spans: Vec::new(), spans: Vec::new(),
events: std::collections::VecDeque::new(), events: std::collections::VecDeque::new(),
@ -118,18 +115,54 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
} }
fn parse_verbatim(&mut self, first: &lex::Token) -> Option<Event> { fn parse_verbatim(&mut self, first: &lex::Token) -> Option<Event> {
self.verbatim match first.kind {
.map(|(kind, opener_len, opener_event)| { lex::Kind::Seq(lex::Sequence::Dollar) => {
assert_eq!(self.events[opener_event].kind, EventKind::Enter(kind)); let math_opt = (first.len <= 2)
let kind = if matches!(first.kind, lex::Kind::Seq(lex::Sequence::Backtick)) .then(|| {
&& first.len == opener_len if let Some(lex::Token {
kind: lex::Kind::Seq(lex::Sequence::Backtick),
len,
}) = self.peek()
{
Some((
if first.len == 2 {
DisplayMath
} else {
InlineMath
},
*len,
))
} else {
None
}
})
.flatten();
if math_opt.is_some() {
self.eat(); // backticks
}
math_opt
}
lex::Kind::Seq(lex::Sequence::Backtick) => Some((Verbatim, first.len)),
_ => None,
}
.map(|(mut kind, opener_len)| {
let opener_event = self.events.len();
self.events.push_back(Event {
kind: EventKind::Enter(kind),
span: self.span,
});
let mut span_inner = Span::empty_at(self.span.end());
while let Some(t) = self.eat() {
if matches!(t.kind, lex::Kind::Seq(lex::Sequence::Backtick)) && t.len == opener_len
{ {
self.verbatim = None; if matches!(kind, Verbatim)
let kind = if matches!(kind, Verbatim)
&& matches!( && matches!(
self.lexer.peek().map(|t| &t.kind), self.lexer.peek().map(|t| &t.kind),
Some(lex::Kind::Open(Delimiter::BraceEqual)) Some(lex::Kind::Open(Delimiter::BraceEqual))
) { )
{
let mut ahead = self.lexer.inner().clone(); let mut ahead = self.lexer.inner().clone();
let mut end = false; let mut end = false;
let len = (&mut ahead) let len = (&mut ahead)
@ -146,64 +179,28 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
if len > 0 && end { if len > 0 && end {
self.lexer = lex::Lexer::new(ahead); self.lexer = lex::Lexer::new(ahead);
let span_format = Span::by_len(self.span.end() + "{=".len(), len); let span_format = Span::by_len(self.span.end() + "{=".len(), len);
self.events[opener_event].kind = EventKind::Enter(RawFormat); kind = RawFormat;
self.events[opener_event].kind = EventKind::Enter(kind);
self.events[opener_event].span = span_format; self.events[opener_event].span = span_format;
self.span = span_format; self.span = span_format;
RawFormat
} else {
Verbatim
} }
} else {
kind
};
EventKind::Exit(kind)
} else {
EventKind::Str
};
Event {
kind,
span: self.span,
}
})
.or_else(|| {
match first.kind {
lex::Kind::Seq(lex::Sequence::Dollar) => {
let math_opt = (first.len <= 2)
.then(|| {
if let Some(lex::Token {
kind: lex::Kind::Seq(lex::Sequence::Backtick),
len,
}) = self.peek()
{
Some((
if first.len == 2 {
DisplayMath
} else {
InlineMath
},
*len,
))
} else {
None
}
})
.flatten();
if math_opt.is_some() {
self.eat(); // backticks
}
math_opt
} }
lex::Kind::Seq(lex::Sequence::Backtick) => Some((Verbatim, first.len)), break;
_ => None,
} }
.map(|(kind, opener_len)| { span_inner = span_inner.extend(t.len);
self.verbatim = Some((kind, opener_len, self.events.len())); self.reset_span();
Event { }
kind: EventKind::Enter(kind),
span: self.span, self.events.push_back(Event {
} kind: EventKind::Str,
}) span: span_inner,
}) });
Event {
kind: EventKind::Exit(kind),
span: self.span,
}
})
} }
fn parse_span(&mut self, first: &lex::Token) -> Option<Event> { fn parse_span(&mut self, first: &lex::Token) -> Option<Event> {
@ -339,7 +336,6 @@ impl<I: Iterator<Item = char> + Clone> Iterator for Parser<I> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while self.events.is_empty() while self.events.is_empty()
|| !self.typesets.is_empty() || !self.typesets.is_empty()
|| self.verbatim.is_some() // might be raw format
|| self // for merge || self // for merge
.events .events
.back() .back()
@ -352,38 +348,27 @@ impl<I: Iterator<Item = char> + Clone> Iterator for Parser<I> {
} }
} }
self.events self.events.pop_front().map(|e| {
.pop_front() if matches!(e.kind, EventKind::Str) {
.map(|e| { // merge str events
if matches!(e.kind, EventKind::Str) { let mut span = e.span;
// merge str events while self
let mut span = e.span; .events
while self .front()
.events .map_or(false, |ev| matches!(ev.kind, EventKind::Str))
.front() {
.map_or(false, |ev| matches!(ev.kind, EventKind::Str)) let ev = self.events.pop_front().unwrap();
{ assert_eq!(span.end(), ev.span.start());
let ev = self.events.pop_front().unwrap(); span = span.union(ev.span);
assert_eq!(span.end(), ev.span.start());
span = span.union(ev.span);
}
Event {
kind: EventKind::Str,
span,
}
} else {
e
} }
}) Event {
.or_else(|| { kind: EventKind::Str,
self.verbatim.map(|(kind, _, _)| { span,
self.verbatim = None; }
Event { } else {
kind: EventKind::Exit(kind), e
span: self.span, }
} })
})
})
} }
} }

View file

@ -502,7 +502,7 @@ mod test {
#[test] #[test]
fn raw_inline() { fn raw_inline() {
test_parse!( test_parse!(
"`raw\nraw`{=format}", "``raw\nraw``{=format}",
Start(Paragraph, Attributes::none()), Start(Paragraph, Attributes::none()),
Start(RawInline { format: "format" }, Attributes::none()), Start(RawInline { format: "format" }, Attributes::none()),
Str("raw\nraw"), Str("raw\nraw"),