use crate::*; pub struct ExpressionStack { stack: Vec, } impl ExpressionStack { pub fn new() -> Self { Self { stack: Vec::new(), } } pub fn pull_result(mut self) -> Result { match self.stack.len() { 0 => Err(StackError::NoReturnValue), 1 => Ok(self.stack.pop().unwrap()), _ => Err(StackError::MultipleReturnValues), } } pub fn push(&mut self, value: isize) { self.stack.push(value); } pub fn apply(&mut self, operator: Operator, source: &SourceSpan) -> Result<(), Tracked> { macro_rules! push { ($val:expr) => { self.stack.push($val) } } macro_rules! pop { ($name:ident) => { let $name = match self.stack.pop() { Some(value) => value, None => return Err(Tracked::from(StackError::Underflow, source.clone())), }; } } macro_rules! truth { ($bool:expr) => { match $bool { true => 1, false => 0 } }; } match operator { Operator::Equal => { pop!(b); pop!(a); push!(truth!(a==b)) }, Operator::NotEqual => { pop!(b); pop!(a); push!(truth!(a!=b)) }, Operator::LessThan => { pop!(b); pop!(a); push!(truth!(a < b)) }, Operator::GreaterThan => { pop!(b); pop!(a); push!(truth!(a > b)) }, Operator::LessThanEqual => { pop!(b); pop!(a); push!(truth!(a <= b)) }, Operator::GreaterThanEqual => { pop!(b); pop!(a); push!(truth!(a >= b)) }, Operator::Add => { pop!(b); pop!(a); push!(a + b) }, Operator::Subtract => { pop!(b); pop!(a); push!(a - b) }, Operator::Multiply => { pop!(b); pop!(a); push!(a * b) }, Operator::Divide => { pop!(b); pop!(a); push!(a / b) }, Operator::Modulo => { pop!(b); pop!(a); push!(a % b) }, Operator::Exponent => { pop!(b); pop!(a); push!( if let Ok(b) = u32::try_from(b) { a.saturating_pow(b) } else { 0 } ) }, Operator::LeftShift => { pop!(b); pop!(a); push!( if b < 0 { a >> -b } else { a << b } ) }, Operator::RightShift => { pop!(b); pop!(a); push!( if b < 0 { a << -b } else { a >> b } ) }, Operator::BitAnd => { pop!(b); pop!(a); push!(a & b) }, Operator::BitOr => { pop!(b); pop!(a); push!(a | b) }, Operator::BitXor => { pop!(b); pop!(a); push!(a ^ b) }, Operator::BitNot => { pop!(a); push!(!a) }, Operator::Length => { pop!(a); push!(width(a) as isize) }, } return Ok(()); } } /// Find the number of bits required to hold an integer. pub fn width(value: isize) -> u32 { match value.cmp(&0) { std::cmp::Ordering::Less => (-value).ilog2() + 2, std::cmp::Ordering::Equal => 0, std::cmp::Ordering::Greater => value.ilog2() + 1, } } pub enum StackError { Underflow, MultipleReturnValues, NoReturnValue, } pub fn report_stack_error(error: &Tracked, source_code: &str) { let context = Context { source_code: &source_code, source: &error.source }; let message = match &error.value { StackError::Underflow => "A stack underflow occurred while evaluating this operator", StackError::MultipleReturnValues => "More than one value was left on the stack after this expression was evaluated", StackError::NoReturnValue => "No value was left on the stack after this expression was evaluated", }; report_source_issue(LogLevel::Error, &context, message); }