Make table contents be a Rc-RefCell
This commit is contained in:
parent
7e5aaf56f1
commit
ba4b36b7ba
@ -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!")
|
|
||||||
@ -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
197
src/vm.rs
@ -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)?));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user