use std::fmt; use crate::value::Value; #[derive(Debug)] pub enum OpCode { Constant(usize), Add, Subtract, Multiply, Divide, Negate, Return, } #[derive(Debug, Default)] pub struct Chunk { pub code: Vec, pub lines: Vec, pub constants: Vec, } impl Chunk { pub fn push(&mut self, op_code: OpCode, line: usize) { self.code.push(op_code); self.lines.push(line); } pub fn push_constant(&mut self, value: Value, line: usize) { self.constants.push(value); self.push(OpCode::Constant(self.constants.len() - 1), line) } pub fn disassemble(&self, name: &str) { println!("== {} ==\n{}", name, self); } } impl fmt::Display for Chunk { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for i in 0..self.code.len() { writeln!(f, "{}", DisassembledInstruction { i, chunk: self })?; } Ok(()) } } pub struct DisassembledInstruction<'a> { i: usize, chunk: &'a Chunk, } impl<'a> DisassembledInstruction<'a> { pub fn new(i: usize, chunk: &'a Chunk) -> Self { Self { i, chunk } } } impl fmt::Display for DisassembledInstruction<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:04} ", self.i)?; let line = self.chunk.lines[self.i]; if self.i > 0 && line != self.chunk.lines[self.i - 1] { write!(f, " | ")?; } else { write!(f, "{:>4} ", line)?; } match self.chunk.code[self.i] { OpCode::Constant(constant) => write!( f, "{:<16} {:4} '{}'", "OP_CONSTANT", constant, self.chunk.constants[constant] )?, OpCode::Add => write!(f, "OP_ADD")?, OpCode::Subtract => write!(f, "OP_SUBTRACT")?, OpCode::Multiply => write!(f, "OP_MULTIPLY")?, OpCode::Divide => write!(f, "OP_DIVIDE")?, OpCode::Negate => write!(f, "OP_NEGATE")?, OpCode::Return => write!(f, "OP_RETURN")?, } Ok(()) } }