#[derive(Clone, Copy, Debug)] enum Instruction { LoadInt { dst: u8, value: i16 }, Copy { dst: u8, src: u8 }, Add { dst: u8, src1: u8, src2: u8 }, Sub { dst: u8, src1: u8, src2: u8 }, Call { func: u8, arg: u8, dst: u8 }, Return { src: u8 }, JumpNotLess { target: u8, src1: u8, src2: u8 }, } struct Function { code: Vec, num_registers: usize, } struct Vm { functions: Vec, stack: Vec, } impl Vm { pub fn new() -> Vm { Vm { functions: vec![], stack: vec![], } } pub fn call(&mut self, func: u8, arg: i64) -> i64 { let func = func as usize; let base_pointer = self.stack.len(); { let function = &self.functions[func]; let stack_top = base_pointer + function.num_registers; self.stack.resize(stack_top, 0); self.stack[base_pointer] = arg; } let bp = base_pointer; let mut program_counter = 0; loop { let func = &self.functions[func]; let instr = func.code[program_counter]; program_counter += 1; match instr { Instruction::LoadInt { dst, value } => { *self.reg(bp, dst) = value as i64; } Instruction::Copy { dst, src } => { *self.reg(bp, dst) = *self.reg(bp, src); } Instruction::Add { dst, src1, src2 } => { *self.reg(bp, dst) = *self.reg(bp, src1) + *self.reg(bp, src2); } Instruction::Sub { dst, src1, src2 } => { *self.reg(bp, dst) = *self.reg(bp, src1) - *self.reg(bp, src2); } Instruction::Call { func, arg, dst } => { let arg = *self.reg(bp, arg); let result = self.call(func, arg); *self.reg(bp, dst) = result; } Instruction::Return { src } => { let result = *self.reg(bp, src); self.stack.truncate(base_pointer); return result; } Instruction::JumpNotLess { target, src1, src2 } => { let src1 = *self.reg(bp, src1); let src2 = *self.reg(bp, src2); if !(src1 < src2) { program_counter = target as usize; } } } } } fn reg(&mut self, base_pointer: usize, index: u8) -> &mut i64 { &mut self.stack[base_pointer + index as usize] } } fn main() { let mut vm = Vm::new(); let fib = 0; vm.functions.push(Function { code: { let n = 0; let two = 1; let one = 2; let temp = 3; let recursive_1 = 4; let recursive_2 = 5; let result = 6; vec![ Instruction::LoadInt { dst: two, value: 2 }, Instruction::JumpNotLess { target: 3, src1: n, src2: two }, Instruction::Return { src: n }, Instruction::Sub { dst: temp, src1: n, src2: two }, Instruction::Call { func: fib, arg: temp, dst: recursive_1 }, Instruction::LoadInt { dst: one, value: 1 }, Instruction::Sub { dst: temp, src1: n, src2: one }, Instruction::Call { func: fib, arg: temp, dst: recursive_2 }, Instruction::Add { dst: result, src1: recursive_1, src2: recursive_2 }, Instruction::Return { src: result }, ] }, num_registers: 7, }); for i in 0..10 { println!("fib({}) = {}", i, vm.call(fib, i)); } }