use std::fmt::{Display, Error, Formatter};
use log::trace;
#[derive(Debug, Default)]
pub struct ParseTreeStack<T: Display> {
pub stack: Vec<T>,
}
impl<T: Display> ParseTreeStack<T> {
pub fn new() -> Self {
Self { stack: Vec::new() }
}
pub fn push(&mut self, node: T) {
trace!("ParseTreeStack: Pushing node: {node}");
self.stack.push(node);
}
pub fn pop(&mut self) -> Option<T> {
let node = self.stack.pop();
node.inspect(|n| {
trace!("LRParseTreeStack: Popping node: {n}");
})
}
pub fn last(&self) -> Option<&T> {
self.stack.last()
}
pub fn split_off(&mut self, at: usize) -> Vec<T> {
self.stack.split_off(at)
}
pub fn pop_n(&mut self, n: usize, f: impl Fn(&T) -> bool) -> Vec<T> {
let mut len = 0;
let mut i = 0;
while i < n && len < self.stack.len() {
if f(&self.stack[self.stack.len() - 1 - len]) {
i += 1;
}
len += 1;
}
if len > self.stack.len() {
len = self.stack.len();
}
self.split_off(self.stack.len() - len)
}
pub fn len(&self) -> usize {
self.stack.len()
}
pub fn is_empty(&self) -> bool {
self.stack.is_empty()
}
pub(crate) fn pop_all(&mut self) -> Vec<T> {
let mut stack = Vec::new();
std::mem::swap(&mut stack, &mut self.stack);
stack
}
}
impl<T: Display> Display for ParseTreeStack<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
self.stack
.iter()
.rev()
.enumerate()
.try_for_each(|(i, e)| writeln!(f, "{i} - {e}"))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn init() {
let _ = env_logger::builder().is_test(true).try_init();
}
#[test]
fn test_push_pop() {
init();
let mut stack = ParseTreeStack::new();
stack.push("a");
stack.push("b");
stack.push("c");
assert_eq!(stack.pop(), Some("c"));
assert_eq!(stack.pop(), Some("b"));
assert_eq!(stack.pop(), Some("a"));
assert_eq!(stack.pop(), None);
}
#[test]
fn test_split_off() {
init();
let mut stack = ParseTreeStack::new();
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
let split = stack.split_off(2);
assert_eq!(split, vec!["c", "d", "e"]);
assert_eq!(stack.stack, vec!["a", "b"]);
}
#[test]
fn test_pop_3() {
init();
let mut stack = ParseTreeStack::new();
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
let split = stack.pop_n(3, |_| true);
assert_eq!(split, vec!["c", "d", "e"]);
assert_eq!(stack.stack, vec!["a", "b"]);
}
#[test]
fn test_pop_5() {
init();
let mut stack = ParseTreeStack::new();
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
let split = stack.pop_n(3, |_| false);
assert_eq!(split, vec!["a", "b", "c", "d", "e"]);
assert_eq!(stack.stack, Vec::<&str>::new());
}
#[test]
fn test_pop_n() {
init();
let mut stack = ParseTreeStack::new();
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
stack.push("e");
let split = stack.pop_n(3, |n| *n != "d");
assert_eq!(split, vec!["b", "c", "d", "e"]);
assert_eq!(stack.stack, vec!["a"]);
}
}