[rlox] Dedop tracing
This commit is contained in:
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
106
rlox/src/vm.rs
106
rlox/src/vm.rs
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user