1use crate::decompile::FormulaError;
2
3#[derive(Debug, Default)]
4pub struct DecompileStack {
5 values: Vec<String>,
6}
7
8impl DecompileStack {
9 pub fn push<S: Into<String>>(&mut self, value: S) {
10 self.values.push(value.into());
11 }
12
13 pub fn pop(&mut self) -> Result<String, FormulaError> {
14 self.values.pop().ok_or(FormulaError::StackUnderflow {
15 needed: 1,
16 available: 0,
17 })
18 }
19
20 pub fn pop2(&mut self) -> Result<(String, String), FormulaError> {
21 let available = self.values.len();
22 if available < 2 {
23 return Err(FormulaError::StackUnderflow {
24 needed: 2,
25 available,
26 });
27 }
28
29 let right = self.values.pop().ok_or(FormulaError::StackUnderflow {
30 needed: 2,
31 available,
32 })?;
33 let left = self.values.pop().ok_or(FormulaError::StackUnderflow {
34 needed: 2,
35 available,
36 })?;
37 Ok((left, right))
38 }
39
40 pub fn pop_n(&mut self, n: usize) -> Result<Vec<String>, FormulaError> {
41 let available = self.values.len();
42 if available < n {
43 return Err(FormulaError::StackUnderflow {
44 needed: n,
45 available,
46 });
47 }
48
49 let start = available - n;
50 Ok(self.values.split_off(start))
51 }
52
53 pub fn apply_unary_prefix(&mut self, prefix: &str) -> Result<(), FormulaError> {
54 let value = self.pop()?;
55 self.push(format!("{prefix}{value}"));
56 Ok(())
57 }
58
59 pub fn apply_unary_suffix(&mut self, suffix: &str) -> Result<(), FormulaError> {
60 let value = self.pop()?;
61 self.push(format!("{value}{suffix}"));
62 Ok(())
63 }
64
65 pub fn wrap_top(&mut self, left: &str, right: &str) -> Result<(), FormulaError> {
66 let value = self.pop()?;
67 self.push(format!("{left}{value}{right}"));
68 Ok(())
69 }
70
71 pub fn len(&self) -> usize {
72 self.values.len()
73 }
74
75 pub fn finish(mut self) -> Result<String, FormulaError> {
76 if self.values.len() != 1 {
77 return Err(FormulaError::InvalidFinalStack {
78 len: self.values.len(),
79 });
80 }
81
82 self.values.pop().ok_or(FormulaError::InvalidFinalStack { len: 0 })
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn pop_n_returns_arguments_in_formula_order() {
92 let mut stack = DecompileStack::default();
93 stack.push("A1");
94 stack.push("A2");
95 stack.push("A3");
96
97 let args = stack.pop_n(2).expect("stack should contain 2 args");
98 assert_eq!(args, vec!["A2".to_string(), "A3".to_string()]);
99 assert_eq!(stack.len(), 1);
100 }
101}