vm::run is now a loop, not vm::interpret as a tailcall

This commit is contained in:
Scott Richmond 2024-12-27 00:47:22 -05:00
parent 8908630a21
commit a7ee8f8e57
3 changed files with 31 additions and 36 deletions

View File

@ -41,6 +41,7 @@ pub enum Op {
Duplicate, Duplicate,
Decrement, Decrement,
Truncate, Truncate,
MatchDepth,
} }
impl std::fmt::Display for Op { impl std::fmt::Display for Op {
@ -79,6 +80,7 @@ impl std::fmt::Display for Op {
Decrement => "decrement", Decrement => "decrement",
Truncate => "truncate", Truncate => "truncate",
Duplicate => "duplicate", Duplicate => "duplicate",
MatchDepth => "match_depth",
}; };
write!(f, "{rep}") write!(f, "{rep}")
} }
@ -114,7 +116,7 @@ impl Chunk {
println!("{i:04}: {:16} {next:04}: {value}", op.to_string()); println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
} }
PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump
| JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero => { | JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero | MatchDepth => {
let next = self.bytecode[i + 1]; let next = self.bytecode[i + 1];
println!("{i:04}: {:16} {next:04}", op.to_string()); println!("{i:04}: {:16} {next:04}", op.to_string());
} }
@ -666,7 +668,7 @@ impl Compiler {
println!("{i:04}: {:16} {next:04}: {value}", op.to_string()); println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
} }
PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump
| JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero => { | JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero | MatchDepth => {
let (_, next) = codes.next().unwrap(); let (_, next) = codes.next().unwrap();
println!("{i:04}: {:16} {next:04}", op.to_string()); println!("{i:04}: {:16} {next:04}", op.to_string());
} }

View File

@ -58,7 +58,7 @@ pub fn run(src: &'static str) {
} }
let mut vm = Vm::new(&compiler.chunk); let mut vm = Vm::new(&compiler.chunk);
let result = vm.interpret(); let result = vm.run();
let output = match result { let output = match result {
Ok(val) => val.show(&compiler.chunk), Ok(val) => val.show(&compiler.chunk),
Err(panic) => format!("{:?}", panic), Err(panic) => format!("{:?}", panic),

View File

@ -37,6 +37,7 @@ pub struct Vm<'a> {
pub return_register: Value, pub return_register: Value,
pub matches: bool, pub matches: bool,
pub match_depth: u8, pub match_depth: u8,
pub result: Option<Result<Value, Panic>>,
} }
impl<'a> Vm<'a> { impl<'a> Vm<'a> {
@ -48,6 +49,7 @@ impl<'a> Vm<'a> {
return_register: Value::Nil, return_register: Value::Nil,
matches: false, matches: false,
match_depth: 0, match_depth: 0,
result: None,
} }
} }
@ -78,9 +80,21 @@ impl<'a> Vm<'a> {
self.chunk.dissasemble_instr(self.ip); self.chunk.dissasemble_instr(self.ip);
} }
pub fn interpret(&mut self) -> Result<Value, Panic> { pub fn run(&mut self) -> &Result<Value, Panic> {
while self.result.is_none() {
self.interpret();
}
self.result.as_ref().unwrap()
}
pub fn panic(&mut self, msg: &'static str) {
self.result = Some(Err(Panic(msg)));
}
pub fn interpret(&mut self) {
let Some(byte) = self.chunk.bytecode.get(self.ip) else { let Some(byte) = self.chunk.bytecode.get(self.ip) else {
return Ok(self.stack.pop().unwrap()); self.result = Some(Ok(self.stack.pop().unwrap()));
return;
}; };
if crate::DEBUG_RUN { if crate::DEBUG_RUN {
self.print_debug(); self.print_debug();
@ -91,34 +105,28 @@ impl<'a> Vm<'a> {
Nil => { Nil => {
self.push(Value::Nil); self.push(Value::Nil);
self.ip += 1; self.ip += 1;
self.interpret()
} }
True => { True => {
self.push(Value::True); self.push(Value::True);
self.ip += 1; self.ip += 1;
self.interpret()
} }
False => { False => {
self.push(Value::False); self.push(Value::False);
self.ip += 1; self.ip += 1;
self.interpret()
} }
Constant => { Constant => {
let const_idx = self.chunk.bytecode[self.ip + 1]; let const_idx = self.chunk.bytecode[self.ip + 1];
let value = self.chunk.constants[const_idx as usize].clone(); let value = self.chunk.constants[const_idx as usize].clone();
self.push(value); self.push(value);
self.ip += 2; self.ip += 2;
self.interpret()
} }
Jump => { Jump => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk.bytecode[self.ip + 1];
self.ip += jump_len as usize + 2; self.ip += jump_len as usize + 2;
self.interpret()
} }
JumpBack => { JumpBack => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk.bytecode[self.ip + 1];
self.ip -= jump_len as usize; self.ip -= jump_len as usize;
self.interpret()
} }
JumpIfFalse => { JumpIfFalse => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk.bytecode[self.ip + 1];
@ -126,11 +134,9 @@ impl<'a> Vm<'a> {
match cond { match cond {
Value::Nil | Value::False => { Value::Nil | Value::False => {
self.ip += jump_len as usize + 2; self.ip += jump_len as usize + 2;
self.interpret()
} }
_ => { _ => {
self.ip += 2; self.ip += 2;
self.interpret()
} }
} }
} }
@ -146,44 +152,38 @@ impl<'a> Vm<'a> {
self.ip += 2; self.ip += 2;
self.interpret() self.interpret()
} }
_ => Err(Panic("repeat requires a number")), _ => self.panic("repeat requires a number"),
} }
} }
Pop => { Pop => {
self.pop(); self.pop();
self.ip += 1; self.ip += 1;
self.interpret()
} }
PushBinding => { PushBinding => {
let binding_idx = self.chunk.bytecode[self.ip + 1] as usize; let binding_idx = self.chunk.bytecode[self.ip + 1] as usize;
let binding_value = self.stack[binding_idx].clone(); let binding_value = self.stack[binding_idx].clone();
self.push(binding_value); self.push(binding_value);
self.ip += 2; self.ip += 2;
self.interpret()
} }
Store => { Store => {
self.return_register = self.pop(); self.return_register = self.pop();
self.push(Value::Nil); self.push(Value::Nil);
self.ip += 1; self.ip += 1;
self.interpret()
} }
Load => { Load => {
let mut value = Value::Nil; let mut value = Value::Nil;
swap(&mut self.return_register, &mut value); swap(&mut self.return_register, &mut value);
self.push(value); self.push(value);
self.ip += 1; self.ip += 1;
self.interpret()
} }
ResetMatch => { ResetMatch => {
self.matches = false; self.matches = false;
self.match_depth = 0; self.match_depth = 0;
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchWord => { MatchWord => {
self.matches = true; self.matches = true;
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchNil => { MatchNil => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
@ -199,7 +199,6 @@ impl<'a> Vm<'a> {
self.matches = true; self.matches = true;
}; };
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchFalse => { MatchFalse => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
@ -207,14 +206,12 @@ impl<'a> Vm<'a> {
self.matches = true; self.matches = true;
} }
self.ip += 1; self.ip += 1;
self.interpret()
} }
PanicIfNoMatch => { PanicIfNoMatch => {
if !self.matches { if !self.matches {
Err(Panic("no match")) self.panic("no match");
} else { } else {
self.ip += 1; self.ip += 1;
self.interpret()
} }
} }
MatchConstant => { MatchConstant => {
@ -222,7 +219,6 @@ impl<'a> Vm<'a> {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize]; self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize];
self.ip += 2; self.ip += 2;
self.interpret()
} }
PushTuple => { PushTuple => {
let tuple_len = self.chunk.bytecode[self.ip + 1]; let tuple_len = self.chunk.bytecode[self.ip + 1];
@ -230,7 +226,6 @@ impl<'a> Vm<'a> {
let tuple = Value::Tuple(Rc::new(tuple_members)); let tuple = Value::Tuple(Rc::new(tuple_members));
self.stack.push(tuple); self.stack.push(tuple);
self.ip += 2; self.ip += 2;
self.interpret()
} }
PushList => { PushList => {
let list_len = self.chunk.bytecode[self.ip + 1]; let list_len = self.chunk.bytecode[self.ip + 1];
@ -238,7 +233,6 @@ impl<'a> Vm<'a> {
let list = Value::List(Box::new(Vector::from(list_members))); let list = Value::List(Box::new(Vector::from(list_members)));
self.stack.push(list); self.stack.push(list);
self.ip += 2; self.ip += 2;
self.interpret()
} }
PushDict => { PushDict => {
let dict_len = self.chunk.bytecode[self.ip + 1] as usize * 2; let dict_len = self.chunk.bytecode[self.ip + 1] as usize * 2;
@ -254,13 +248,11 @@ impl<'a> Vm<'a> {
} }
self.stack.push(Value::Dict(Box::new(dict))); self.stack.push(Value::Dict(Box::new(dict)));
self.ip += 2; self.ip += 2;
self.interpret()
} }
PushBox => { PushBox => {
let val = self.pop(); let val = self.pop();
self.stack.push(Value::Box(Rc::new(RefCell::new(val)))); self.stack.push(Value::Box(Rc::new(RefCell::new(val))));
self.ip += 1; self.ip += 1;
self.interpret()
} }
GetKey => { GetKey => {
let key = self.pop(); let key = self.pop();
@ -274,7 +266,6 @@ impl<'a> Vm<'a> {
}; };
self.push(value); self.push(value);
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchTuple => { MatchTuple => {
todo!() todo!()
@ -286,23 +277,20 @@ impl<'a> Vm<'a> {
} else { } else {
self.ip += 2; self.ip += 2;
} }
self.interpret()
} }
TypeOf => { TypeOf => {
let val = self.pop(); let val = self.pop();
let type_of = self.chunk.kw_from(val.type_of()).unwrap(); let type_of = self.chunk.kw_from(val.type_of()).unwrap();
self.push(type_of); self.push(type_of);
self.ip += 1; self.ip += 1;
self.interpret()
} }
Truncate => { Truncate => {
let val = self.pop(); let val = self.pop();
if let Value::Number(x) = val { if let Value::Number(x) = val {
self.push(Value::Number(x as usize as f64)); self.push(Value::Number(x as usize as f64));
self.ip += 1; self.ip += 1;
self.interpret()
} else { } else {
Err(Panic("repeat requires a number")) self.panic("repeate requires a number");
} }
} }
Decrement => { Decrement => {
@ -312,7 +300,7 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
self.interpret() self.interpret()
} else { } else {
Err(Panic("you may only decrement a number")) self.panic("you may only decrement a number");
} }
} }
Duplicate => { Duplicate => {
@ -320,7 +308,12 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
self.interpret() self.interpret()
} }
PanicNoWhen | PanicNoMatch => Err(Panic("no match")), MatchDepth => {
self.match_depth = self.chunk.bytecode[self.ip + 1];
self.ip += 2;
self.interpret()
}
PanicNoWhen | PanicNoMatch => self.panic("no match"),
} }
} }
} }