diff options
| author | Cody <cody@codyq.dev> | 2023-04-11 17:34:11 -0500 |
|---|---|---|
| committer | Cody <cody@codyq.dev> | 2023-04-11 17:34:11 -0500 |
| commit | ee079d193b6644e65543c3fa02dbfcf7b4f2f9c6 (patch) | |
| tree | 80975f19a2fcbd909beee83f2000f3dcabac1d9a /crates/sloth_vm/src/vm.rs | |
| parent | 7451bdb02d54243eb299dde55f22d3b06ac5b2f2 (diff) | |
| download | sloth-ee079d193b6644e65543c3fa02dbfcf7b4f2f9c6.tar.gz | |
Hehehe
Diffstat (limited to 'crates/sloth_vm/src/vm.rs')
| -rw-r--r-- | crates/sloth_vm/src/vm.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/crates/sloth_vm/src/vm.rs b/crates/sloth_vm/src/vm.rs new file mode 100644 index 0000000..22b769b --- /dev/null +++ b/crates/sloth_vm/src/vm.rs @@ -0,0 +1,140 @@ +use sloth_bytecode::Instruction; + +use crate::{Chunk, Data, Stack}; + +pub struct VM { + vm_return: Option<Data>, + stack: Stack, +} + +impl VM { + fn new() -> Self { + Self { + vm_return: None, + stack: Stack::default(), + } + } + + fn execute(&mut self) { + loop { + self.execute_once(); + } + } + + fn execute_once(&mut self) { + // + } + + fn run(&mut self, chunk: &Chunk) { + let mut pointer = 0; + + loop { + let instruction = Instruction::disassemble(&chunk.code, &mut pointer); + + match instruction { + Instruction::Constant(idx) => { + let value = chunk.constants[idx as usize]; + self.stack.push(value); + } + Instruction::Load(_) => todo!(), + Instruction::Push(_) => todo!(), + Instruction::Dup => { + let value = self.stack.pop(); + self.stack.push(value); + self.stack.push(value); + } + Instruction::Del => { + self.stack.pop(); + } + Instruction::Add => { + let value = match self.stack.pop2() { + (Data::Integer(lhs), Data::Integer(rhs)) => Data::Integer(lhs + rhs), + (Data::Float(lhs), Data::Float(rhs)) => Data::Float(lhs + rhs), + _ => panic!(), + }; + + self.stack.push(value); + } + Instruction::Sub => { + let value = match self.stack.pop2() { + (Data::Integer(lhs), Data::Integer(rhs)) => Data::Integer(lhs - rhs), + (Data::Float(lhs), Data::Float(rhs)) => Data::Float(lhs - rhs), + _ => panic!(), + }; + + self.stack.push(value); + } + Instruction::Mul => { + let value = match self.stack.pop2() { + (Data::Integer(lhs), Data::Integer(rhs)) => Data::Integer(lhs * rhs), + (Data::Float(lhs), Data::Float(rhs)) => Data::Float(lhs * rhs), + _ => panic!(), + }; + + self.stack.push(value); + } + Instruction::Div => { + let value = match self.stack.pop2() { + (Data::Integer(lhs), Data::Integer(rhs)) => Data::Integer(lhs / rhs), + (Data::Float(lhs), Data::Float(rhs)) => Data::Float(lhs / rhs), + _ => panic!(), + }; + + self.stack.push(value); + } + Instruction::Mod => { + let value = match self.stack.pop2() { + (Data::Integer(lhs), Data::Integer(rhs)) => Data::Integer(lhs % rhs), + (Data::Float(lhs), Data::Float(rhs)) => Data::Float(lhs % rhs), + _ => panic!(), + }; + + self.stack.push(value); + } + Instruction::Hlt => break, + Instruction::Exit => break, + Instruction::VMReturn => { + let value = self.stack.pop(); + self.vm_return = Some(value); + break; + } + _ => unimplemented!(), + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::{Chunk, Data, VM}; + + #[test] + fn arithmetic_ops() { + let mut vm = VM::new(); + + // Addition + vm.run(&Chunk { + constants: vec![Data::Integer(7)], + code: vec![ + 0x00, 0, 0, 0, 0, // Load constant from 0 + 0x10, // Duplicate + 0x20, // Add + 0xF0, // Return VM + ], + }); + + assert_eq!(vm.vm_return, Some(Data::Integer(14))); + + vm.run(&Chunk { + constants: vec![Data::Integer(2), Data::Integer(11)], + code: vec![ + 0x00, 0, 0, 0, 0, // Load constant from 0 + 0x00, 0, 0, 0, 1, // Load constant from 1 + 0x20, // Add + 0xF0, // Return VM + ], + }); + + assert_eq!(vm.vm_return, Some(Data::Integer(13))); + } +} |
