roan_engine/vm/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
pub mod native_fn;

use crate::value::Value;
use roan_error::frame::Frame;

/// Virtual machine for executing Roan code.
#[derive(Debug, Clone)]
pub struct VM {
    /// The stack of frames.
    frames: Vec<Frame>,
    /// The stack of values.
    stack: Vec<Value>,
}

impl VM {
    pub fn new() -> Self {
        Self {
            frames: vec![],
            stack: vec![],
        }
    }
}

impl VM {
    pub fn push_frame(&mut self, frame: Frame) {
        self.frames.push(frame);
    }

    pub fn pop_frame(&mut self) -> Option<Frame> {
        self.frames.pop()
    }

    pub fn frame(&self) -> Option<&Frame> {
        self.frames.last()
    }

    pub fn frames(&self) -> &[Frame] {
        &self.frames
    }
}

impl VM {
    pub fn push(&mut self, value: Value) {
        self.stack.push(value);
    }

    pub fn pop(&mut self) -> Option<Value> {
        self.stack.pop()
    }

    pub fn peek(&self) -> Option<&Value> {
        self.stack.last()
    }

    pub fn stack(&self) -> &[Value] {
        &self.stack
    }

    pub fn stack_last(&self) -> Option<&Value> {
        self.stack.last()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::value::Value;
    use roan_error::TextSpan;

    #[test]
    fn test_vm() {
        let mut vm = VM::new();
        assert_eq!(vm.frames().len(), 0);
        assert_eq!(vm.stack().len(), 0);

        let frame = Frame::new(
            "test".to_string(),
            TextSpan::default(),
            ".\\test.roan".to_string(),
        );
        vm.push_frame(frame.clone());
        assert_eq!(vm.frames().len(), 1);

        let value = Value::Int(42);
        vm.push(value.clone());
        assert_eq!(vm.stack().len(), 1);
        assert_eq!(vm.peek(), Some(&value));

        let popped = vm.pop().unwrap();
        assert_eq!(popped, value);
        assert_eq!(vm.stack().len(), 0);

        let popped = vm.pop_frame().unwrap();
        assert_eq!(vm.frames().len(), 0);
    }
}