diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/vm.rs | 360 |
1 files changed, 188 insertions, 172 deletions
@@ -178,6 +178,11 @@ pub struct VM { print_ops: bool, } +enum OpResult { + Continue, + Done, +} + impl VM { pub fn new() -> Self { Self { @@ -229,222 +234,233 @@ impl VM { } } - pub fn run(&mut self, block: Rc<Block>) -> Result<(), Error>{ - crate::typer::VM::new().print_ops(self.print_ops) - .print_blocks(self.print_blocks) - .typecheck(Type::Void, Rc::clone(&block))?; - - self.frames.push(Frame { - stack_offset: 0, - block, - ip: 0 - }); + fn eval_op(&mut self, op: &Op) -> Result<OpResult, Error> { + match op { + Op::Illegal => { + error!(self, ErrorKind::InvalidProgram); + } - if self.print_blocks { - self.frame().block.debug_print(); - } + Op::Unreachable => { + error!(self, ErrorKind::Unreachable); + } - loop { - if self.print_ops { - let start = self.frame().stack_offset; - print!(" {:3} [", start); - for (i, s) in self.stack.iter().skip(start).enumerate() { - if i != 0 { - print!(" "); - } - print!("{:?}", s.green()); - } - println!("]"); + Op::Pop => { + self.stack.pop(); + } - println!("{:5} {:05} {:?}", - self.frame().block.line(self.frame().ip).red(), - self.frame().ip.blue(), - self.frame().block.ops[self.frame().ip]); + Op::Constant(value) => { + self.stack.push(value.clone()); } - let op = self.frame().block.ops[self.frame().ip].clone(); - match op { - Op::Illegal => { - error!(self, ErrorKind::InvalidProgram); + Op::Neg => { + match self.stack.pop().unwrap() { + Value::Float(a) => self.stack.push(Value::Float(-a)), + Value::Int(a) => self.stack.push(Value::Int(-a)), + a => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a])), } + } - Op::Unreachable => { - error!(self, ErrorKind::Unreachable); + Op::Add => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a + b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a + b)), + (Value::String(a), Value::String(b)) => { + self.stack.push(Value::String(Rc::from(format!("{}{}", a, b)))) + } + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Pop => { - self.stack.pop(); + Op::Sub => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a - b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a - b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Constant(value) => { - self.stack.push(value.clone()); + Op::Mul => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a * b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a * b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Neg => { - match self.stack.pop().unwrap() { - Value::Float(a) => self.stack.push(Value::Float(-a)), - Value::Int(a) => self.stack.push(Value::Int(-a)), - a => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a])), - } + Op::Div => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a / b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a / b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Add => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a + b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a + b)), - (Value::String(a), Value::String(b)) => { - self.stack.push(Value::String(Rc::from(format!("{}{}", a, b)))) - } - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::Equal => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a == b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a == b)), + (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a == b)), + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a == b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Sub => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a - b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a - b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::Less => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a < b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a < b)), + (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a < b)), + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a < b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Mul => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a * b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a * b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::Greater => { + match self.pop_twice() { + (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a > b)), + (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a > b)), + (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a > b)), + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a > b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Div => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a / b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a / b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::And => { + match self.pop_twice() { + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Equal => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a == b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a == b)), - (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a == b)), - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a == b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::Or => { + match self.pop_twice() { + (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)), + (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), } + } - Op::Less => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a < b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a < b)), - (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a < b)), - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a < b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::Not => { + match self.stack.pop().unwrap() { + Value::Bool(a) => self.stack.push(Value::Bool(!a)), + a => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a])), } + } - Op::Greater => { - match self.pop_twice() { - (Value::Float(a), Value::Float(b)) => self.stack.push(Value::Bool(a > b)), - (Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a > b)), - (Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a > b)), - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a > b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } - } + Op::Jmp(line) => { + self.frame_mut().ip = *line; + return Ok(OpResult::Continue); + } - Op::And => { - match self.pop_twice() { - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::JmpFalse(line) => { + if matches!(self.stack.pop(), Some(Value::Bool(false))) { + self.frame_mut().ip = *line; + return Ok(OpResult::Continue); } + } - Op::Or => { - match self.pop_twice() { - (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)), - (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])), - } + Op::Assert => { + if matches!(self.stack.pop(), Some(Value::Bool(false))) { + error!(self, ErrorKind::Assert); } + self.stack.push(Value::Bool(true)); + } - Op::Not => { - match self.stack.pop().unwrap() { - Value::Bool(a) => self.stack.push(Value::Bool(!a)), - a => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a])), - } - } + Op::ReadLocal(slot) => { + let slot = self.frame().stack_offset + slot; + self.stack.push(self.stack[slot].clone()); + } - Op::Jmp(line) => { - self.frame_mut().ip = line; - continue; - } + Op::Assign(slot) => { + let slot = self.frame().stack_offset + slot; + self.stack[slot] = self.stack.pop().unwrap(); + } - Op::JmpFalse(line) => { - if matches!(self.stack.pop(), Some(Value::Bool(false))) { - self.frame_mut().ip = line; - continue; + Op::Define(_) => {} + + Op::Call(num_args) => { + let new_base = self.stack.len() - 1 - num_args; + match &self.stack[new_base] { + Value::Function(args, _ret, block) => { + if args.len() != *num_args { + error!(self, + ErrorKind::InvalidProgram, + format!("Invalid number of arguments, got {} expected {}.", + num_args, args.len())); + } + if self.print_blocks { + block.debug_print(); + } + self.frames.push(Frame { + stack_offset: new_base, + block: Rc::clone(&block), + ip: 0, + }); + return Ok(OpResult::Continue); + }, + _ => { + unreachable!() } } + } - Op::Assert => { - if matches!(self.stack.pop(), Some(Value::Bool(false))) { - error!(self, ErrorKind::Assert); - } - self.stack.push(Value::Bool(true)); - } + Op::Print => { + println!("PRINT: {:?}", self.stack.pop().unwrap()); + } - Op::ReadLocal(slot) => { - let slot = self.frame().stack_offset + slot; - self.stack.push(self.stack[slot].clone()); + Op::Return => { + let last = self.frames.pop().unwrap(); + if self.frames.is_empty() { + return Ok(OpResult::Done); + } else { + self.stack[last.stack_offset] = self.stack.pop().unwrap(); } + } + } + self.frame_mut().ip += 1; + Ok(OpResult::Continue) + } - Op::Assign(slot) => { - let slot = self.frame().stack_offset + slot; - self.stack[slot] = self.stack.pop().unwrap(); - } + pub fn print_stack(&mut self) { + let start = self.frame().stack_offset; + print!(" {:3} [", start); + for (i, s) in self.stack.iter().skip(start).enumerate() { + if i != 0 { + print!(" "); + } + print!("{:?}", s.green()); + } + println!("]"); - Op::Define(_) => {} - - Op::Call(num_args) => { - let new_base = self.stack.len() - 1 - num_args; - match &self.stack[new_base] { - Value::Function(args, _ret, block) => { - if args.len() != num_args { - error!(self, - ErrorKind::InvalidProgram, - format!("Invalid number of arguments, got {} expected {}.", - num_args, args.len())); - } - if self.print_blocks { - block.debug_print(); - } - self.frames.push(Frame { - stack_offset: new_base, - block: Rc::clone(&block), - ip: 0, - }); - continue; - }, - _ => { - unreachable!() - } - } - } + println!("{:5} {:05} {:?}", + self.frame().block.line(self.frame().ip).red(), + self.frame().ip.blue(), + self.frame().block.ops[self.frame().ip]); + } - Op::Print => { - println!("PRINT: {:?}", self.stack.pop().unwrap()); - } + pub fn run(&mut self, block: Rc<Block>) -> Result<(), Error>{ + crate::typer::VM::new().print_ops(self.print_ops) + .print_blocks(self.print_blocks) + .typecheck(Type::Void, Rc::clone(&block))?; - Op::Return => { - let last = self.frames.pop().unwrap(); - if self.frames.is_empty() { - return Ok(()); - } else { - self.stack[last.stack_offset] = self.stack.pop().unwrap(); - } - } + self.frames.push(Frame { + stack_offset: 0, + block, + ip: 0 + }); + + if self.print_blocks { + self.frame().block.debug_print(); + } + + loop { + if self.print_ops { + self.print_stack() + } + + let op = self.frame().block.ops[self.frame().ip].clone(); + if matches!(self.eval_op(&op)?, OpResult::Done) { + return Ok(()); } - self.frame_mut().ip += 1; } } } |
