inline: keep track of lines ahead

Needed for attributes, as they cannot be parsed without backtracking.
Potentially we have to parse for attributes until the end of the block
before we can know if it is invalid attributes and we should instead
parse for other inline events.
This commit is contained in:
Noah Hellman 2023-02-25 16:41:21 +01:00
parent 2bcc6122ca
commit 7133de94bb

View file

@ -80,6 +80,8 @@ struct Input<'s> {
complete: bool, complete: bool,
/// Span of current line. /// Span of current line.
span_line: Span, span_line: Span,
/// Upcoming lines within the current block.
ahead: std::collections::VecDeque<Span>,
/// Span of current event. /// Span of current event.
span: Span, span: Span,
} }
@ -91,20 +93,40 @@ impl<'s> Input<'s> {
lexer: lex::Lexer::new(""), lexer: lex::Lexer::new(""),
complete: false, complete: false,
span_line: Span::new(0, 0), span_line: Span::new(0, 0),
ahead: std::collections::VecDeque::new(),
span: Span::empty_at(0), span: Span::empty_at(0),
} }
} }
fn feed_line(&mut self, line: Span, last: bool) { fn feed_line(&mut self, line: Span, last: bool) {
debug_assert!(!self.complete); debug_assert!(!self.complete);
self.lexer = lex::Lexer::new(line.of(self.src));
self.complete = last; self.complete = last;
if self.lexer.ahead().is_empty() {
if let Some(next) = self.ahead.pop_front() {
self.set_current_line(next);
self.ahead.push_back(line);
} else {
self.set_current_line(line);
}
} else {
self.ahead.push_back(line);
}
}
fn set_current_line(&mut self, line: Span) {
self.lexer = lex::Lexer::new(line.of(self.src));
self.span_line = line; self.span_line = line;
self.span = line.empty_before(); self.span = line.empty_before();
} }
fn reset(&mut self) { fn reset(&mut self) {
*self = Self::new(self.src); self.lexer = lex::Lexer::new("");
self.complete = false;
self.ahead.clear();
}
fn last(&self) -> bool {
self.complete && self.ahead.is_empty()
} }
fn eat(&mut self) -> Option<lex::Token> { fn eat(&mut self) -> Option<lex::Token> {
@ -960,8 +982,10 @@ impl<'s> Iterator for Parser<'s> {
.map_or(false, |ev| matches!(ev.kind, EventKind::Str)) .map_or(false, |ev| matches!(ev.kind, EventKind::Str))
{ {
if self.parse_event().is_none() { if self.parse_event().is_none() {
if self.input.complete { if self.input.last() {
break; break;
} else if let Some(l) = self.input.ahead.pop_front() {
self.input.set_current_line(l);
} else { } else {
return None; return None;
} }