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}