rigz_vm/
call_frame.rs

1use crate::{StackValue, VMError};
2use indexmap::map::Entry;
3use indexmap::IndexMap;
4use log_derive::{logfn, logfn_inputs};
5use std::cell::RefCell;
6use std::ops::Index;
7
8#[derive(Clone, Debug)]
9pub enum Variable {
10    Let(StackValue),
11    Mut(StackValue),
12}
13
14#[derive(Clone, Debug)]
15pub struct Frames<'vm> {
16    pub current: RefCell<CallFrame<'vm>>,
17    pub frames: Vec<RefCell<CallFrame<'vm>>>,
18}
19
20impl<'vm> Index<usize> for Frames<'vm> {
21    type Output = RefCell<CallFrame<'vm>>;
22
23    #[inline]
24    fn index(&self, index: usize) -> &Self::Output {
25        &self.frames[index]
26    }
27}
28
29impl<'vm> Frames<'vm> {
30    #[inline]
31    pub fn reset(&mut self) {
32        self.current = RefCell::new(CallFrame::main());
33        self.frames.clear();
34    }
35
36    #[inline]
37    pub fn pop(&mut self) -> Option<RefCell<CallFrame<'vm>>> {
38        self.frames.pop()
39    }
40
41    #[inline]
42    pub fn len(&self) -> usize {
43        self.frames.len()
44    }
45
46    #[inline]
47    pub fn push(&mut self, call_frame: CallFrame<'vm>) {
48        self.frames.push(call_frame.into())
49    }
50
51    #[inline]
52    #[logfn_inputs(Trace, fmt = "load_let(frames={:#?} name={}, value={:?})")]
53    pub fn load_let(&self, name: &'vm str, value: StackValue) -> Result<(), VMError> {
54        match self.current.borrow_mut().variables.entry(name) {
55            Entry::Occupied(v) => {
56                return Err(VMError::UnsupportedOperation(format!(
57                    "Cannot overwrite let variable: {}",
58                    *v.key()
59                )))
60            }
61            Entry::Vacant(e) => {
62                e.insert(Variable::Let(value));
63            }
64        }
65        Ok(())
66    }
67
68    #[logfn(Trace)]
69    #[logfn_inputs(Trace, fmt = "get_variable(frames={:#p} name={})")]
70    pub fn get_variable(&self, name: &'vm str) -> Option<StackValue> {
71        self.current.borrow().get_variable(name, self)
72    }
73
74    #[logfn(Trace)]
75    #[logfn_inputs(Trace, fmt = "get_mutable_variable(frames={:#p} name={})")]
76    pub fn get_mutable_variable(&self, name: &'vm str) -> Result<Option<StackValue>, VMError> {
77        self.current.borrow().get_mutable_variable(name, self)
78    }
79
80    #[inline]
81    #[logfn_inputs(Trace, fmt = "load_mut(frames={:#?} name={}, value={:?})")]
82    pub fn load_mut(&self, name: &'vm str, value: StackValue) -> Result<(), VMError> {
83        match self.current.borrow_mut().variables.entry(name) {
84            Entry::Occupied(mut var) => match var.get() {
85                Variable::Let(_) => {
86                    return Err(VMError::UnsupportedOperation(format!(
87                        "Cannot overwrite let variable: {}",
88                        *var.key()
89                    )))
90                }
91                Variable::Mut(_) => {
92                    var.insert(Variable::Mut(value));
93                }
94            },
95            Entry::Vacant(e) => {
96                e.insert(Variable::Mut(value));
97            }
98        }
99        Ok(())
100    }
101}
102
103impl Default for Frames<'_> {
104    #[inline]
105    fn default() -> Self {
106        Frames {
107            current: RefCell::new(CallFrame::main()),
108            frames: vec![],
109        }
110    }
111}
112
113#[derive(Clone, Debug, Default)]
114pub struct CallFrame<'vm> {
115    pub scope_id: usize,
116    pub pc: usize,
117    pub variables: IndexMap<&'vm str, Variable>,
118    pub parent: Option<usize>,
119}
120
121impl<'vm> CallFrame<'vm> {
122    fn get_variable(&self, name: &'vm str, frames: &Frames<'vm>) -> Option<StackValue> {
123        match self.variables.get(name) {
124            None => match self.parent {
125                None => None,
126                Some(parent) => frames[parent].borrow().get_variable(name, frames),
127            },
128            Some(v) => match v {
129                Variable::Let(v) => Some(v.clone()),
130                Variable::Mut(v) => Some(v.clone()),
131            },
132        }
133    }
134
135    fn get_mutable_variable(
136        &self,
137        name: &'vm str,
138        frames: &Frames<'vm>,
139    ) -> Result<Option<StackValue>, VMError> {
140        match self.variables.get(name) {
141            None => match self.parent {
142                None => Ok(None),
143                Some(parent) => frames[parent].borrow().get_mutable_variable(name, frames),
144            },
145            Some(v) => match v {
146                Variable::Let(_) => Err(VMError::VariableDoesNotExist(format!(
147                    "Variable {} is immutable",
148                    name
149                ))),
150                Variable::Mut(v) => Ok(Some(v.clone())),
151            },
152        }
153    }
154}
155
156impl CallFrame<'_> {
157    #[inline]
158    pub fn main() -> Self {
159        Self::default()
160    }
161
162    #[inline]
163    pub fn child(scope_id: usize, call_frame_id: usize) -> Self {
164        Self {
165            scope_id,
166            parent: Some(call_frame_id),
167            ..Default::default()
168        }
169    }
170}