use crate::{mismatched_types, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type};
pub struct VM {
ip: usize,
pub chunk: Vec<u8>,
pub stack: Vec<Value>,
pub pool: Vec<Value>,
pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions
text: Vec<String>
}
impl VM {
pub fn new(bytecode: Vec<u8>, lines: Vec<(usize, usize)>, pool: Vec<Value>, 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(),
}
}
}