diff --git a/src/bytecode.rs b/src/bytecode.rs index 74e6005..e1ad7eb 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -2,50 +2,40 @@ use std::collections::HashMap; use crate::ast::{Ast, Expr, Stmt, BinOpType}; -#[repr(u32)] -#[derive(Debug, Clone, Copy)] -pub enum OP { - Push, - Pop, - Load, - Store, +pub mod op { + type OpSize = u32; - Add, - Subtract, - Multiply, - Divide, - Modulo, - BOr, - BAnd, - BXor, - Shl, - Shr, - - Eq, - Neq, - - Gt, - Ge, - Lt, - Le, - - Jump, - - JumpTrue, - - JumpFalse, - - Value(u32), - - Print, - - DbgPrint, + pub const PUSH: OpSize = 0; + pub const POP: OpSize = 1; + pub const LOAD: OpSize = 2; + pub const STORE: OpSize = 3; + pub const ADD: OpSize = 4; + pub const SUB: OpSize = 5; + pub const MUL: OpSize = 6; + pub const DIV: OpSize = 7; + pub const MOD: OpSize = 8; + pub const BOR: OpSize = 9; + pub const BAND: OpSize = 10; + pub const BXOR: OpSize = 11; + pub const SHL: OpSize = 12; + pub const SHR: OpSize = 13; + pub const EQ: OpSize = 14; + pub const NEQ: OpSize = 15; + pub const GT: OpSize = 16; + pub const GE: OpSize = 17; + pub const LT: OpSize = 18; + pub const LE: OpSize = 19; + pub const JUMP: OpSize = 20; + pub const JUMP_TRUE: OpSize = 21; + pub const JUMP_FALSE: OpSize = 22; + pub const PRINT: OpSize = 23; + pub const DBG_PRINT: OpSize = 24; } #[derive(Debug, Default)] pub struct Compiler { - ops: Vec, - global_vars: HashMap, + ops: Vec, + global_vars: HashMap, } impl Compiler { @@ -58,26 +48,30 @@ impl Compiler { match stmt { Stmt::Expr(expr) => { self.compile_expr(expr); - self.ops.push(OP::Pop); + self.ops.push(op::POP); } Stmt::Let(name, rhs) => { - let id = self.global_vars.len() as u64; + let id = self.global_vars.len() as u16; self.global_vars.insert(name.clone(), id); self.compile_expr(rhs); self.gen_store(id); } Stmt::While(cond, body) => { - let idx_start = self.ops.len(); self.compile_expr(cond); - self.ops.push(OP::JumpFalse); + self.ops.push(op::JUMP_FALSE); let idx_jmp = self.ops.len(); self.gen_i64(0); + + let idx_start = self.ops.len(); self.compile(body); - self.ops.push(OP::Jump); + // check condition before loop jump + self.compile_expr(cond); + + self.ops.push(op::JUMP_TRUE); self.gen_i64(idx_start as i64); self.overwrite_i64(idx_jmp, self.ops.len() as i64); @@ -86,13 +80,13 @@ impl Compiler { Stmt::If(cond, if_block, else_block) => { self.compile_expr(cond); - self.ops.push(OP::JumpFalse); + self.ops.push(op::JUMP_FALSE); let idx_if = self.ops.len(); self.gen_i64(0); self.compile(if_block); - self.ops.push(OP::Jump); + self.ops.push(op::JUMP); let idx_else = self.ops.len(); self.gen_i64(0); @@ -105,24 +99,24 @@ impl Compiler { }, Stmt::DbgPrint(expr) => { self.compile_expr(expr); - self.ops.push(OP::DbgPrint); + self.ops.push(op::DBG_PRINT); } Stmt::Print(expr) => { self.compile_expr(expr); - self.ops.push(OP::Print); + self.ops.push(op::PRINT); } } } } - pub fn into_ops(self) -> Vec { + pub fn into_ops(self) -> Vec { self.ops } pub fn compile_expr(&mut self, expr: &Expr) { match expr { Expr::I64(val) => { - self.ops.push(OP::Push); + self.ops.push(op::PUSH); self.gen_i64(*val) } Expr::Ident(name) => { @@ -155,48 +149,48 @@ impl Compiler { self.compile_expr(rhs); match bo { - BinOpType::Add => self.ops.push(OP::Add), - BinOpType::Sub => self.ops.push(OP::Subtract), - BinOpType::Mul => self.ops.push(OP::Multiply), - BinOpType::Div => self.ops.push(OP::Divide), - BinOpType::Mod => self.ops.push(OP::Modulo), - BinOpType::BOr => self.ops.push(OP::BOr), - BinOpType::BAnd => self.ops.push(OP::BAnd), - BinOpType::BXor => self.ops.push(OP::BXor), - BinOpType::Shl => self.ops.push(OP::Shl), - BinOpType::Shr => self.ops.push(OP::Shr), - BinOpType::Equ => self.ops.push(OP::Eq), - BinOpType::Neq => self.ops.push(OP::Neq), - BinOpType::Gt => self.ops.push(OP::Gt), - BinOpType::Ge => self.ops.push(OP::Ge), - BinOpType::Lt => self.ops.push(OP::Lt), - BinOpType::Le => self.ops.push(OP::Le), + BinOpType::Add => self.ops.push(op::ADD), + BinOpType::Sub => self.ops.push(op::SUB), + BinOpType::Mul => self.ops.push(op::MUL), + BinOpType::Div => self.ops.push(op::DIV), + BinOpType::Mod => self.ops.push(op::MOD), + BinOpType::BOr => self.ops.push(op::BOR), + BinOpType::BAnd => self.ops.push(op::BAND), + BinOpType::BXor => self.ops.push(op::BXOR), + BinOpType::Shl => self.ops.push(op::SHL), + BinOpType::Shr => self.ops.push(op::SHR), + BinOpType::Equ => self.ops.push(op::EQ), + BinOpType::Neq => self.ops.push(op::NEQ), + BinOpType::Gt => self.ops.push(op::GT), + BinOpType::Ge => self.ops.push(op::GE), + BinOpType::Lt => self.ops.push(op::LT), + BinOpType::Le => self.ops.push(op::LE), BinOpType::Assign => unreachable!(), } } fn gen_i64(&mut self, val: i64) { - self.ops.push(OP::Value((val & u32::MAX as i64) as u32)); - self.ops.push(OP::Value((val >> 32) as u32)); + self.ops.push((val & u32::MAX as i64) as u32); + self.ops.push((val >> 32) as u32); } fn overwrite_i64(&mut self, idx: usize, val: i64) { - self.ops[idx] = OP::Value((val & u32::MAX as i64) as u32); - self.ops[idx+1] = OP::Value((val >> 32) as u32); + self.ops[idx] = (val & u32::MAX as i64) as u32; + self.ops[idx+1] = (val >> 32) as u32; } - fn gen_load(&mut self, addr: u64) { - self.ops.push(OP::Load); - self.gen_i64(addr as i64) + fn gen_load(&mut self, addr: u16) { + self.ops.push(op::LOAD | (addr << 8) as u32); + // self.gen_i64(addr as i64) } - fn gen_store(&mut self, addr: u64) { - self.ops.push(OP::Store); - self.gen_i64(addr as i64) + fn gen_store(&mut self, addr: u16) { + self.ops.push(op::STORE | (addr << 8) as u32); + // self.gen_i64(addr as i64) } } -pub fn compile(ast: &Ast) -> Vec { +pub fn compile(ast: &Ast) -> Vec { let mut compiler = Compiler::new(); compiler.compile(ast); compiler.into_ops() diff --git a/src/vm.rs b/src/vm.rs index 5323792..20f4d3f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,8 +1,8 @@ -use crate::{bytecode::OP, interpreter::Value}; +use crate::{bytecode::op::*, interpreter::Value}; #[derive(Debug, Default)] pub struct Vm { - prog: Vec, + prog: Vec, ip: usize, stack: Vec, @@ -10,8 +10,21 @@ pub struct Vm { heap: Vec, } +macro_rules! binop_stack { + ($self:ident, $op:tt) => { + { + let rhs = $self.stack.pop().unwrap(); + let lhs = $self.stack.last_mut().unwrap(); + match (lhs, rhs) { + (Value::I64(lhs), Value::I64(rhs)) => *lhs = *lhs $op rhs, + _ => panic!("Invalid data for add"), + } + } + }; +} + impl Vm { - pub fn new(prog: Vec) -> Self { + pub fn new(prog: Vec) -> Self { Self { prog, ..Default::default() @@ -22,16 +35,17 @@ impl Vm { while let Some(op) = self.prog.get(self.ip).copied() { self.ip += 1; - match op { - OP::Push => { + match op & 0xff { + PUSH => { let val = self.read_i64(); self.stack.push(Value::I64(val)); } - OP::Pop => { + POP => { self.stack.pop(); } - OP::Load => { - let addr = self.read_i64() as usize; + LOAD => { + // let addr = self.read_i64() as usize; + let addr = (op >> 8) as usize; if let Some(val) = self.heap.get(addr) { self.stack.push(val.clone()); @@ -39,26 +53,28 @@ impl Vm { panic!("Trying to load from uninitialized heap"); } } - OP::Store => { + STORE => { let val = self .stack .pop() .expect("Trying to pop value from stack for storing"); - let addr = self.read_i64() as usize; + // let addr = self.read_i64() as usize; + let addr = (op >> 8) as usize; + if self.heap.len() == addr { self.heap.push(val); } else { self.heap[addr] = val; } } - OP::Print => { + PRINT => { let val = self .stack .pop() .expect("Trying to pop value from stack for printing"); print!("{}", val); } - OP::DbgPrint => { + DBG_PRINT => { let val = self .stack .pop() @@ -66,94 +82,96 @@ impl Vm { print!("{:?}", val); } - OP::Add => { - let vals = self.pop2_i64(); - self.stack.push(Value::I64(vals.0 + vals.1)) + ADD => { + binop_stack!(self, +); + // self.stack.push(Value::I64(vals.0 + vals.1)) } - OP::Subtract => { - let vals = self.pop2_i64(); - self.stack.push(Value::I64(vals.0 - vals.1)) + SUB => { + binop_stack!(self, -); + // let vals = self.pop2_i64(); + // self.stack.push(Value::I64(vals.0 - vals.1)) } - OP::Multiply => { - let vals = self.pop2_i64(); - self.stack.push(Value::I64(vals.0 * vals.1)) + MUL => { + binop_stack!(self, *); + // let vals = self.pop2_i64(); + // self.stack.push(Value::I64(vals.0 * vals.1)) } - OP::Divide => { - let vals = self.pop2_i64(); - self.stack.push(Value::I64(vals.0 / vals.1)) + DIV => { + binop_stack!(self, /); + // let vals = self.pop2_i64(); + // self.stack.push(Value::I64(vals.0 / vals.1)) } - OP::Modulo => { - let vals = self.pop2_i64(); - self.stack.push(Value::I64(vals.0 % vals.1)) + MOD => { + binop_stack!(self, %); + // let vals = self.pop2_i64(); + // self.stack.push(Value::I64(vals.0 % vals.1)) } - OP::Eq => { + EQ => { let vals = self.pop2_i64(); self.stack .push(Value::I64(if vals.0 == vals.1 { 1 } else { 0 })) } - OP::Neq => { + NEQ => { let vals = self.pop2_i64(); self.stack .push(Value::I64(if vals.0 != vals.1 { 1 } else { 0 })) } - OP::Gt => { + GT => { let vals = self.pop2_i64(); self.stack .push(Value::I64(if vals.0 > vals.1 { 1 } else { 0 })) } - OP::Ge => { + GE => { let vals = self.pop2_i64(); self.stack .push(Value::I64(if vals.0 >= vals.1 { 1 } else { 0 })) } - OP::Lt => { + LT => { let vals = self.pop2_i64(); self.stack .push(Value::I64(if vals.0 < vals.1 { 1 } else { 0 })) } - OP::Le => { + LE => { let vals = self.pop2_i64(); self.stack .push(Value::I64(if vals.0 <= vals.1 { 1 } else { 0 })) } - OP::BOr => { + BOR => { let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 | vals.1)) } - OP::BAnd => { + BAND => { let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 & vals.1)) } - OP::BXor => { + BXOR => { let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 ^ vals.1)) } - OP::Shl => { + SHL => { let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 << vals.1)) } - OP::Shr => { + SHR => { let vals = self.pop2_i64(); self.stack.push(Value::I64(vals.0 >> vals.1)) } - OP::Value(_) => { - panic!("This is not an instruction, but data. This should never be evaluated") - } - OP::Jump => { + JUMP => { self.ip = self.read_i64() as usize; } - OP::JumpTrue => { + JUMP_TRUE => { let jmp_target = self.read_i64() as usize; if !matches!(self.stack.pop(), Some(Value::I64(0))) { self.ip = jmp_target; } } - OP::JumpFalse => { + JUMP_FALSE => { let jmp_target = self.read_i64() as usize; if matches!(self.stack.pop(), Some(Value::I64(0))) { self.ip = jmp_target; } } + _ => panic!("Invalid opcode") } } } @@ -168,7 +186,7 @@ impl Vm { } fn read_i64(&mut self) -> i64 { - let mut val = if let Some(OP::Value(val)) = self.prog.get(self.ip).copied() { + let mut val = if let Some(val) = self.prog.get(self.ip).copied() { val } else { panic!("Expected Value as next OP") @@ -176,7 +194,7 @@ impl Vm { self.ip += 1; - val |= (if let Some(OP::Value(val)) = self.prog.get(self.ip).copied() { + val |= (if let Some(val) = self.prog.get(self.ip).copied() { val } else { panic!("Expected Value as next OP")