[rlox] Dedop tracing

This commit is contained in:
ctsk
2023-03-30 20:17:00 +02:00
parent acc95c36e9
commit 278bcf5a54
2 changed files with 85 additions and 38 deletions

View File

@@ -2,8 +2,13 @@ mod vm;
fn main() { fn main() {
let mut chunk = vm::Chunk::new("TEST".to_string()); let mut chunk = vm::Chunk::new("TEST".to_string());
chunk.add_op(vm::Op::Return, 1);
chunk.add_op(vm::Op::Constant { offset: 0 }, 1);
chunk.add_constant(vm::Value::from(3.14)); chunk.add_constant(vm::Value::from(3.14));
chunk.add_op(vm::Op::Constant { offset: 0 }, 1);
chunk.add_op(vm::Op::Negate, 1);
chunk.add_op(vm::Op::Return, 1);
println!("{:?}", chunk); println!("{:?}", chunk);
let mut interpreter = vm::VM::new();
interpreter.trace = true;
interpreter.interpret(&chunk).unwrap()
} }

View File

@@ -6,6 +6,7 @@ use std::fmt;
pub enum Op { pub enum Op {
Return, Return,
Constant { offset: usize }, Constant { offset: usize },
Negate,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@@ -57,70 +58,111 @@ impl fmt::Debug for Chunk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
writeln!(f, "-*-*- {} -*-*-", self.name)?; writeln!(f, "-*-*- {} -*-*-", self.name)?;
for (idx, op) in self.code.iter().copied().enumerate() { for (idx, op) in self.code.iter().copied().enumerate() {
write!(f, "{:04} ", idx)?; writeln!(f, "{:?}", TraceInfo {
offset: idx,
let line = self.debug_info[idx]; op: op,
chunk: &self
if idx > 0 && self.debug_info[idx-1] == line { })?;
write!(f, " | ")
} else {
write!(f, "{:4} ", line)
}?;
match op {
Op::Return => writeln!(f, "{:?}", op),
Op::Constant { offset } =>
f.debug_struct("Constant")
.field("val", &self.constants[offset].val)
.finish(),
}?;
} }
return Ok(()); return Ok(());
} }
} }
const VM_STACK_SIZE: usize = 256; struct TraceInfo<'a> {
offset: usize,
struct VM { op: Op,
trace: bool, chunk: &'a Chunk
stack: Vec<Value>,
code: Chunk
} }
enum VMError { impl fmt::Debug for TraceInfo<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let chunk = self.chunk;
let op = self.op;
let offset = self.offset;
write!(f, "{:04} ", offset)?;
let line = chunk.debug_info[offset];
if offset > 0 && chunk.debug_info[offset-1] == line {
write!(f, " | ")
} else {
write!(f, "{:4} ", line)
}?;
match op {
Op::Return | Op::Negate => write!(f, "{:?}", op),
Op::Constant { offset } => {
f.debug_struct("Constant")
.field("val", &chunk.constants[offset].val)
.finish()?;
write!(f, "")
},
}
}
}
pub struct VM {
pub trace: bool,
stack: Vec<Value>,
pc: usize,
}
#[derive(Debug)]
pub enum VMError {
Compile, Compile,
Runtime Runtime
} }
impl VM { impl VM {
pub fn new() -> VM {
VM {
trace: false,
stack: Vec::new(),
pc: 0,
}
}
fn push(&mut self, value: Value) { fn push(&mut self, value: Value) {
self.stack.push(value); self.stack.push(value);
} }
fn pop(&mut self) -> Value { fn pop(&mut self) -> Result<Value, VMError> {
self.stack.pop().unwrap() self.stack.pop().ok_or(VMError::Runtime)
} }
pub fn interpret(&mut self, chunk: &Chunk) -> Result<(), VMError> { pub fn interpret(&mut self, chunk: &Chunk) -> Result<(), VMError> {
for instr in chunk.code.iter().copied() { while self.pc < chunk.code.len() {
let instr = chunk.code[self.pc];
self.pc += 1;
if self.trace { if self.trace {
print!(" [ "); print!(" [ ");
for value in self.stack.iter() { for value in self.stack.iter() {
println!("{:?} | ", value); print!("{:?} | ", value);
} }
println!("_ ]"); println!("_ ]\n");
println!("{:?}", instr);
println!("{:?}\n", TraceInfo {
offset: self.pc - 1,
op: instr,
chunk: chunk
});
} }
match instr { match instr {
Op::Return => { Op::Return => {
print!("{:?}", self.pop()); print!("{:?}", self.pop()?);
return Ok(()) return Ok(())
}, },
Op::Constant { offset } => { Op::Constant { offset } => {
self.push(self.code.constants[offset]) self.push(chunk.constants[offset])
}
Op::Negate => {
let new_val = -self.pop()?.val;
self.push(Value::from(new_val));
} }
} }
} }