Implement upvalues
This commit is contained in:
parent
5c96834e5c
commit
9d471400d9
@ -1,6 +1,8 @@
|
|||||||
function add(x)
|
function add(x)
|
||||||
|
return function test()
|
||||||
return x
|
return x
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
global d = add(5)
|
global d = add(5)
|
||||||
global c = print(d)
|
global c = print(d())
|
||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
36
src/vm.rs
36
src/vm.rs
@ -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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user