inline: resume attr parsing when new lines received
instead of starting over for each new line
This commit is contained in:
parent
50205573d0
commit
1202160a88
2 changed files with 59 additions and 29 deletions
|
@ -239,6 +239,7 @@ impl<'s> std::fmt::Debug for Attributes<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Validator {
|
pub struct Validator {
|
||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue