use crate::compiler::{Chunk, Op}; use crate::parser::Ast; use crate::spans::Spanned; use crate::value::Value; use chumsky::prelude::SimpleSpan; use num_traits::FromPrimitive; use std::mem::swap; #[derive(Debug, Clone, PartialEq)] pub struct Panic { pub input: &'static str, pub src: &'static str, pub msg: String, pub span: SimpleSpan, pub trace: Vec, pub extra: String, } #[derive(Debug, Clone, PartialEq)] pub struct Trace { pub callee: Spanned, pub caller: Spanned, pub function: Value, pub arguments: Value, pub input: &'static str, pub src: &'static str, } pub struct Vm<'a> { pub stack: Vec, pub chunk: &'a Chunk<'a>, pub ip: usize, pub return_register: Value, } impl<'a> Vm<'a> { pub fn new(chunk: &'a Chunk) -> Vm<'a> { Vm { chunk, stack: vec![], ip: 0, return_register: Value::Nil, } } pub fn push(&mut self, value: Value) { self.stack.push(value); } pub fn pop(&mut self) -> Value { self.stack.pop().unwrap() } fn print_stack(&self) { let inner = self .stack .iter() .map(|val| val.to_string()) .collect::>() .join("|"); println!("{:04}: [{inner}] {}", self.ip, self.return_register); } fn print_debug(&self) { self.chunk.dissasemble_instr(self.ip); self.print_stack(); } pub fn interpret(&mut self) -> Result { let Some(byte) = self.chunk.bytecode.get(self.ip) else { return Ok(self.stack.pop().unwrap()); }; if crate::DEBUG_RUN { self.print_debug(); } let op = Op::from_u8(*byte).unwrap(); use Op::*; match op { Constant => { let const_idx = self.chunk.bytecode[self.ip + 1]; let value = self.chunk.constants[const_idx as usize].clone(); self.push(value); self.ip += 2; self.interpret() } Jump => { let jump_len = self.chunk.bytecode[self.ip + 1]; self.ip += jump_len as usize; self.interpret() } JumpIfFalse => { let jump_len = self.chunk.bytecode[self.ip + 1]; let cond = self.pop(); match cond { Value::Nil | Value::False => { self.ip += jump_len as usize + 2; self.interpret() } _ => { self.ip += 2; self.interpret() } } } Pop => { self.pop(); self.ip += 1; self.interpret() } PushBinding => { let binding_idx = self.chunk.bytecode[self.ip + 1] as usize; let binding_value = self.stack[binding_idx].clone(); self.push(binding_value); self.ip += 2; self.interpret() } Store => { self.return_register = self.pop(); self.push(Value::Nil); self.ip += 1; self.interpret() } Load => { let mut value = Value::Nil; // println!( // "before swap, return register holds: {}", // self.return_register // ); swap(&mut self.return_register, &mut value); // println!( // "before swap, return register holds: {}", // self.return_register // ); // println!("now local value holds {value}"); self.push(value); self.ip += 1; self.interpret() } } } }