use crate::parsing::prelude::*;
use crate::tree::{AttributeMap, Container, ContainerType};
use std::mem;
#[derive(Debug, Default)]
pub struct ParagraphStack<'t> {
current: Vec<Element<'t>>,
finished: Vec<Element<'t>>,
errors: Vec<ParseError>,
}
impl<'t> ParagraphStack<'t> {
#[inline]
pub fn new() -> Self {
ParagraphStack::default()
}
#[inline]
pub fn current_empty(&self) -> bool {
self.current.is_empty()
}
#[inline]
pub fn reserve_elements(&mut self, additional: usize) {
self.current.reserve(additional);
}
#[inline]
pub fn push_element(&mut self, element: Element<'t>, paragraph_safe: bool) {
debug!(
"Pushing element {} to stack (paragraph safe: {}",
element.name(),
paragraph_safe,
);
if paragraph_safe {
self.current.push(element);
} else {
self.end_paragraph();
self.finished.push(element);
}
}
#[inline]
pub fn push_errors(&mut self, errors: &mut Vec<ParseError>) {
debug!("Pushing errors to stack (length {})", errors.len());
self.errors.append(errors);
}
#[inline]
pub fn pop_line_break(&mut self) {
trace!("Popping last element if Element::LineBreak");
if let Some(Element::LineBreak) = self.current.last() {
self.current.pop();
}
}
pub fn build_paragraph(&mut self) -> Option<Element<'t>> {
trace!(
"Building paragraph from current stack state (length {})",
self.current.len(),
);
if self.current.is_empty() {
trace!("No paragraph created, no pending elements in stack");
return None;
}
let elements = mem::take(&mut self.current);
let container =
Container::new(ContainerType::Paragraph, elements, AttributeMap::new());
let element = Element::Container(container);
Some(element)
}
pub fn end_paragraph(&mut self) {
trace!("Ending the current paragraph to push as a completed element");
if let Some(paragraph) = self.build_paragraph() {
self.finished.push(paragraph);
}
}
pub fn into_result<'r>(mut self) -> ParseResult<'r, 't, Vec<Element<'t>>> {
debug!("Converting paragraph parse stack into ParseResult");
self.end_paragraph();
let ParagraphStack {
current: _,
finished: elements,
errors,
} = self;
let paragraph_safe = elements.iter().all(|element| element.paragraph_safe());
ok!(paragraph_safe; elements, errors)
}
pub fn into_elements(mut self) -> Vec<Element<'t>> {
debug!("Converting paragraph parse stack into a Vec<Element>");
self.end_paragraph();
debug_assert!(
self.errors.is_empty(),
"Exceptions found in ParagraphStack::into_elements()!",
);
self.finished
}
}