use super::{Location, Loc, Precedence, Op, MaybeExpr, Expr};
#[derive(Debug)]
pub struct Waiting {
expr: MaybeExpr,
op: Loc<Op>,
right: Precedence,
}
#[derive(Default, Debug)]
pub struct Stack {
ops: Vec<Waiting>,
expr: MaybeExpr,
}
impl Stack {
pub fn has_expr(&self) -> bool { self.expr.is_some() }
fn right(&self) -> Option<Precedence> { self.ops.last().map(|w| w.right) }
fn insert_missing(&mut self, loc: Location) {
let expr = self.expr.take();
if expr.is_some() {
let op = Loc::new(Op::Missing, loc);
let right = Precedence::MIN;
self.ops.push(Waiting {expr, op, right});
}
}
fn partial_flush(&mut self, left: Precedence) {
while let Some(right) = self.right() {
if right < left { break }
let Waiting {expr, op, ..} = self.ops.pop().unwrap();
let expr = Expr::Op(expr, op, self.expr.take());
self.expr = Some(Box::new(expr));
}
}
pub fn flush(mut self) -> MaybeExpr {
let mut ret = self.expr;
while let Some(Waiting {expr, op, ..}) = self.ops.pop() {
ret = Some(Box::new(Expr::Op(expr, op, ret)));
}
ret
}
pub fn op(&mut self, op: Loc<Op>) {
let (left, right) = op.precedence();
if let Some(left) = left {
self.partial_flush(left);
} else {
self.insert_missing(Loc::location(&op));
}
if let Some(right) = right {
let expr = self.expr.take();
self.ops.push(Waiting {expr, op, right});
} else {
let expr = Expr::Op(self.expr.take(), op, None);
self.expr = Some(Box::new(expr));
}
}
pub fn nonfix(&mut self, nonfix: Expr, loc: Location) {
self.insert_missing(loc);
self.expr = Some(Box::new(nonfix));
}
pub fn postfix(&mut self, left: Precedence, postfix: impl FnOnce(MaybeExpr) -> Expr) {
self.partial_flush(left);
let expr = postfix(self.expr.take());
self.expr = Some(Box::new(expr));
}
}