rush_interpreter_vm/
vm.rs

1use std::{
2    fmt::{self, Display, Formatter},
3    mem::size_of,
4    thread::sleep,
5    time::Duration,
6};
7
8use crate::{
9    instruction::{Instruction, Program},
10    value::{Pointer, Value},
11};
12
13pub struct Vm {
14    /// Working memory for temporary values
15    stack: Vec<Value>,
16    /// Linear memory for variables.
17    mem: Vec<Option<Value>>,
18    /// The memory pointer points to the last free location in memory.
19    /// The value is always positive, however using `isize` is beneficial in order to avoid casts.
20    mem_ptr: isize,
21    /// Holds information about the current position (like ip / fp).
22    call_stack: Vec<CallFrame>,
23}
24
25#[derive(Debug, Default)]
26struct CallFrame {
27    /// Specifies the instruction pointer relative to the function
28    ip: usize,
29    /// Specifies the function pointer
30    fp: usize,
31}
32
33const STACK_LIMIT: usize = 1024;
34const CALL_STACK_LIMIT: usize = 1024;
35
36pub type Result<T> = std::result::Result<T, RuntimeError>;
37
38#[derive(Debug)]
39pub struct RuntimeError {
40    pub kind: RuntimeErrorKind,
41    pub msg: String,
42}
43
44impl Display for RuntimeError {
45    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
46        write!(f, "{}: {}", self.kind, self.msg)
47    }
48}
49
50impl RuntimeError {
51    pub fn new(kind: RuntimeErrorKind, msg: String) -> Self {
52        Self { kind, msg }
53    }
54}
55
56#[derive(Debug)]
57pub enum RuntimeErrorKind {
58    StackOverflow,
59    Arithmetic,
60}
61
62impl Display for RuntimeErrorKind {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        write!(
65            f,
66            "{}",
67            match self {
68                Self::StackOverflow => "StackOverflowError",
69                Self::Arithmetic => "ArithmeticError",
70            }
71        )
72    }
73}
74
75impl Default for Vm {
76    fn default() -> Self {
77        Self::new()
78    }
79}
80
81impl Vm {
82    pub fn new() -> Self {
83        Self {
84            stack: vec![],
85            mem: vec![],
86            mem_ptr: 0,
87            // start execution at the first instruction of the prelude
88            call_stack: vec![CallFrame::default()],
89        }
90    }
91
92    /// Adds a value to the stack.
93    /// If this operation would exceed the stack limit, an error is returned.
94    fn push(&mut self, val: Value) -> Result<()> {
95        match self.stack.len() >= STACK_LIMIT {
96            true => Err(RuntimeError::new(
97                RuntimeErrorKind::StackOverflow,
98                format!("maximum stack size of {STACK_LIMIT} exceeded"),
99            )),
100            false => {
101                self.stack.push(val);
102                Ok(())
103            }
104        }
105    }
106
107    #[inline]
108    /// Removes the top stack element and returns its value.
109    fn pop(&mut self) -> Value {
110        self.stack.pop().expect("pop is always called safely")
111    }
112
113    #[inline]
114    fn call_frame(&self) -> &CallFrame {
115        self.call_stack
116            .last()
117            .expect("there is always at least one call frame")
118    }
119
120    #[inline]
121    fn call_frame_mut(&mut self) -> &mut CallFrame {
122        self.call_stack
123            .last_mut()
124            .expect("there is always at least one call frame")
125    }
126
127    /// Runs the specified program but includes debug prints after each instruction.
128    /// Also accepts the `clock_hz` parameter which specifies the speed of the VM.
129    pub fn debug_run(&mut self, program: Program, clock_hz: u64) -> Result<i64> {
130        while self.call_frame().ip < program.0[self.call_frame().fp].len() {
131            let instruction = &program.0[self.call_frame().fp][self.call_frame().ip];
132
133            println!(
134                "[{fp:02}/{ip:02}] {instr:15} | {stack:>40} | mp = {mp} | used = {used_mem:4}b | {mem}",
135                fp = self.call_frame().fp,
136                ip = self.call_frame().ip,
137                instr = instruction.to_string(),
138                stack = self
139                    .stack
140                    .iter()
141                    .rev()
142                    .map(|v| v.to_string())
143                    .collect::<Vec<String>>()
144                    .join(", "),
145                mp = self.mem_ptr,
146                used_mem = self.mem.len() * size_of::<Value>(),
147                mem = self.mem[self.mem_ptr as usize..]
148                    .iter()
149                    .map(|v| match v {
150                        Some(v) => v.to_string(),
151                        None => "NONE".to_string(),
152                    })
153                    .collect::<Vec<String>>()
154                    .join(", ")
155            );
156            sleep(Duration::from_millis(1000 / clock_hz));
157
158            // if the current instruction exists the VM, terminate execution
159            if let Some(code) = self.run_instruction(instruction)? {
160                return Ok(code);
161            };
162        }
163        Ok(0)
164    }
165
166    pub fn run(&mut self, program: Program) -> Result<i64> {
167        while self.call_frame().ip < program.0[self.call_frame().fp].len() {
168            let instruction = &program.0[self.call_frame().fp][self.call_frame().ip];
169
170            // if the current instruction exists the VM, terminate execution
171            if let Some(code) = self.run_instruction(instruction)? {
172                return Ok(code);
173            };
174        }
175
176        Ok(0)
177    }
178
179    fn run_instruction(&mut self, inst: &Instruction) -> Result<Option<i64>> {
180        match inst {
181            Instruction::Nop => {}
182            Instruction::Push(value) => self.push(*value)?,
183            Instruction::Drop => {
184                self.pop();
185            }
186            Instruction::Clone => self
187                .stack
188                .push(*self.stack.last().expect("clone is always called safely")),
189            Instruction::Jmp(idx) => {
190                self.call_frame_mut().ip = *idx;
191                return Ok(None);
192            }
193            Instruction::JmpFalse(idx) => {
194                // if the value on the stack is `false`, perform the jump
195                if !self.pop().unwrap_bool() {
196                    self.call_frame_mut().ip = *idx;
197                    return Ok(None);
198                }
199            }
200            Instruction::SetVarImm(_) | Instruction::SetVar => {
201                let val = self.pop();
202
203                let addr = match inst {
204                    Instruction::SetVarImm(Pointer::Rel(offset)) => {
205                        (self.mem_ptr + offset) as usize
206                    }
207                    Instruction::SetVarImm(Pointer::Abs(addr)) => *addr,
208                    _ => match self.pop().unwrap_ptr() {
209                        Pointer::Rel(offset) => (self.mem_ptr + offset) as usize,
210                        Pointer::Abs(addr) => addr,
211                    },
212                };
213
214                // if there is already an entry in the memory, use it.
215                // otherwise, new memory is allocated
216                match self.mem.get_mut(addr) {
217                    Some(var) => *var = Some(val),
218                    None => {
219                        self.mem.resize(addr + 1, None);
220                        self.mem[addr] = Some(val)
221                    }
222                }
223            }
224            Instruction::GetVar => {
225                let addr = match self.pop().unwrap_ptr() {
226                    Pointer::Rel(offset) => (self.mem_ptr + offset) as usize,
227                    Pointer::Abs(addr) => addr,
228                };
229                self.push(self.mem[addr].expect("variables are always initialized"))?
230            }
231            Instruction::Call(idx) => {
232                if self.call_stack.len() >= CALL_STACK_LIMIT {
233                    return Err(RuntimeError::new(
234                        RuntimeErrorKind::StackOverflow,
235                        format!("maximum call-stack size of {CALL_STACK_LIMIT} was exceeded"),
236                    ));
237                }
238
239                // sets the function pointer and instruction pointer to the callee
240                self.call_stack.push(CallFrame { ip: 0, fp: *idx });
241
242                // must return because the ip would be incremented otherwise
243                return Ok(None);
244            }
245            Instruction::SetMp(offset) => {
246                self.mem_ptr += offset;
247                self.mem.resize(self.mem_ptr as usize + 1, None);
248            }
249            Instruction::RelToAddr(offset) => {
250                let addr = (self.mem_ptr + offset) as usize;
251                self.push(Value::Ptr(Pointer::Abs(addr)))?;
252            }
253            Instruction::Ret => {
254                self.call_stack.pop();
255            }
256            Instruction::Cast(to) => {
257                let from = self.pop();
258                self.push(from.cast(*to))?
259            }
260            Instruction::Exit => {
261                return Ok(Some(self.pop().unwrap_int()));
262            }
263            Instruction::Neg => {
264                let top = self.pop();
265                self.push(top.neg())?;
266            }
267            Instruction::Not => {
268                let top = self.pop();
269                self.push(top.not())?;
270            }
271            Instruction::Add => {
272                let rhs = self.pop();
273                let lhs = self.pop();
274                self.push(lhs.add(rhs))?;
275            }
276            Instruction::Sub => {
277                let rhs = self.pop();
278                let lhs = self.pop();
279                self.push(lhs.sub(rhs))?;
280            }
281            Instruction::Mul => {
282                let rhs = self.pop();
283                let lhs = self.pop();
284                self.push(lhs.mul(rhs))?;
285            }
286            Instruction::Pow => {
287                let rhs = self.pop();
288                let lhs = self.pop();
289                self.push(lhs.pow(rhs))?;
290            }
291            Instruction::Div => {
292                let rhs = self.pop();
293                let lhs = self.pop();
294                self.push(lhs.div(rhs)?)?;
295            }
296            Instruction::Rem => {
297                let rhs = self.pop();
298                let lhs = self.pop();
299                self.push(lhs.rem(rhs)?)?;
300            }
301            Instruction::Eq => {
302                let rhs = self.pop();
303                let lhs = self.pop();
304                self.push(lhs.eq(rhs))?;
305            }
306            Instruction::Ne => {
307                let rhs = self.pop();
308                let lhs = self.pop();
309                self.push(lhs.ne(rhs))?;
310            }
311            Instruction::Lt => {
312                let rhs = self.pop();
313                let lhs = self.pop();
314                self.push(lhs.lt(rhs))?;
315            }
316            Instruction::Le => {
317                let rhs = self.pop();
318                let lhs = self.pop();
319                self.push(lhs.le(rhs))?;
320            }
321            Instruction::Gt => {
322                let rhs = self.pop();
323                let lhs = self.pop();
324                self.push(lhs.gt(rhs))?;
325            }
326            Instruction::Ge => {
327                let rhs = self.pop();
328                let lhs = self.pop();
329                self.push(lhs.ge(rhs))?;
330            }
331            Instruction::Shl => {
332                let rhs = self.pop();
333                let lhs = self.pop();
334                self.push(lhs.shl(rhs)?)?;
335            }
336            Instruction::Shr => {
337                let rhs = self.pop();
338                let lhs = self.pop();
339                self.push(lhs.shr(rhs)?)?;
340            }
341            Instruction::BitOr => {
342                let rhs = self.pop();
343                let lhs = self.pop();
344                self.push(lhs.bit_or(rhs))?;
345            }
346            Instruction::BitAnd => {
347                let rhs = self.pop();
348                let lhs = self.pop();
349                self.push(lhs.bit_and(rhs))?;
350            }
351            Instruction::BitXor => {
352                let rhs = self.pop();
353                let lhs = self.pop();
354                self.push(lhs.bit_xor(rhs))?;
355            }
356        }
357        self.call_frame_mut().ip += 1;
358        Ok(None)
359    }
360}