use crate::{mismatched_types, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type}; pub struct VM { ip: usize, pub chunk: Vec, pub stack: Vec, pub pool: Vec, pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions text: Vec } impl VM { pub fn new(bytecode: Vec, lines: Vec<(usize, usize)>, pool: Vec, text: String) -> Self { Self { ip: 0, chunk: bytecode, stack: Vec::new(), pool, lines, text: text.lines().map(|s| s.to_string()).collect(), } } pub fn run(&mut self, output: &mut String) -> Result<(), KabelRuntimeError> { use Value::*; while self.ip < self.chunk.len() { match self.read() { 0x00 => { // CONSTANT let byte = self.read() as usize; self.stack.push(self.pool[byte].clone()); } 0x01 => { // ADD match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)), (Str(v1), Str(v2)) => { self.stack.push(Str(v1 + &v2)); }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot add booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x02 => { // SUB match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)), (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot subtract strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot subtract booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x03 => { // MUL match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)), (Str(v1), Num(v2)) => { if v2.fract() == 0.0 { self.stack.push(Str(v1.repeat(v2 as usize))); } else { return Err(wrong_type!(self, "Number must be an integer")) } } (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot multiply strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot multiply booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x04 => { // DIV match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)), (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot divide strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot divide booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x05 => { // MOD match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)), (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot perform modulus on strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot perform modulus on booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x06 => { // BITAND match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { return Err(wrong_type!(self, "Cannot perform bitwise AND on {}", v1)) } if v2.fract() != 0.0 { return Err(wrong_type!(self, "Cannot perform bitwise AND on {}", v2)) } self.stack.push(Num((v1 as u32 & v2 as u32) as f32)) } (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot perform bitwise AND on strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot perform bitwise AND on booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x07 => { // BITXOR match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { return Err(wrong_type!(self, "Cannot perform bitwise XOR on {}", v1)) } if v2.fract() != 0.0 { return Err(wrong_type!(self, "Cannot perform bitwise XOR on {}", v2)) } self.stack.push(Num((v1 as u32 ^ v2 as u32) as f32)) } (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot perform bitwise XOR on strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot perform bitwise XOR on booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } 0x08 => { // BITOR match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { return Err(wrong_type!(self, "Cannot perform bitwise OR on {}", v1)) } if v2.fract() != 0.0 { return Err(wrong_type!(self, "Cannot perform bitwise OR on {}", v2)) } self.stack.push(Num((v1 as u32 | v2 as u32) as f32)) } (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot perform bitwise OR on strings")) }, (Bool(_v1), Bool(_v2)) => { return Err(wrong_type!(self, "Cannot perform bitwise OR on booleans")) } (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } // EQ 0x09 => vm_boolean_binary!(self, ==), // NE 0x0A => vm_boolean_binary!(self, !=), // GR 0x0B => vm_boolean_binary!(self, >), // GE 0x0C => vm_boolean_binary!(self, >=), // LS 0x0D => vm_boolean_binary!(self, <), // LE 0x0E => vm_boolean_binary!(self, <=), // OR 0x0F => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(_v1), Num(_v2)) => { return Err(wrong_type!(self, "Cannot perform logical OR on numbers")) } (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot perform logical OR on strings")) }, (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 || v2)), (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } // AND 0x10 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(_v1), Num(_v2)) => { return Err(wrong_type!(self, "Cannot perform logical AND on numbers")) } (Str(_v1), Str(_v2)) => { return Err(wrong_type!(self, "Cannot perform logical AND on strings")) }, (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 && v2)), (v1, v2) => { return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } // NOT 0x11 => match self.stack.pop().unwrap() { Num(_v1) => { return Err(wrong_type!(self, "Cannot perform logical NOT on numbers")) } Str(_v1) => { return Err(wrong_type!(self, "Cannot perform logical NOT on strings")) } Bool(v1) => self.stack.push(Bool(!v1)), } // NEG 0x12 => match self.stack.pop().unwrap() { Num(v1) => self.stack.push(Num(-v1)), Str(_v1) => { return Err(wrong_type!(self, "Cannot negate strings")) } Bool(_v1) => { return Err(wrong_type!(self, "Cannot negate bools")) } } // JMP 0x13 => { let loc = self.read_u16(); self.ip += loc as usize; } // IF_NE 0x14 => { let condition = self.stack.pop().unwrap(); if let Value::Bool(condition) = condition { if !condition { let loc = self.read_u16(); self.ip += loc as usize; } else { self.read_u16(); } } else { return Err(wrong_type!(self, "if must have condition of type boolean")) } } 0xFD => { // POP self.stack.pop().unwrap(); } 0xFE => { // PRINT let value = self.stack.pop().unwrap(); match value { Num(v) => *output += &v.to_string(), Str(v) => *output += &v, Bool(v) => *output += &v.to_string(), } *output += "\n"; } _ => {} } } Ok(()) } pub fn read(&mut self) -> u8 { let byte = self.chunk[self.ip]; self.ip += 1; byte } pub fn read_u16(&mut self) -> u16 { let byte_one = (self.chunk[self.ip] as u16) << 0x08; self.ip += 1; let byte_two = self.chunk[self.ip] as u16; self.ip += 1; byte_one | byte_two } pub fn find_line(&mut self) -> usize { // returns line # at ip let mut line_ip = 0; for (line, rep) in self.lines.clone() { if line_ip + rep > self.ip { return line; } line_ip += rep; } panic!("Something went wrong in finding line for error") } } #[derive(Debug, Clone)] pub enum Value { Num(f32), Str(String), Bool(bool), } impl Value { pub fn type_str(&self) -> String { match self { Value::Num(_) => "number".to_string(), Value::Str(_) => "string".to_string(), Value::Bool(_) => "bool".to_string(), } } }