inline: resume attr parsing when new lines received

instead of starting over for each new line
This commit is contained in:
Noah Hellman 2023-03-30 19:51:50 +02:00
parent 50205573d0
commit 1202160a88
2 changed files with 59 additions and 29 deletions

View file

@ -239,6 +239,7 @@ impl<'s> std::fmt::Debug for Attributes<'s> {
} }
} }
#[derive(Clone)]
pub struct Validator { pub struct Validator {
state: State, state: State,
} }

View file

@ -197,6 +197,14 @@ struct VerbatimState {
non_whitespace_last: Option<(lex::Kind, usize)>, non_whitespace_last: Option<(lex::Kind, usize)>,
} }
#[derive(Clone)]
struct AttributesState {
elem_ty: AttributesElementType,
end_attr: usize,
valid_lines: usize,
validator: attr::Validator,
}
#[derive(Clone)] #[derive(Clone)]
enum AttributesElementType { enum AttributesElementType {
Container { e_placeholder: usize }, Container { e_placeholder: usize },
@ -214,7 +222,7 @@ pub struct Parser<'s> {
/// State if inside a verbatim container. /// State if inside a verbatim container.
verbatim: Option<VerbatimState>, verbatim: Option<VerbatimState>,
/// State if currently parsing potential attributes. /// State if currently parsing potential attributes.
attributes: Option<AttributesElementType>, attributes: Option<AttributesState>,
/// Storage of cow strs, used to reduce size of [`Container`]. /// Storage of cow strs, used to reduce size of [`Container`].
pub(crate) store_cowstrs: Vec<CowStr<'s>>, pub(crate) store_cowstrs: Vec<CowStr<'s>>,
/// Storage of attributes, used to reduce size of [`EventKind`]. /// Storage of attributes, used to reduce size of [`EventKind`].
@ -389,11 +397,11 @@ impl<'s> Parser<'s> {
fn parse_attributes(&mut self, first: &lex::Token) -> Option<ControlFlow> { fn parse_attributes(&mut self, first: &lex::Token) -> Option<ControlFlow> {
if first.kind == lex::Kind::Open(Delimiter::Brace) { if first.kind == lex::Kind::Open(Delimiter::Brace) {
let elem_ty = self if let Some(state) = self.attributes.take() {
.attributes self.resume_attributes(state, true, false)
.take() } else {
.unwrap_or(AttributesElementType::Word); self.ahead_attributes(AttributesElementType::Word, true)
self.ahead_attributes(elem_ty, true) }
} else { } else {
debug_assert!(self.attributes.is_none()); debug_assert!(self.attributes.is_none());
None None
@ -404,29 +412,50 @@ impl<'s> Parser<'s> {
&mut self, &mut self,
elem_ty: AttributesElementType, elem_ty: AttributesElementType,
opener_eaten: bool, opener_eaten: bool,
) -> Option<ControlFlow> {
let state = AttributesState {
elem_ty,
end_attr: self.input.span.end() - usize::from(opener_eaten),
valid_lines: 0,
validator: attr::Validator::new(),
};
self.resume_attributes(state, opener_eaten, true)
}
fn resume_attributes(
&mut self,
mut state: AttributesState,
opener_eaten: bool,
first: bool,
) -> Option<ControlFlow> { ) -> Option<ControlFlow> {
let start_attr = self.input.span.end() - usize::from(opener_eaten); let start_attr = self.input.span.end() - usize::from(opener_eaten);
debug_assert!(self.input.src[start_attr..].starts_with('{')); debug_assert!(self.input.src[start_attr..].starts_with('{'));
let mut end_attr = start_attr; let (mut line_next, mut line_start, mut line_end) = if first {
let mut line_next = 0; (0, start_attr, self.input.span_line.end())
let mut valid_lines = 0; } else {
let mut line_end = self.input.span_line.end(); let last = self.input.ahead.len() - 1;
(
self.input.ahead.len(),
self.input.ahead[last].start(),
self.input.ahead[last].end(),
)
};
{ {
let mut line_start = start_attr; let mut res = state.validator.parse(&self.input.src[line_start..line_end]);
let mut validator = attr::Validator::new();
let mut res = validator.parse(&self.input.src[line_start..line_end]);
loop { loop {
if let Some(len) = res.take() { if let Some(len) = res.take() {
if len == 0 { if len == 0 {
break; break;
} }
valid_lines = line_next; state.valid_lines = line_next;
end_attr = line_start + len; state.end_attr = line_start + len;
if self.input.src[end_attr..].starts_with('{') { if self.input.src[state.end_attr..].starts_with('{') {
line_start = end_attr; line_start = state.end_attr;
validator.restart(); state.validator.restart();
res = validator.parse(&self.input.src[end_attr..line_end]); res = state
.validator
.parse(&self.input.src[state.end_attr..line_end]);
} else { } else {
break; break;
} }
@ -434,12 +463,12 @@ impl<'s> Parser<'s> {
line_next += 1; line_next += 1;
line_start = l.start(); line_start = l.start();
line_end = l.end(); line_end = l.end();
res = validator.parse(l.of(self.input.src)); res = state.validator.parse(l.of(self.input.src));
} else if self.input.complete { } else if self.input.complete {
// no need to ask for more input // no need to ask for more input
break; break;
} else { } else {
self.attributes = Some(elem_ty); self.attributes = Some(state);
if opener_eaten { if opener_eaten {
self.input.span = Span::empty_at(start_attr); self.input.span = Span::empty_at(start_attr);
self.input.lexer = lex::Lexer::new( self.input.lexer = lex::Lexer::new(
@ -451,7 +480,7 @@ impl<'s> Parser<'s> {
} }
} }
if start_attr == end_attr { if start_attr == state.end_attr {
return None; return None;
} }
@ -459,10 +488,10 @@ impl<'s> Parser<'s> {
let attrs = { let attrs = {
let first = Span::new(start_attr, self.input.span_line.end()); let first = Span::new(start_attr, self.input.span_line.end());
let mut parser = attr::Parser::new(attr::Attributes::new()); let mut parser = attr::Parser::new(attr::Attributes::new());
for line in for line in std::iter::once(first)
std::iter::once(first).chain(self.input.ahead.iter().take(valid_lines).copied()) .chain(self.input.ahead.iter().take(state.valid_lines).copied())
{ {
let line = line.start()..usize::min(end_attr, line.end()); let line = line.start()..usize::min(state.end_attr, line.end());
parser.parse(&self.input.src[line]); parser.parse(&self.input.src[line]);
} }
parser.finish() parser.finish()
@ -472,20 +501,20 @@ impl<'s> Parser<'s> {
let l = self.input.ahead.pop_front().unwrap(); let l = self.input.ahead.pop_front().unwrap();
self.input.set_current_line(l); self.input.set_current_line(l);
} }
self.input.span = Span::new(start_attr, end_attr); self.input.span = Span::new(start_attr, state.end_attr);
self.input.lexer = lex::Lexer::new(&self.input.src[end_attr..line_end]); self.input.lexer = lex::Lexer::new(&self.input.src[state.end_attr..line_end]);
if !attrs.is_empty() { if !attrs.is_empty() {
let attr_index = self.store_attributes.len() as AttributesIndex; let attr_index = self.store_attributes.len() as AttributesIndex;
self.store_attributes.push(attrs); self.store_attributes.push(attrs);
let attr_event = Event { let attr_event = Event {
kind: EventKind::Attributes { kind: EventKind::Attributes {
container: matches!(elem_ty, AttributesElementType::Container { .. }), container: matches!(state.elem_ty, AttributesElementType::Container { .. }),
attrs: attr_index, attrs: attr_index,
}, },
span: self.input.span, span: self.input.span,
}; };
match elem_ty { match state.elem_ty {
AttributesElementType::Container { e_placeholder } => { AttributesElementType::Container { e_placeholder } => {
self.events[e_placeholder] = attr_event; self.events[e_placeholder] = attr_event;
if matches!(self.events[e_placeholder + 1].kind, EventKind::Str) { if matches!(self.events[e_placeholder + 1].kind, EventKind::Str) {