vm::run is now a loop, not vm::interpret as a tailcall
This commit is contained in:
parent
8908630a21
commit
a7ee8f8e57
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
59
src/vm.rs
59
src/vm.rs
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user