Skip to main content

xlsbye_formula/
stack.rs

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}