sym_lang/
vm.rs

1use crate::error::SymError;
2use crate::utils;
3use crate::{instructions::Instruction, parse::Line};
4
5pub struct VM {
6    //stack: [u8; 255],
7    stack: Vec<u8>,
8    pc: usize,
9    program: Vec<Line>,
10    running: bool,
11}
12
13impl VM {
14    pub fn new(program: Vec<Line>) -> Self {
15        Self {
16            //stack: [0; 255],
17            stack: Vec::new(),
18            pc: 0,
19            program,
20            running: true,
21        }
22    }
23
24    pub fn run(&mut self) -> Result<(), SymError> {
25        while self.running && self.pc < self.program.len() {
26            self.pc += 1;
27            let instruction = self.program[self.pc - 1].clone();
28            self.execute_line(instruction)?;
29        }
30        Ok(())
31    }
32
33    fn execute_line(&mut self, instructions: Line) -> Result<(), SymError> {
34        if let Line::Instructions(instructions) = instructions {
35            for instruction in instructions {
36                self.execute(instruction)?;
37            }
38        }
39        Ok(())
40    }
41
42    fn binary_op<F>(&mut self, op: F) -> Result<(), SymError>
43    where
44        F: FnOnce(u8, u8) -> u8,
45    {
46        let a = self.stack.pop().ok_or(SymError::StackUnderflow)?;
47        let b = self.stack.pop().ok_or(SymError::StackUnderflow)?;
48        self.stack.push(op(a, b));
49        Ok(())
50    }
51
52    fn execute(&mut self, instruction: Instruction) -> Result<(), SymError> {
53        match instruction {
54            Instruction::Push(num) => {
55                self.stack.push(num);
56                Ok(())
57            }
58            Instruction::Pop => self.stack.pop().ok_or(SymError::StackUnderflow).map(|_| ()),
59            Instruction::Dup => {
60                let a = *self.stack.last().ok_or(SymError::StackUnderflow)?;
61                self.stack.push(a);
62                Ok(())
63            }
64            Instruction::Swap => {
65                let a = self.stack.pop().ok_or(SymError::StackUnderflow)?;
66                let b = self.stack.pop().ok_or(SymError::StackUnderflow)?;
67                self.stack.push(a);
68                self.stack.push(b);
69                Ok(())
70            }
71            Instruction::Add => Ok(self.binary_op(|a, b| a + b)?),
72            Instruction::Sub => Ok(self.binary_op(|a, b| b - a)?),
73            Instruction::Mul => Ok(self.binary_op(|a, b| a * b)?),
74            Instruction::Div => Ok(self.binary_op(|a, b| b / a)?),
75            Instruction::Mod => Ok(self.binary_op(|a, b| b % a)?),
76            Instruction::Eq => Ok(self.binary_op(|a, b| if a == b { 1 } else { 0 })?),
77            Instruction::Gt => Ok(self.binary_op(|a, b| if b > a { 1 } else { 0 })?),
78            Instruction::Lt => Ok(self.binary_op(|a, b| if b < a { 1 } else { 0 })?),
79            Instruction::Jmp(i) => {
80                self.pc = i - 1;
81                Ok(())
82            }
83            Instruction::Jz(i) => {
84                if self.stack.pop().ok_or(SymError::StackUnderflow)? == 0 {
85                    self.pc = i - 1;
86                }
87                Ok(())
88            }
89            Instruction::Jnz(i) => {
90                if self.stack.pop().ok_or(SymError::StackUnderflow)? != 0 {
91                    self.pc = i - 1;
92                }
93                Ok(())
94            }
95            Instruction::Halt => {
96                self.running = false;
97                Ok(())
98            }
99            Instruction::In => {
100                self.stack.push(utils::input_from_char()?);
101                Ok(())
102            }
103            Instruction::Out => {
104                let a = self.stack.pop().ok_or(SymError::StackUnderflow)?;
105                utils::out_as_char(a);
106                Ok(())
107            }
108            Instruction::DebugIn => {
109                self.stack.push(utils::input_from_u8()?);
110                Ok(())
111            }
112            Instruction::DebugOut => {
113                let a = self.stack.pop().ok_or(SymError::StackUnderflow)?;
114                utils::out_as_u8(a);
115                Ok(())
116            }
117            Instruction::None => Ok(()),
118        }
119    }
120}