Implement upvalues

This commit is contained in:
Sofia 2026-03-14 23:33:40 +02:00
parent 5c96834e5c
commit 9d471400d9
3 changed files with 50 additions and 3 deletions

View File

@ -1,6 +1,8 @@
function add(x) function add(x)
return x return function test()
return x
end
end end
global d = add(5) global d = add(5)
global c = print(d) global c = print(d())

View File

@ -25,6 +25,7 @@ impl State {
pub struct Scope { pub struct Scope {
pub locals: HashMap<String, u16>, pub locals: HashMap<String, u16>,
pub register_counter: LocalCounter, pub register_counter: LocalCounter,
pub upvalues: HashMap<String, u16>,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -165,6 +166,9 @@ impl Expression {
Expression::ValueRef(name) => { Expression::ValueRef(name) => {
if let Some(local) = scope.locals.get(name) { if let Some(local) = scope.locals.get(name) {
(Vec::new(), vec![*local]) (Vec::new(), vec![*local])
} else if let Some(upvalue) = scope.upvalues.get(name) {
let local = scope.register_counter.next();
(vec![Instruction::GetUpVal(local, *upvalue)], vec![local])
} else { } else {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
let reg = scope.register_counter.next(); let reg = scope.register_counter.next();
@ -184,6 +188,13 @@ impl Expression {
.insert(param.kind.clone(), inner_scope.register_counter.next()); .insert(param.kind.clone(), inner_scope.register_counter.next());
} }
let highest_upvalue = scope.upvalues.iter().map(|(_, v)| *v).max().unwrap_or(0);
inner_scope.upvalues = scope.upvalues.clone();
for (name, reg) in &scope.locals {
inner_scope.upvalues.insert(name.clone(), *reg + 1);
}
let instructions = block.compile(state, &mut inner_scope); let instructions = block.compile(state, &mut inner_scope);
state.prototypes.push(instructions); state.prototypes.push(instructions);

View File

@ -32,11 +32,16 @@ pub enum Instruction {
SetGlobal(u16, u32), SetGlobal(u16, u32),
/// R(A) := G[K(Bx)] /// R(A) := G[K(Bx)]
GetGlobal(u16, u32), GetGlobal(u16, u32),
/// R(A) := U[B]
GetUpVal(u16, u16),
/// [func] [params.len()] [ret_regs.len()] /// [func] [params.len()] [ret_regs.len()]
/// R(A), ... R(A+C-2) := R(A)(R(A+1), ... R(A+B-1)) /// R(A), ... R(A+C-2) := R(A)(R(A+1), ... R(A+B-1))
Call(u16, u16, u16), Call(u16, u16, u16),
/// return R(A), ... , R(B)
Return(u16, u16), Return(u16, u16),
/// close stack variables up to R(A)
Close(u16), Close(u16),
/// R(A) := closure(KPROTO[Bx], R(A), ..., R(A+n))
Closure(u16, u32), Closure(u16, u32),
} }
@ -47,6 +52,7 @@ impl Debug for Instruction {
Instruction::LoadK(arg0, arg1) => write!(f, "LOADK {} {}", arg0, arg1), Instruction::LoadK(arg0, arg1) => write!(f, "LOADK {} {}", arg0, arg1),
Instruction::SetGlobal(arg0, arg1) => write!(f, "SETGLOBAL {} {}", arg0, arg1), Instruction::SetGlobal(arg0, arg1) => write!(f, "SETGLOBAL {} {}", arg0, arg1),
Instruction::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1), Instruction::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1),
Instruction::GetUpVal(arg0, arg1) => write!(f, "GETUPVAL {} {}", arg0, arg1),
Instruction::Call(arg0, arg1, arg2) => write!(f, "CALL {} {} {}", arg0, arg1, arg2), Instruction::Call(arg0, arg1, arg2) => write!(f, "CALL {} {} {}", arg0, arg1, arg2),
Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0), Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0),
Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1), Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1),
@ -240,13 +246,29 @@ impl ClosureRunner {
} }
Instruction::Close(_) => {} Instruction::Close(_) => {}
Instruction::Closure(reg, protok) => { Instruction::Closure(reg, protok) => {
let highest_upvalue = self
.closure
.upvalues
.iter()
.map(|(v, _)| *v)
.max()
.unwrap_or(0);
let mut upvalues = self.closure.upvalues.clone();
for (reg, value) in &self.stack {
upvalues.insert(
reg + highest_upvalue + 1,
Rc::new(RefCell::new(value.clone())),
);
}
self.stack.insert( self.stack.insert(
*reg, *reg,
Value::Function(Closure { 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: HashMap::new(), upvalues,
}), }),
); );
} }
@ -256,8 +278,20 @@ impl ClosureRunner {
for i in *reg_start..=*reg_end { for i in *reg_start..=*reg_end {
ret_values.push(self.stack.get(&i).cloned().unwrap_or(Value::Nil)); ret_values.push(self.stack.get(&i).cloned().unwrap_or(Value::Nil));
} }
dbg!(&self.closure.upvalues);
return Some(ret_values); return Some(ret_values);
} }
Instruction::GetUpVal(reg, upvalreg) => {
self.stack.insert(
*reg,
self.closure
.upvalues
.get(upvalreg)
.unwrap()
.borrow()
.clone(),
);
}
}; };
self.program_counter += 1; self.program_counter += 1;