jetcrab\vm\executor\instruction_handlers/
stack_ops.rs

1//! # Stack Operations Handler
2//!
3//! Handles all stack manipulation operations in the VM including pushing, popping,
4//! duplicating, and other stack management operations.
5//!
6//! ## Operations Supported
7//!
8//! - **Basic Operations**: push, pop, peek
9//! - **Duplication**: dup, dup2
10//! - **Rearrangement**: swap, rot, over
11//! - **Removal**: drop, drop2, clear
12//! - **Information**: size, is_empty, depth
13//! - **Advanced**: reserve, truncate
14//!
15//! ## Stack Semantics
16//!
17//! - **LIFO**: Last In, First Out stack behavior
18//! - **Type Safety**: All operations maintain type safety
19//! - **Bounds Checking**: Prevents stack underflow/overflow
20//! - **Performance**: Optimized for common operations
21//!
22//! ## Usage
23//!
24//! ```rust
25//! use jetcrab::vm::executor::instruction_handlers::StackOpsHandler;
26//! use jetcrab::vm::executor::traits::StackOperations;
27//!
28//! let mut stack = MyStack::new();
29//! stack.push(Value::Number(42.0));
30//! StackOpsHandler::dup(&mut stack)?;
31//! // Stack now contains: [42.0, 42.0]
32//! ```
33
34use crate::vm::executor::error_handler::ExecutionError;
35use crate::vm::executor::traits::StackOperations;
36use crate::vm::value::Value;
37use crate::vm::types::indices::StackIndex;
38
39/// Handles stack operations for the VM
40pub struct StackOpsHandler;
41
42impl StackOpsHandler {
43    /// Pushes a value onto the stack
44    ///
45    /// Adds a value to the top of the stack.
46    ///
47    /// # Arguments
48    /// * `stack` - The stack to operate on
49    /// * `value` - The value to push onto the stack
50    ///
51    /// # Returns
52    /// * `Ok(())` on success
53    /// * `Err(ExecutionError)` on failure
54    ///
55    /// # Examples
56    ///
57    /// ```rust
58    /// let mut stack = MyStack::new();
59    /// StackOpsHandler::push(&mut stack, Value::Number(42.0))?;
60    /// assert_eq!(stack.pop(), Some(Value::Number(42.0)));
61    /// ```
62    pub fn push<S>(stack: &mut S, value: Value) -> Result<(), ExecutionError>
63    where
64        S: StackOperations,
65    {
66        stack.push(value);
67        Ok(())
68    }
69
70    /// Pops a value from the top of the stack
71    ///
72    /// Removes and returns the top value from the stack.
73    ///
74    /// # Arguments
75    /// * `stack` - The stack to operate on
76    ///
77    /// # Returns
78    /// * `Ok(())` on success
79    /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
80    ///
81    /// # Examples
82    ///
83    /// ```rust
84    /// let mut stack = MyStack::new();
85    /// stack.push(Value::Number(42.0));
86    /// StackOpsHandler::pop(&mut stack)?;
87    /// assert!(stack.is_empty());
88    /// ```
89    pub fn pop<S>(stack: &mut S) -> Result<(), ExecutionError>
90    where
91        S: StackOperations,
92    {
93        stack.pop().ok_or(ExecutionError::StackUnderflow)?;
94        Ok(())
95    }
96
97    /// Duplicates the top value on the stack
98    ///
99    /// Pops the top value and pushes it twice, effectively duplicating it.
100    ///
101    /// # Arguments
102    /// * `stack` - The stack to operate on
103    ///
104    /// # Returns
105    /// * `Ok(())` on success
106    /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
107    ///
108    /// # Examples
109    ///
110    /// ```rust
111    /// let mut stack = MyStack::new();
112    /// stack.push(Value::Number(42.0));
113    /// StackOpsHandler::dup(&mut stack)?;
114    /// // Stack now contains: [42.0, 42.0]
115    /// ```
116    pub fn dup<S>(stack: &mut S) -> Result<(), ExecutionError>
117    where
118        S: StackOperations,
119    {
120        let value = stack.peek().ok_or(ExecutionError::StackUnderflow)?.clone();
121        stack.push(value);
122        Ok(())
123    }
124
125    /// Duplicates the top two values on the stack
126    ///
127    /// Pops the top two values and pushes them twice, effectively duplicating them.
128    ///
129    /// # Arguments
130    /// * `stack` - The stack to operate on
131    ///
132    /// # Returns
133    /// * `Ok(())` on success
134    /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
135    ///
136    /// # Examples
137    ///
138    /// ```rust
139    /// let mut stack = MyStack::new();
140    /// stack.push(Value::Number(42.0));
141    /// stack.push(Value::Number(100.0));
142    /// StackOpsHandler::dup2(&mut stack)?;
143    /// // Stack now contains: [42.0, 100.0, 42.0, 100.0]
144    /// ```
145    pub fn dup2<S>(stack: &mut S) -> Result<(), ExecutionError>
146    where
147        S: StackOperations,
148    {
149        if stack.len() < 2 {
150            return Err(ExecutionError::StackUnderflow);
151        }
152
153        let b = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
154        let a = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
155
156        stack.push(a.clone());
157        stack.push(b.clone());
158        stack.push(a);
159        stack.push(b);
160
161        Ok(())
162    }
163
164    /// Swaps the top two values on the stack
165    ///
166    /// Exchanges the positions of the top two values on the stack.
167    ///
168    /// # Arguments
169    /// * `stack` - The stack to operate on
170    ///
171    /// # Returns
172    /// * `Ok(())` on success
173    /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
174    ///
175    /// # Examples
176    ///
177    /// ```rust
178    /// let mut stack = MyStack::new();
179    /// stack.push(Value::Number(42.0));
180    /// stack.push(Value::Number(100.0));
181    /// StackOpsHandler::swap(&mut stack)?;
182    /// // Stack now contains: [100.0, 42.0]
183    /// ```
184    pub fn swap<S>(stack: &mut S) -> Result<(), ExecutionError>
185    where
186        S: StackOperations,
187    {
188        if stack.len() < 2 {
189            return Err(ExecutionError::StackUnderflow);
190        }
191
192        let b = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
193        let a = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
194
195        stack.push(b);
196        stack.push(a);
197
198        Ok(())
199    }
200
201    /// Rotates the top three values on the stack
202    ///
203    /// Moves the third value to the top, shifting the others down.
204    ///
205    /// # Arguments
206    /// * `stack` - The stack to operate on
207    ///
208    /// # Returns
209    /// * `Ok(())` on success
210    /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
211    ///
212    /// # Examples
213    ///
214    /// ```rust
215    /// let mut stack = MyStack::new();
216    /// stack.push(Value::Number(1.0));
217    /// stack.push(Value::Number(2.0));
218    /// stack.push(Value::Number(3.0));
219    /// StackOpsHandler::rot(&mut stack)?;
220    /// // Stack now contains: [2.0, 3.0, 1.0]
221    /// ```
222    pub fn rot<S>(stack: &mut S) -> Result<(), ExecutionError>
223    where
224        S: StackOperations,
225    {
226        if stack.len() < 3 {
227            return Err(ExecutionError::StackUnderflow);
228        }
229
230        let c = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
231        let b = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
232        let a = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
233
234        stack.push(b);
235        stack.push(c);
236        stack.push(a);
237
238        Ok(())
239    }
240
241    /// Copies the second value to the top of the stack
242    ///
243    /// Pushes a copy of the second value without removing it.
244    ///
245    /// # Arguments
246    /// * `stack` - The stack to operate on
247    ///
248    /// # Returns
249    /// * `Ok(())` on success
250    /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
251    ///
252    /// # Examples
253    ///
254    /// ```rust
255    /// let mut stack = MyStack::new();
256    /// stack.push(Value::Number(42.0));
257    /// stack.push(Value::Number(100.0));
258    /// StackOpsHandler::over(&mut stack)?;
259    /// // Stack now contains: [42.0, 100.0, 42.0]
260    /// ```
261    pub fn over<S>(stack: &mut S) -> Result<(), ExecutionError>
262    where
263        S: StackOperations,
264    {
265        if stack.len() < 2 {
266            return Err(ExecutionError::StackUnderflow);
267        }
268
269        let values = stack.stack_mut();
270        let second_value = values.get(StackIndex::new(values.size() - 2)).unwrap().clone();
271        stack.push(second_value);
272
273        Ok(())
274    }
275
276    /// Removes the top value from the stack
277    ///
278    /// Pops and discards the top value from the stack.
279    ///
280    /// # Arguments
281    /// * `stack` - The stack to operate on
282    ///
283    /// # Returns
284    /// * `Ok(())` on success
285    /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
286    pub fn drop<S>(stack: &mut S) -> Result<(), ExecutionError>
287    where
288        S: StackOperations,
289    {
290        stack.pop().ok_or(ExecutionError::StackUnderflow)?;
291        Ok(())
292    }
293
294    /// Removes the top two values from the stack
295    ///
296    /// Pops and discards the top two values from the stack.
297    ///
298    /// # Arguments
299    /// * `stack` - The stack to operate on
300    ///
301    /// # Returns
302    /// * `Ok(())` on success
303    /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
304    pub fn drop2<S>(stack: &mut S) -> Result<(), ExecutionError>
305    where
306        S: StackOperations,
307    {
308        if stack.len() < 2 {
309            return Err(ExecutionError::StackUnderflow);
310        }
311
312        stack.pop().ok_or(ExecutionError::StackUnderflow)?;
313        stack.pop().ok_or(ExecutionError::StackUnderflow)?;
314
315        Ok(())
316    }
317
318    /// Clears all values from the stack
319    ///
320    /// Removes all values from the stack, leaving it empty.
321    ///
322    /// # Arguments
323    /// * `stack` - The stack to operate on
324    ///
325    /// # Returns
326    /// * `Ok(())` on success
327    pub fn clear<S>(stack: &mut S) -> Result<(), ExecutionError>
328    where
329        S: StackOperations,
330    {
331        stack.clear();
332        Ok(())
333    }
334
335    /// Gets the current size of the stack
336    ///
337    /// Pushes the number of values currently on the stack.
338    ///
339    /// # Arguments
340    /// * `stack` - The stack to operate on
341    ///
342    /// # Returns
343    /// * `Ok(())` on success
344    ///
345    /// # Examples
346    ///
347    /// ```rust
348    /// let mut stack = MyStack::new();
349    /// stack.push(Value::Number(42.0));
350    /// stack.push(Value::Number(100.0));
351    /// StackOpsHandler::size(&mut stack)?;
352    /// assert_eq!(stack.pop(), Some(Value::Number(2.0)));
353    /// ```
354    pub fn size<S>(stack: &mut S) -> Result<(), ExecutionError>
355    where
356        S: StackOperations,
357    {
358        let size = stack.size();
359        stack.push(Value::Number(size as f64));
360        Ok(())
361    }
362
363    /// Checks if the stack is empty
364    ///
365    /// Pushes a boolean indicating whether the stack is empty.
366    ///
367    /// # Arguments
368    /// * `stack` - The stack to operate on
369    ///
370    /// # Returns
371    /// * `Ok(())` on success
372    ///
373    /// # Examples
374    ///
375    /// ```rust
376    /// let mut stack = MyStack::new();
377    /// StackOpsHandler::is_empty(&mut stack)?;
378    /// assert_eq!(stack.pop(), Some(Value::Boolean(true)));
379    /// ```
380    pub fn is_empty<S>(stack: &mut S) -> Result<(), ExecutionError>
381    where
382        S: StackOperations,
383    {
384        let is_empty = stack.is_empty();
385        stack.push(Value::Boolean(is_empty));
386        Ok(())
387    }
388
389    /// Peeks at the top value without removing it
390    ///
391    /// Pushes a copy of the top value without modifying the stack.
392    ///
393    /// # Arguments
394    /// * `stack` - The stack to operate on
395    ///
396    /// # Returns
397    /// * `Ok(())` on success
398    /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
399    ///
400    /// # Examples
401    ///
402    /// ```rust
403    /// let mut stack = MyStack::new();
404    /// stack.push(Value::Number(42.0));
405    /// StackOpsHandler::peek(&mut stack)?;
406    /// // Stack now contains: [42.0, 42.0]
407    /// ```
408    pub fn peek<S>(stack: &mut S) -> Result<(), ExecutionError>
409    where
410        S: StackOperations,
411    {
412        let value = stack.peek().ok_or(ExecutionError::StackUnderflow)?.clone();
413        stack.push(value);
414        Ok(())
415    }
416
417    /// Gets the depth of the stack
418    ///
419    /// Pushes the current depth (number of values) on the stack.
420    ///
421    /// # Arguments
422    /// * `stack` - The stack to operate on
423    ///
424    /// # Returns
425    /// * `Ok(())` on success
426    pub fn depth<S>(stack: &mut S) -> Result<(), ExecutionError>
427    where
428        S: StackOperations,
429    {
430        let depth = stack.len();
431        stack.push(Value::Number(depth as f64));
432        Ok(())
433    }
434
435    /// Reserves space on the stack
436    ///
437    /// Ensures the stack has at least the specified capacity.
438    ///
439    /// # Arguments
440    /// * `stack` - The stack to operate on
441    /// * `capacity` - The minimum capacity to reserve
442    ///
443    /// # Returns
444    /// * `Ok(())` on success
445    pub fn reserve<S>(stack: &mut S, capacity: usize) -> Result<(), ExecutionError>
446    where
447        S: StackOperations,
448    {
449        let stack_mut = stack.stack_mut();
450        stack_mut.values.reserve(capacity);
451        Ok(())
452    }
453
454    /// Truncates the stack to a specific size
455    ///
456    /// Removes values from the top of the stack until it reaches the specified size.
457    ///
458    /// # Arguments
459    /// * `stack` - The stack to operate on
460    /// * `size` - The target size for the stack
461    ///
462    /// # Returns
463    /// * `Ok(())` on success
464    /// * `Err(ExecutionError::StackUnderflow)` if target size is larger than current size
465    pub fn truncate<S>(stack: &mut S, size: usize) -> Result<(), ExecutionError>
466    where
467        S: StackOperations,
468    {
469        let current_size = stack.len();
470        if size > current_size {
471            return Err(ExecutionError::StackUnderflow);
472        }
473
474        let to_remove = current_size - size;
475        for _ in 0..to_remove {
476            stack.pop().ok_or(ExecutionError::StackUnderflow)?;
477        }
478
479        Ok(())
480    }
481}