Make table contents be a Rc-RefCell

This commit is contained in:
Sofia 2026-03-17 19:47:19 +02:00
parent 7e5aaf56f1
commit ba4b36b7ba
3 changed files with 136 additions and 94 deletions

View File

@ -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 = {} global sometable = {}
sometable["hello"] = "there" 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!")

View File

@ -98,13 +98,13 @@ fn main() {
} }
dbg!(&vm.prototypes); dbg!(&vm.prototypes);
vm.environment.borrow_mut().globals.insert( vm.environment.borrow_mut().set_global(
vm::Constant::String("max".to_owned()), 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::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); let closure = vm.create_closure(chunk_id);

197
src/vm.rs
View File

@ -127,13 +127,46 @@ pub enum RuntimeError {
GlobalNotFound(Option<Constant>), GlobalNotFound(Option<Constant>),
#[error("Unable to index tables with {0:?}")] #[error("Unable to index tables with {0:?}")]
InvalidTableIndex(Value), InvalidTableIndex(Value),
#[error("Value is not a table: {0:?}")]
NotTable(Value),
#[error("{0}")] #[error("{0}")]
Custom(String), Custom(String),
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Environment { pub struct Environment {
pub globals: HashMap<Constant, Value>, pub globals: HashMap<Constant, Rc<RefCell<Value>>>,
}
impl Environment {
pub fn get_global(&mut self, key: &Constant) -> Option<StackValue> {
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)] #[derive(Clone)]
@ -143,7 +176,7 @@ pub enum Value {
RustFunction(Rc<RefCell<dyn RustFunction>>), RustFunction(Rc<RefCell<dyn RustFunction>>),
Function(Closure), Function(Closure),
Nil, Nil,
Table(HashMap<IndexableValue, Value>), Table(Rc<RefCell<HashMap<IndexableValue, Value>>>),
} }
impl Value { impl Value {
@ -289,7 +322,7 @@ impl Debug for Value {
Value::Nil => write!(f, "Nil"), Value::Nil => write!(f, "Nil"),
Value::Table(hash_map) => { Value::Table(hash_map) => {
let mut table = f.debug_struct("Table"); 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.field(&format!("{:?}", key), value);
} }
table.finish() table.finish()
@ -355,6 +388,17 @@ impl Closure {
top: 0, 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 { pub struct ClosureRunner {
@ -367,12 +411,41 @@ pub struct ClosureRunner {
pub top: u16, pub top: u16,
} }
#[derive(Clone, Debug)]
pub enum StackValue {
Value(Value),
Ref(Rc<RefCell<Value>>),
}
impl ClosureRunner { impl ClosureRunner {
pub fn set_stack(&mut self, idx: u16, value: Value) { pub fn set_stack(&mut self, idx: u16, value: StackValue) {
if let Some(stack_slot) = self.stack.get(&idx) { if let Some(stack_slot) = self.stack.get_mut(&idx) {
*stack_slot.borrow_mut() = value; match value {
StackValue::Value(value) => {
*stack_slot.borrow_mut() = value;
}
StackValue::Ref(ref_cell) => *stack_slot = ref_cell,
}
} else { } 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) .get(&self.closure.prototype)
.unwrap() .unwrap()
.clone(); .clone();
let constants = &self.closure.vm.constants; let constants = self.closure.vm.constants.clone();
if let Some(instr) = instructions.get(self.program_counter) { if let Some(instr) = instructions.get(self.program_counter) {
match instr { match instr {
Instruction::Move(a, b) => { Instruction::Move(a, b) => {
self.set_stack( let b = self.get_stack(*b);
*a, self.set_stack(*a, b);
self.stack
.get(b)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
.clone(),
);
} }
Instruction::LoadK(reg, constant) => { Instruction::LoadK(reg, constant) => {
self.set_stack( self.set_stack(
*reg, *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::String(value) => Value::String(value.clone()),
Constant::Number(value) => Value::Number(*value), Constant::Number(value) => Value::Number(*value),
}, }),
); );
} }
Instruction::LoadNil(from_reg, to_reg) => { Instruction::LoadNil(from_reg, to_reg) => {
@ -481,25 +548,23 @@ impl ClosureRunner {
} }
} }
Instruction::SetGlobal(reg, global) => { Instruction::SetGlobal(reg, global) => {
self.closure.environment.borrow_mut().globals.insert( let value = self.get_stack(*reg);
constants.get(*global as usize).unwrap().clone(), dbg!(&value);
self.stack self.closure
.get(reg) .environment
.map(|v| v.borrow().clone()) .borrow_mut()
.unwrap_or(Value::Nil) .set_global(constants.get(*global as usize).unwrap().clone(), value);
.clone(),
); dbg!(&self.closure.environment);
} }
Instruction::GetGlobal(reg, global) => { Instruction::GetGlobal(reg, global) => {
let glob = self let glob = self
.closure .closure
.environment .environment
.borrow() .borrow_mut()
.globals .get_global(constants.get(*global as usize).unwrap());
.get(constants.get(*global as usize).unwrap())
.cloned();
if let Some(global) = glob { if let Some(global) = glob {
self.set_stack(*reg, global.clone()); self.set_stack(*reg, global);
} else { } else {
return Err(RuntimeError::GlobalNotFound( return Err(RuntimeError::GlobalNotFound(
constants.get(*global as usize).cloned(), constants.get(*global as usize).cloned(),
@ -507,14 +572,8 @@ impl ClosureRunner {
} }
} }
Instruction::GetUpVal(reg, upvalreg) => { Instruction::GetUpVal(reg, upvalreg) => {
self.set_stack( let upvalue = self.closure.get_upvalue(*upvalreg);
*reg, self.set_stack(*reg, upvalue);
self.closure
.upvalues
.get(upvalreg)
.map(|v| v.borrow().clone())
.unwrap(),
);
} }
Instruction::SetUpVal(upvalreg, reg) => { Instruction::SetUpVal(upvalreg, reg) => {
*self.closure.upvalues.get(upvalreg).unwrap().borrow_mut() = self *self.closure.upvalues.get(upvalreg).unwrap().borrow_mut() = self
@ -542,21 +601,24 @@ impl ClosureRunner {
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
match value { match value {
Value::Nil => { 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 { } else {
todo!() return Err(RuntimeError::NotTable(table.clone()));
} }
} }
None => todo!(), None => todo!(),
} }
} }
Instruction::NewTable(reg) => { 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) => { Instruction::Jmp(b) => {
self.program_counter = (self.program_counter as i32 + *b) as usize self.program_counter = (self.program_counter as i32 + *b) as usize
@ -572,13 +634,8 @@ impl ClosureRunner {
_ => false, _ => false,
}; };
if is_true { if is_true {
self.set_stack( let b = self.get_stack(*b);
*a, self.set_stack(*a, b);
self.stack
.get(b)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil),
);
} else { } else {
self.program_counter += 1; self.program_counter += 1;
} }
@ -620,12 +677,20 @@ impl ClosureRunner {
for i in 0..=(*ret_len - 2) { for i in 0..=(*ret_len - 2) {
self.set_stack( self.set_stack(
*func_reg + i, *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 { } else {
for (i, value) in ret_values.iter().enumerate() { 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; self.top = *func_reg + ret_values.len() as u16;
} }
@ -646,12 +711,12 @@ impl ClosureRunner {
Instruction::Closure(reg, protok) => { Instruction::Closure(reg, protok) => {
self.set_stack( self.set_stack(
*reg, *reg,
Value::Function(Closure { StackValue::Value(Value::Function(Closure {
vm: self.closure.vm.clone(), vm: self.closure.vm.clone(),
prototype: *protok, prototype: *protok,
environment: self.closure.environment.clone(), environment: self.closure.environment.clone(),
upvalues: self.close_upvalues(), upvalues: self.close_upvalues(),
}), })),
); );
} }
Instruction::Return(reg_start, reg_end) => { Instruction::Return(reg_start, reg_end) => {
@ -687,7 +752,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .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) => { Instruction::Equal(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -700,7 +765,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .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) => { Instruction::LessThan(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -713,7 +778,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .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) => { Instruction::LessThanOrEqual(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -726,16 +791,18 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.lte(&rhs)?); self.set_stack(*res, StackValue::Value(lhs.lte(&rhs)?));
} }
Instruction::Unm(res, reg) => { Instruction::Unm(res, reg) => {
self.set_stack( self.set_stack(
*res, *res,
self.stack StackValue::Value(
.get(reg) self.stack
.map(|v| v.borrow().clone()) .get(reg)
.unwrap_or(Value::Nil) .map(|v| v.borrow().clone())
.unm()?, .unwrap_or(Value::Nil)
.unm()?,
),
); );
} }
Instruction::Or(res, lhs, rhs) => { Instruction::Or(res, lhs, rhs) => {
@ -749,7 +816,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .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) => { Instruction::And(res, lhs, rhs) => {
let lhs = self let lhs = self
@ -762,7 +829,7 @@ impl ClosureRunner {
.get(rhs) .get(rhs)
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
self.set_stack(*res, lhs.and(&rhs)?); self.set_stack(*res, StackValue::Value(lhs.and(&rhs)?));
} }
}; };