diff --git a/src/compile.rs b/src/compile.rs index db50398..f3be14a 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -209,7 +209,7 @@ impl Expression { Expression::Literal(literal) => { let mut instructions = Vec::new(); let reg = scope.register_counter.next(); - instructions.push(Instruction::GetGlobal( + instructions.push(Instruction::LoadK( reg, state.get_constant(&match literal { Literal::Number(value) => Constant::Number(value.to_bits()), diff --git a/src/main.rs b/src/main.rs index 0bd5a59..13d9e57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,12 @@ -use std::path::PathBuf; +use std::{cell::RefCell, path::PathBuf, rc::Rc}; use crate::{ - ast::{Block, Function}, + ast::{Block, Function, LuaNumber}, token_stream::{ TokenStream, lexer::{Token, tokenize}, }, + vm::{RustFunction, VirtualMachine}, }; mod ast; @@ -15,6 +16,22 @@ mod vm; static TEST: &str = include_str!("../examples/test.lua"); +#[derive(Debug)] +pub struct Max; +impl RustFunction for Max { + fn execute(&self, parameters: Vec) -> Vec { + let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil); + let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil); + match lhs.lt(&rhs) { + vm::Value::Number(value) => { + let res = LuaNumber::from_bits(value); + vec![if res > 0. { rhs } else { lhs }] + } + _ => vec![vm::Value::Nil], + } + } +} + fn main() { let file_path = PathBuf::from("../examples/test.lua"); let tokens = tokenize(TEST).unwrap(); @@ -33,6 +50,30 @@ fn main() { .collect::>(); dbg!(&constants); - let instructions = chunk.compile(&mut compile::State { constants }, &mut Default::default()); + let instructions = chunk.compile( + &mut compile::State { + constants: constants.clone(), + }, + &mut Default::default(), + ); dbg!(&instructions); + + let mut vm = VirtualMachine { + environment: Default::default(), + constants, + prototypes: Default::default(), + }; + vm.prototypes.insert(0, instructions); + vm.environment.borrow_mut().globals.insert( + vm::Constant::String("max".to_owned()), + vm::Value::RustFunction(Rc::new(RefCell::new(Max))), + ); + + let closure = vm.create_closure(0); + + let mut run = closure.run(); + + while run.next() {} + + dbg!(vm.environment.borrow()); } diff --git a/src/vm.rs b/src/vm.rs index 4439ab5..02088cf 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -49,22 +49,170 @@ impl Debug for Instruction { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Environment { pub globals: HashMap, } -#[derive(Debug, Clone)] +#[derive(Clone)] pub enum Value { Number(VMNumber), RustFunction(Rc>), + Function(Closure), + Nil, +} + +impl Value { + pub fn add(&self, other: &Value) -> Value { + match (self, other) { + (Value::Number(lhs), Value::Number(rhs)) => { + let res = LuaNumber::from_bits(*lhs) + LuaNumber::from_bits(*rhs); + Value::Number(res.to_bits()) + } + _ => Value::Nil, + } + } + + pub fn lt(&self, other: &Value) -> Value { + match (self, other) { + (Value::Number(lhs), Value::Number(rhs)) => { + let res = LuaNumber::from_bits(*lhs) < LuaNumber::from_bits(*rhs); + Value::Number((res as u64 as f64).to_bits()) + } + _ => Value::Nil, + } + } +} + +impl Debug for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Number(arg0) => f + .debug_tuple("Number") + .field(&LuaNumber::from_bits(*arg0)) + .finish(), + Self::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(), + Self::Function(arg0) => f.debug_tuple("Function").field(arg0).finish(), + Self::Nil => write!(f, "Nil"), + } + } } pub trait RustFunction: Debug { fn execute(&self, parameters: Vec) -> Vec; } -pub struct ClosureRunner { +#[derive(Debug, Clone)] +pub struct VirtualMachine { pub environment: Rc>, pub constants: Vec, + pub prototypes: HashMap>, +} + +impl VirtualMachine { + pub fn create_closure(&self, prototype: u32) -> Closure { + Closure { + vm: self.clone(), + prototype, + environment: self.environment.clone(), + upvalues: HashMap::new(), + } + } +} + +#[derive(Debug, Clone)] +pub struct Closure { + pub vm: VirtualMachine, + pub prototype: u32, + pub environment: Rc>, + pub upvalues: HashMap>>, +} + +impl Closure { + pub fn run(&self) -> ClosureRunner { + ClosureRunner { + closure: self.clone(), + program_counter: 0, + stack: HashMap::new(), + } + } +} + +pub struct ClosureRunner { + pub closure: Closure, + pub program_counter: usize, + pub stack: HashMap, +} + +impl ClosureRunner { + pub fn next(&mut self) -> bool { + let instructions = self + .closure + .vm + .prototypes + .get(&self.closure.prototype) + .unwrap(); + let constants = &self.closure.vm.constants; + + if let Some(instr) = instructions.get(self.program_counter) { + match instr { + Instruction::Move(a, b) => { + self.stack.insert(*a, self.stack.get(b).unwrap().clone()); + } + Instruction::LoadK(reg, constant) => { + self.stack.insert( + *reg, + match constants.get(*constant as usize).unwrap() { + Constant::String(_) => todo!(), + Constant::Number(value) => Value::Number(*value), + }, + ); + } + Instruction::SetGlobal(reg, global) => { + self.closure.environment.borrow_mut().globals.insert( + constants.get(*global as usize).unwrap().clone(), + self.stack.get(reg).unwrap().clone(), + ); + } + Instruction::GetGlobal(reg, global) => { + if let Some(global) = self + .closure + .environment + .borrow() + .globals + .get(constants.get(*global as usize).unwrap()) + { + self.stack.insert(*reg, global.clone()); + } else { + todo!("Global not found: {:?}", constants.get(*global as usize)) + } + } + Instruction::Call(func_reg, param_len, ret_len) => { + match self.stack.get(func_reg).unwrap_or(&Value::Nil) { + Value::RustFunction(func) => { + let mut params = Vec::new(); + for i in 0..*param_len { + params.push(self.stack.get(&(func_reg + i + 1)).unwrap().clone()); + } + let ret_values = func.borrow_mut().execute(params); + for i in 0..=(*ret_len - 2) { + self.stack.insert( + *func_reg + i, + ret_values.get(i as usize).cloned().unwrap_or(Value::Nil), + ); + } + } + Value::Function(_) => todo!(), + _ => panic!(), + } + } + }; + + self.program_counter += 1; + + true + } else { + false + } + } }