glyph_runtime/
stack.rs

1//! Stack implementation for the Glyph VM
2
3use glyph_types::Value;
4
5/// Stack for the VM with configurable size limit
6#[derive(Debug, Clone)]
7pub struct Stack {
8    items: Vec<Value>,
9    max_size: usize,
10}
11
12impl Stack {
13    /// Create a new stack with the given maximum size
14    pub fn new(max_size: usize) -> Self {
15        Stack {
16            items: Vec::with_capacity(1024),
17            max_size,
18        }
19    }
20
21    /// Push a value onto the stack
22    pub fn push(&mut self, value: Value) -> Result<(), StackError> {
23        if self.items.len() >= self.max_size {
24            return Err(StackError::Overflow);
25        }
26        self.items.push(value);
27        Ok(())
28    }
29
30    /// Pop a value from the stack
31    pub fn pop(&mut self) -> Result<Value, StackError> {
32        self.items.pop().ok_or(StackError::Underflow)
33    }
34
35    /// Peek at the top value without removing it
36    pub fn peek(&self) -> Result<&Value, StackError> {
37        self.items.last().ok_or(StackError::Underflow)
38    }
39
40    /// Peek at the nth value from the top (0 = top)
41    pub fn peek_n(&self, n: usize) -> Result<&Value, StackError> {
42        let len = self.items.len();
43        if n >= len {
44            return Err(StackError::Underflow);
45        }
46        Ok(&self.items[len - n - 1])
47    }
48
49    /// Duplicate the top value
50    pub fn dup(&mut self) -> Result<(), StackError> {
51        let value = self.peek()?.clone();
52        self.push(value)
53    }
54
55    /// Swap the top two values
56    pub fn swap(&mut self) -> Result<(), StackError> {
57        let len = self.items.len();
58        if len < 2 {
59            return Err(StackError::Underflow);
60        }
61        self.items.swap(len - 1, len - 2);
62        Ok(())
63    }
64
65    /// Get the current stack depth
66    pub fn depth(&self) -> usize {
67        self.items.len()
68    }
69
70    /// Clear the stack
71    pub fn clear(&mut self) {
72        self.items.clear();
73    }
74
75    /// Get a slice of the stack from a base pointer
76    pub fn slice_from(&self, bp: usize) -> &[Value] {
77        &self.items[bp..]
78    }
79
80    /// Remove multiple items from the top
81    pub fn pop_n(&mut self, n: usize) -> Result<Vec<Value>, StackError> {
82        if self.items.len() < n {
83            return Err(StackError::Underflow);
84        }
85        let split_at = self.items.len() - n;
86        Ok(self.items.split_off(split_at))
87    }
88
89    /// Truncate stack to a specific depth
90    pub fn truncate(&mut self, depth: usize) {
91        self.items.truncate(depth);
92    }
93}
94
95#[derive(Debug, Clone, PartialEq)]
96pub enum StackError {
97    Overflow,
98    Underflow,
99}
100
101impl std::fmt::Display for StackError {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        match self {
104            StackError::Overflow => write!(f, "Stack overflow"),
105            StackError::Underflow => write!(f, "Stack underflow"),
106        }
107    }
108}
109
110impl std::error::Error for StackError {}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn test_stack_operations() {
118        let mut stack = Stack::new(100);
119
120        // Test push and pop
121        stack.push(Value::Int(42)).unwrap();
122        stack.push(Value::Str("hello".to_string())).unwrap();
123
124        assert_eq!(stack.depth(), 2);
125        assert_eq!(stack.pop().unwrap(), Value::Str("hello".to_string()));
126        assert_eq!(stack.pop().unwrap(), Value::Int(42));
127
128        // Test underflow
129        assert!(matches!(stack.pop(), Err(StackError::Underflow)));
130    }
131
132    #[test]
133    fn test_stack_overflow() {
134        let mut stack = Stack::new(2);
135
136        stack.push(Value::Int(1)).unwrap();
137        stack.push(Value::Int(2)).unwrap();
138
139        // Should overflow
140        assert!(matches!(
141            stack.push(Value::Int(3)),
142            Err(StackError::Overflow)
143        ));
144    }
145
146    #[test]
147    fn test_dup_swap() {
148        let mut stack = Stack::new(100);
149
150        stack.push(Value::Int(1)).unwrap();
151        stack.push(Value::Int(2)).unwrap();
152
153        // Test dup
154        stack.dup().unwrap();
155        assert_eq!(stack.depth(), 3);
156        assert_eq!(stack.peek().unwrap(), &Value::Int(2));
157
158        // Test swap
159        stack.pop().unwrap(); // Remove duplicated value
160        stack.swap().unwrap();
161        assert_eq!(stack.pop().unwrap(), Value::Int(1));
162        assert_eq!(stack.pop().unwrap(), Value::Int(2));
163    }
164}