aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vm.rs360
1 files changed, 188 insertions, 172 deletions
diff --git a/src/vm.rs b/src/vm.rs
index 77a1374..e78b914 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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;
}
}
}