use super::SymExpr;
pub struct ExprIter<'a> {
stack: Vec<&'a SymExpr>,
last_visited: Option<&'a SymExpr>,
}
impl<'a> ExprIter<'a> {
pub fn new(expr: &'a SymExpr) -> Self {
Self {
stack: vec![expr],
last_visited: None,
}
}
fn visit(&mut self) -> Option<&'a SymExpr> {
self.last_visited = Some(self.stack.pop()?);
self.last_visited
}
fn is_last_visited(&self, expr: &'a SymExpr) -> bool {
match self.last_visited {
Some(last_visited) => std::ptr::eq(last_visited, expr),
None => false,
}
}
}
impl<'a> Iterator for ExprIter<'a> {
type Item = &'a SymExpr;
fn next(&mut self) -> Option<Self::Item> {
loop {
let expr = self.stack.last()?;
match expr {
SymExpr::Primary(_) => return self.visit(),
SymExpr::Add(terms) => {
if terms.is_empty() || self.is_last_visited(terms.last().unwrap()) {
return self.visit();
}
for term in terms.iter().rev() {
self.stack.push(term);
}
},
SymExpr::Mul(factors) => {
if factors.is_empty() || self.is_last_visited(factors.last().unwrap()) {
return self.visit();
}
for factor in factors.iter().rev() {
self.stack.push(factor);
}
},
SymExpr::Exp(lhs, rhs) => {
if self.is_last_visited(rhs) {
return self.visit();
}
self.stack.push(rhs);
self.stack.push(lhs);
},
}
}
}
}