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…
	
	Add table
		Add a link
		
	
		Reference in a new issue