use crate::parsing::prelude::*;
use crate::tree::{Container, ContainerType};
use std::mem;
#[derive(Debug)]
pub struct ParagraphStack<'t> {
log: slog::Logger,
current: Vec<Element<'t>>,
finished: Vec<Element<'t>>,
exceptions: Vec<ParseException<'t>>,
}
impl<'t> ParagraphStack<'t> {
#[inline]
pub fn new(log: &slog::Logger) -> Self {
ParagraphStack {
log: slog::Logger::clone(log),
current: Vec::new(),
finished: Vec::new(),
exceptions: Vec::new(),
}
}
#[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>) {
debug!(
self.log,
"Pushing element to stack";
"element" => element.name(),
);
self.current.push(element);
}
#[inline]
pub fn push_exceptions(&mut self, exceptions: &mut Vec<ParseException<'t>>) {
debug!(
self.log,
"Pushing exception to stack";
"exceptions-len" => exceptions.len(),
);
self.exceptions.append(exceptions);
}
pub fn build_paragraph(&mut self) -> Option<Element<'t>> {
debug!(
self.log,
"Building paragraph from current stack state";
"current-len" => self.current.len(),
);
if self.current.is_empty() {
trace!(
self.log,
"No paragraph created, no pending elements in stack",
);
return None;
}
let elements = mem::replace(&mut self.current, Vec::new());
let container = Container::new(ContainerType::Paragraph, elements);
let element = Element::Container(container);
Some(element)
}
pub fn end_paragraph(&mut self) {
debug!(
self.log,
"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!(
self.log,
"Converting paragraph parse stack into ParseResult",
);
self.end_paragraph();
let ParagraphStack {
log: _,
current: _,
finished: elements,
exceptions,
} = self;
ok!(elements, exceptions)
}
}