roan_engine/vm/
mod.rs

1pub mod native_fn;
2
3use crate::value::Value;
4use roan_error::frame::Frame;
5
6/// Virtual machine for executing Roan code.
7#[derive(Debug, Clone)]
8pub struct VM {
9    /// The stack of frames.
10    frames: Vec<Frame>,
11    /// The stack of values.
12    stack: Vec<Value>,
13}
14
15impl VM {
16    pub fn new() -> Self {
17        Self {
18            frames: vec![],
19            stack: vec![],
20        }
21    }
22}
23
24impl VM {
25    pub fn push_frame(&mut self, frame: Frame) {
26        self.frames.push(frame);
27    }
28
29    pub fn pop_frame(&mut self) -> Option<Frame> {
30        self.frames.pop()
31    }
32
33    pub fn frame(&self) -> Option<&Frame> {
34        self.frames.last()
35    }
36
37    pub fn frames(&self) -> &[Frame] {
38        &self.frames
39    }
40}
41
42impl VM {
43    pub fn push(&mut self, value: Value) {
44        self.stack.push(value);
45    }
46
47    pub fn pop(&mut self) -> Option<Value> {
48        self.stack.pop()
49    }
50
51    pub fn peek(&self) -> Option<&Value> {
52        self.stack.last()
53    }
54
55    pub fn stack(&self) -> &[Value] {
56        &self.stack
57    }
58
59    pub fn stack_last(&self) -> Option<&Value> {
60        self.stack.last()
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::value::Value;
68    use roan_error::TextSpan;
69
70    #[test]
71    fn test_vm() {
72        let mut vm = VM::new();
73        assert_eq!(vm.frames().len(), 0);
74        assert_eq!(vm.stack().len(), 0);
75
76        let frame = Frame::new(
77            "test".to_string(),
78            TextSpan::default(),
79            ".\\test.roan".to_string(),
80        );
81        vm.push_frame(frame.clone());
82        assert_eq!(vm.frames().len(), 1);
83
84        let value = Value::Int(42);
85        vm.push(value.clone());
86        assert_eq!(vm.stack().len(), 1);
87        assert_eq!(vm.peek(), Some(&value));
88
89        let popped = vm.pop().unwrap();
90        assert_eq!(popped, value);
91        assert_eq!(vm.stack().len(), 0);
92
93        let popped = vm.pop_frame().unwrap();
94        assert_eq!(vm.frames().len(), 0);
95    }
96}