From ba4b36b7bad096e7b121ca75cb35f4bb8e4b1a83 Mon Sep 17 00:00:00 2001 From: Sofia Date: Tue, 17 Mar 2026 19:47:19 +0200 Subject: [PATCH] Make table contents be a Rc-RefCell --- examples/test.lua | 25 ------ src/main.rs | 8 +- src/vm.rs | 197 +++++++++++++++++++++++++++++++--------------- 3 files changed, 136 insertions(+), 94 deletions(-) diff --git a/examples/test.lua b/examples/test.lua index 3f16c49..5993979 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1,28 +1,3 @@ -global b = 5 - -function add(x) - return function (y) - x = x + 1 - b = b + 1 - return x + y, 1, 2, b - end -end - -function min(x, y) - local m = x - if y < x then - m = y - end - return m -end global sometable = {} sometable["hello"] = "there" - -print(max(11, 9)) -print(add(10)(15)) -print(add(10)(15)) -print(b) -print(min(11, 9)) -print(10 - 15) -print("hello there!") \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f64060f..58e372f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,13 +98,13 @@ fn main() { } dbg!(&vm.prototypes); - vm.environment.borrow_mut().globals.insert( + vm.environment.borrow_mut().set_global( vm::Constant::String("max".to_owned()), - vm::Value::RustFunction(Rc::new(RefCell::new(Max))), + vm::StackValue::Value(vm::Value::RustFunction(Rc::new(RefCell::new(Max)))), ); - vm.environment.borrow_mut().globals.insert( + vm.environment.borrow_mut().set_global( vm::Constant::String("print".to_owned()), - vm::Value::RustFunction(Rc::new(RefCell::new(Print))), + vm::StackValue::Value(vm::Value::RustFunction(Rc::new(RefCell::new(Print)))), ); let closure = vm.create_closure(chunk_id); diff --git a/src/vm.rs b/src/vm.rs index afc5a5d..bc8ce22 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -127,13 +127,46 @@ pub enum RuntimeError { GlobalNotFound(Option), #[error("Unable to index tables with {0:?}")] InvalidTableIndex(Value), + #[error("Value is not a table: {0:?}")] + NotTable(Value), #[error("{0}")] Custom(String), } #[derive(Debug, Clone, Default)] pub struct Environment { - pub globals: HashMap, + pub globals: HashMap>>, +} + +impl Environment { + pub fn get_global(&mut self, key: &Constant) -> Option { + let value = self.globals.get_mut(key)?; + Some(match &*value.borrow() { + _ => StackValue::Value(value.borrow().clone()), + }) + } + + pub fn set_global(&mut self, key: Constant, value: StackValue) { + if let Some(existing) = self.globals.get_mut(&key) { + match value { + StackValue::Value(value) => { + *existing.borrow_mut() = value; + } + StackValue::Ref(reference) => { + *existing = reference; + } + } + } else { + match value { + StackValue::Value(value) => { + self.globals.insert(key, Rc::new(RefCell::new(value))); + } + StackValue::Ref(reference) => { + self.globals.insert(key, reference); + } + } + } + } } #[derive(Clone)] @@ -143,7 +176,7 @@ pub enum Value { RustFunction(Rc>), Function(Closure), Nil, - Table(HashMap), + Table(Rc>>), } impl Value { @@ -289,7 +322,7 @@ impl Debug for Value { Value::Nil => write!(f, "Nil"), Value::Table(hash_map) => { let mut table = f.debug_struct("Table"); - for (key, value) in hash_map { + for (key, value) in hash_map.borrow().iter() { table.field(&format!("{:?}", key), value); } table.finish() @@ -355,6 +388,17 @@ impl Closure { top: 0, } } + + fn get_upvalue(&mut self, idx: u16) -> StackValue { + let value = self.upvalues.get(&idx); + if let Some(value) = value { + match &*value.borrow() { + _ => StackValue::Value(value.borrow().clone()), + } + } else { + StackValue::Value(Value::Nil) + } + } } pub struct ClosureRunner { @@ -367,12 +411,41 @@ pub struct ClosureRunner { pub top: u16, } +#[derive(Clone, Debug)] +pub enum StackValue { + Value(Value), + Ref(Rc>), +} + impl ClosureRunner { - pub fn set_stack(&mut self, idx: u16, value: Value) { - if let Some(stack_slot) = self.stack.get(&idx) { - *stack_slot.borrow_mut() = value; + pub fn set_stack(&mut self, idx: u16, value: StackValue) { + if let Some(stack_slot) = self.stack.get_mut(&idx) { + match value { + StackValue::Value(value) => { + *stack_slot.borrow_mut() = value; + } + StackValue::Ref(ref_cell) => *stack_slot = ref_cell, + } } else { - self.stack.insert(idx, Rc::new(RefCell::new(value))); + match value { + StackValue::Value(value) => { + self.stack.insert(idx, Rc::new(RefCell::new(value))); + } + StackValue::Ref(reference) => { + self.stack.insert(idx, reference); + } + } + } + } + + pub fn get_stack(&mut self, idx: u16) -> StackValue { + let value = self.stack.get(&idx); + if let Some(value) = value { + match &*value.borrow() { + _ => StackValue::Value(value.borrow().clone()), + } + } else { + StackValue::Value(Value::Nil) } } @@ -452,27 +525,21 @@ impl ClosureRunner { .get(&self.closure.prototype) .unwrap() .clone(); - let constants = &self.closure.vm.constants; + let constants = self.closure.vm.constants.clone(); if let Some(instr) = instructions.get(self.program_counter) { match instr { Instruction::Move(a, b) => { - self.set_stack( - *a, - self.stack - .get(b) - .map(|v| v.borrow().clone()) - .unwrap_or(Value::Nil) - .clone(), - ); + let b = self.get_stack(*b); + self.set_stack(*a, b); } Instruction::LoadK(reg, constant) => { self.set_stack( *reg, - match constants.get(*constant as usize).unwrap() { + StackValue::Value(match constants.get(*constant as usize).unwrap() { Constant::String(value) => Value::String(value.clone()), Constant::Number(value) => Value::Number(*value), - }, + }), ); } Instruction::LoadNil(from_reg, to_reg) => { @@ -481,25 +548,23 @@ impl ClosureRunner { } } Instruction::SetGlobal(reg, global) => { - self.closure.environment.borrow_mut().globals.insert( - constants.get(*global as usize).unwrap().clone(), - self.stack - .get(reg) - .map(|v| v.borrow().clone()) - .unwrap_or(Value::Nil) - .clone(), - ); + let value = self.get_stack(*reg); + dbg!(&value); + self.closure + .environment + .borrow_mut() + .set_global(constants.get(*global as usize).unwrap().clone(), value); + + dbg!(&self.closure.environment); } Instruction::GetGlobal(reg, global) => { let glob = self .closure .environment - .borrow() - .globals - .get(constants.get(*global as usize).unwrap()) - .cloned(); + .borrow_mut() + .get_global(constants.get(*global as usize).unwrap()); if let Some(global) = glob { - self.set_stack(*reg, global.clone()); + self.set_stack(*reg, global); } else { return Err(RuntimeError::GlobalNotFound( constants.get(*global as usize).cloned(), @@ -507,14 +572,8 @@ impl ClosureRunner { } } Instruction::GetUpVal(reg, upvalreg) => { - self.set_stack( - *reg, - self.closure - .upvalues - .get(upvalreg) - .map(|v| v.borrow().clone()) - .unwrap(), - ); + let upvalue = self.closure.get_upvalue(*upvalreg); + self.set_stack(*reg, upvalue); } Instruction::SetUpVal(upvalreg, reg) => { *self.closure.upvalues.get(upvalreg).unwrap().borrow_mut() = self @@ -542,21 +601,24 @@ impl ClosureRunner { .unwrap_or(Value::Nil); match value { Value::Nil => { - table.remove(&index_value); + table.borrow_mut().remove(&index_value); } _ => { - table.insert(index_value, value); + table.borrow_mut().insert(index_value, value); } } } else { - todo!() + return Err(RuntimeError::NotTable(table.clone())); } } None => todo!(), } } Instruction::NewTable(reg) => { - self.set_stack(*reg, Value::Table(HashMap::new())); + self.set_stack( + *reg, + StackValue::Value(Value::Table(Rc::new(RefCell::new(HashMap::new())))), + ); } Instruction::Jmp(b) => { self.program_counter = (self.program_counter as i32 + *b) as usize @@ -572,13 +634,8 @@ impl ClosureRunner { _ => false, }; if is_true { - self.set_stack( - *a, - self.stack - .get(b) - .map(|v| v.borrow().clone()) - .unwrap_or(Value::Nil), - ); + let b = self.get_stack(*b); + self.set_stack(*a, b); } else { self.program_counter += 1; } @@ -620,12 +677,20 @@ impl ClosureRunner { for i in 0..=(*ret_len - 2) { self.set_stack( *func_reg + i, - ret_values.get(i as usize).cloned().unwrap_or(Value::Nil), + StackValue::Value( + ret_values + .get(i as usize) + .cloned() + .unwrap_or(Value::Nil), + ), ); } } else { for (i, value) in ret_values.iter().enumerate() { - self.set_stack(*func_reg + i as u16 + 1, value.clone()); + self.set_stack( + *func_reg + i as u16 + 1, + StackValue::Value(value.clone()), + ); } self.top = *func_reg + ret_values.len() as u16; } @@ -646,12 +711,12 @@ impl ClosureRunner { Instruction::Closure(reg, protok) => { self.set_stack( *reg, - Value::Function(Closure { + StackValue::Value(Value::Function(Closure { vm: self.closure.vm.clone(), prototype: *protok, environment: self.closure.environment.clone(), upvalues: self.close_upvalues(), - }), + })), ); } Instruction::Return(reg_start, reg_end) => { @@ -687,7 +752,7 @@ impl ClosureRunner { .get(rhs) .map(|v| v.borrow().clone()) .unwrap_or(Value::Nil); - self.set_stack(*res, lhs.add(&rhs)?); + self.set_stack(*res, StackValue::Value(lhs.add(&rhs)?)); } Instruction::Equal(res, lhs, rhs) => { let lhs = self @@ -700,7 +765,7 @@ impl ClosureRunner { .get(rhs) .map(|v| v.borrow().clone()) .unwrap_or(Value::Nil); - self.set_stack(*res, lhs.eq(&rhs)?); + self.set_stack(*res, StackValue::Value(lhs.eq(&rhs)?)); } Instruction::LessThan(res, lhs, rhs) => { let lhs = self @@ -713,7 +778,7 @@ impl ClosureRunner { .get(rhs) .map(|v| v.borrow().clone()) .unwrap_or(Value::Nil); - self.set_stack(*res, lhs.lt(&rhs)?); + self.set_stack(*res, StackValue::Value(lhs.lt(&rhs)?)); } Instruction::LessThanOrEqual(res, lhs, rhs) => { let lhs = self @@ -726,16 +791,18 @@ impl ClosureRunner { .get(rhs) .map(|v| v.borrow().clone()) .unwrap_or(Value::Nil); - self.set_stack(*res, lhs.lte(&rhs)?); + self.set_stack(*res, StackValue::Value(lhs.lte(&rhs)?)); } Instruction::Unm(res, reg) => { self.set_stack( *res, - self.stack - .get(reg) - .map(|v| v.borrow().clone()) - .unwrap_or(Value::Nil) - .unm()?, + StackValue::Value( + self.stack + .get(reg) + .map(|v| v.borrow().clone()) + .unwrap_or(Value::Nil) + .unm()?, + ), ); } Instruction::Or(res, lhs, rhs) => { @@ -749,7 +816,7 @@ impl ClosureRunner { .get(rhs) .map(|v| v.borrow().clone()) .unwrap_or(Value::Nil); - self.set_stack(*res, lhs.or(&rhs)?); + self.set_stack(*res, StackValue::Value(lhs.or(&rhs)?)); } Instruction::And(res, lhs, rhs) => { let lhs = self @@ -762,7 +829,7 @@ impl ClosureRunner { .get(rhs) .map(|v| v.borrow().clone()) .unwrap_or(Value::Nil); - self.set_stack(*res, lhs.and(&rhs)?); + self.set_stack(*res, StackValue::Value(lhs.and(&rhs)?)); } };