diff --git a/src/compiler.rs b/src/compiler.rs index 64425df..66cdb7e 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -41,6 +41,7 @@ pub enum Op { Duplicate, Decrement, Truncate, + MatchDepth, } impl std::fmt::Display for Op { @@ -79,6 +80,7 @@ impl std::fmt::Display for Op { Decrement => "decrement", Truncate => "truncate", Duplicate => "duplicate", + MatchDepth => "match_depth", }; write!(f, "{rep}") } @@ -114,7 +116,7 @@ impl Chunk { println!("{i:04}: {:16} {next:04}: {value}", op.to_string()); } PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump - | JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero => { + | JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero | MatchDepth => { let next = self.bytecode[i + 1]; 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()); } PushBinding | MatchTuple | PushTuple | PushDict | PushList | PushBox | Jump - | JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero => { + | JumpIfFalse | JumpIfNoMatch | JumpBack | JumpIfZero | MatchDepth => { let (_, next) = codes.next().unwrap(); println!("{i:04}: {:16} {next:04}", op.to_string()); } diff --git a/src/main.rs b/src/main.rs index b539c79..8c0e6c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,7 +58,7 @@ pub fn run(src: &'static str) { } let mut vm = Vm::new(&compiler.chunk); - let result = vm.interpret(); + let result = vm.run(); let output = match result { Ok(val) => val.show(&compiler.chunk), Err(panic) => format!("{:?}", panic), diff --git a/src/vm.rs b/src/vm.rs index c201906..c4b8322 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -37,6 +37,7 @@ pub struct Vm<'a> { pub return_register: Value, pub matches: bool, pub match_depth: u8, + pub result: Option>, } impl<'a> Vm<'a> { @@ -48,6 +49,7 @@ impl<'a> Vm<'a> { return_register: Value::Nil, matches: false, match_depth: 0, + result: None, } } @@ -78,9 +80,21 @@ impl<'a> Vm<'a> { self.chunk.dissasemble_instr(self.ip); } - pub fn interpret(&mut self) -> Result { + pub fn run(&mut self) -> &Result { + 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 { - return Ok(self.stack.pop().unwrap()); + self.result = Some(Ok(self.stack.pop().unwrap())); + return; }; if crate::DEBUG_RUN { self.print_debug(); @@ -91,34 +105,28 @@ impl<'a> Vm<'a> { Nil => { self.push(Value::Nil); self.ip += 1; - self.interpret() } True => { self.push(Value::True); self.ip += 1; - self.interpret() } False => { self.push(Value::False); self.ip += 1; - self.interpret() } Constant => { let const_idx = self.chunk.bytecode[self.ip + 1]; let value = self.chunk.constants[const_idx as usize].clone(); self.push(value); self.ip += 2; - self.interpret() } Jump => { let jump_len = self.chunk.bytecode[self.ip + 1]; self.ip += jump_len as usize + 2; - self.interpret() } JumpBack => { let jump_len = self.chunk.bytecode[self.ip + 1]; self.ip -= jump_len as usize; - self.interpret() } JumpIfFalse => { let jump_len = self.chunk.bytecode[self.ip + 1]; @@ -126,11 +134,9 @@ impl<'a> Vm<'a> { match cond { Value::Nil | Value::False => { self.ip += jump_len as usize + 2; - self.interpret() } _ => { self.ip += 2; - self.interpret() } } } @@ -146,44 +152,38 @@ impl<'a> Vm<'a> { self.ip += 2; self.interpret() } - _ => Err(Panic("repeat requires a number")), + _ => self.panic("repeat requires a number"), } } Pop => { self.pop(); self.ip += 1; - self.interpret() } PushBinding => { let binding_idx = self.chunk.bytecode[self.ip + 1] as usize; let binding_value = self.stack[binding_idx].clone(); self.push(binding_value); self.ip += 2; - self.interpret() } Store => { self.return_register = self.pop(); self.push(Value::Nil); self.ip += 1; - self.interpret() } Load => { let mut value = Value::Nil; swap(&mut self.return_register, &mut value); self.push(value); self.ip += 1; - self.interpret() } ResetMatch => { self.matches = false; self.match_depth = 0; self.ip += 1; - self.interpret() } MatchWord => { self.matches = true; self.ip += 1; - self.interpret() } MatchNil => { let idx = self.stack.len() - self.match_depth as usize - 1; @@ -199,7 +199,6 @@ impl<'a> Vm<'a> { self.matches = true; }; self.ip += 1; - self.interpret() } MatchFalse => { let idx = self.stack.len() - self.match_depth as usize - 1; @@ -207,14 +206,12 @@ impl<'a> Vm<'a> { self.matches = true; } self.ip += 1; - self.interpret() } PanicIfNoMatch => { if !self.matches { - Err(Panic("no match")) + self.panic("no match"); } else { self.ip += 1; - self.interpret() } } MatchConstant => { @@ -222,7 +219,6 @@ impl<'a> Vm<'a> { let idx = self.stack.len() - self.match_depth as usize - 1; self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize]; self.ip += 2; - self.interpret() } PushTuple => { 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)); self.stack.push(tuple); self.ip += 2; - self.interpret() } PushList => { 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))); self.stack.push(list); self.ip += 2; - self.interpret() } PushDict => { 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.ip += 2; - self.interpret() } PushBox => { let val = self.pop(); self.stack.push(Value::Box(Rc::new(RefCell::new(val)))); self.ip += 1; - self.interpret() } GetKey => { let key = self.pop(); @@ -274,7 +266,6 @@ impl<'a> Vm<'a> { }; self.push(value); self.ip += 1; - self.interpret() } MatchTuple => { todo!() @@ -286,23 +277,20 @@ impl<'a> Vm<'a> { } else { self.ip += 2; } - self.interpret() } TypeOf => { let val = self.pop(); let type_of = self.chunk.kw_from(val.type_of()).unwrap(); self.push(type_of); self.ip += 1; - self.interpret() } Truncate => { let val = self.pop(); if let Value::Number(x) = val { self.push(Value::Number(x as usize as f64)); self.ip += 1; - self.interpret() } else { - Err(Panic("repeat requires a number")) + self.panic("repeate requires a number"); } } Decrement => { @@ -312,7 +300,7 @@ impl<'a> Vm<'a> { self.ip += 1; self.interpret() } else { - Err(Panic("you may only decrement a number")) + self.panic("you may only decrement a number"); } } Duplicate => { @@ -320,7 +308,12 @@ impl<'a> Vm<'a> { self.ip += 1; 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"), } } }