implement a couple more opcodes fighting the closure issue
parent
4da634a2aa
commit
f0d4f25cec
78
src/state.rs
78
src/state.rs
|
@ -167,7 +167,7 @@ impl State {
|
|||
let v_b = self.reg (*b);
|
||||
let v_c = self.reg (*c);
|
||||
|
||||
let sum = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
|
||||
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
|
||||
{
|
||||
Value::from (v_b + v_c)
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ impl State {
|
|||
Value::from (v_b + v_c)
|
||||
};
|
||||
|
||||
*self.reg_mut (*a) = sum;
|
||||
*self.reg_mut (*a) = x;
|
||||
},
|
||||
Instruction::Call (a, b, _c) => {
|
||||
let b = usize::from (*b);
|
||||
|
@ -250,16 +250,24 @@ impl State {
|
|||
Instruction::Closure (a, b) => {
|
||||
let b = usize::try_from (*b).unwrap ();
|
||||
|
||||
let idx = b + frame.block_idx + 1;
|
||||
let idx = b + 1;
|
||||
let block = &chunk.blocks [idx];
|
||||
let upvalues = block.upvalues.iter ().map (|uv| {
|
||||
assert! (uv.in_stack, "off-stack upvalues not implemented");
|
||||
self.reg (uv.idx).clone ()
|
||||
}).collect ();
|
||||
|
||||
let mut new_upvalues = Vec::with_capacity (block.upvalues.len ());
|
||||
for uv in &block.upvalues {
|
||||
let val = if uv.in_stack {
|
||||
self.reg (uv.idx).clone ()
|
||||
}
|
||||
else {
|
||||
// TODO: This isn't really correct
|
||||
upvalues [usize::from (uv.idx)].clone ()
|
||||
};
|
||||
new_upvalues.push (val);
|
||||
}
|
||||
|
||||
*self.reg_mut (*a) = Value::from (BogusClosure {
|
||||
idx,
|
||||
upvalues,
|
||||
upvalues: new_upvalues,
|
||||
});
|
||||
},
|
||||
Instruction::EqI (a, sb, k_flag) => {
|
||||
|
@ -439,7 +447,22 @@ impl State {
|
|||
Instruction::Move (a, b) => {
|
||||
*self.reg_mut (*a) = self.reg (*b).clone ();
|
||||
},
|
||||
Instruction::Mul (_a, _b, _c) => unimplemented!(),
|
||||
Instruction::Mul (a, b, c) => {
|
||||
let v_b = self.reg (*b);
|
||||
let v_c = self.reg (*c);
|
||||
|
||||
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
|
||||
{
|
||||
Value::from (v_b * v_c)
|
||||
}
|
||||
else {
|
||||
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
|
||||
let v_c = v_c.as_float ().unwrap_or_else (|| panic! ("{v_c}"));
|
||||
Value::from (v_b * v_c)
|
||||
};
|
||||
|
||||
*self.reg_mut (*a) = x;
|
||||
},
|
||||
Instruction::NewTable (a) => {
|
||||
*self.reg_mut (*a) = Value::Table (Default::default ());
|
||||
},
|
||||
|
@ -500,7 +523,10 @@ impl State {
|
|||
return self.registers [a..(a + b - 1)].to_vec();
|
||||
}
|
||||
},
|
||||
Instruction::Return0 => unimplemented! (),
|
||||
Instruction::Return0 => {
|
||||
self.stack.pop ();
|
||||
next_pc = self.stack.last ().unwrap ().program_counter;
|
||||
},
|
||||
Instruction::Return1 (a) => {
|
||||
let a = usize::try_from (*a).unwrap ();
|
||||
let popped_frame = self.stack.pop ().unwrap ();
|
||||
|
@ -574,7 +600,36 @@ impl State {
|
|||
}
|
||||
},
|
||||
Instruction::SetTabUp (_a, _b, _c) => unimplemented! (),
|
||||
Instruction::TailCall (_a, _b, _c, _k) => unimplemented! (),
|
||||
Instruction::TailCall (a, b, _c, k) => {
|
||||
assert! (!k, "closing over values in tail calls not implemented");
|
||||
|
||||
// Shift closure and inputs into place
|
||||
let a = usize::from (*a);
|
||||
let b = usize::from (*b);
|
||||
let offset = frame.register_offset - 1;
|
||||
for i in (offset)..(offset + b) {
|
||||
self.registers [i] = self.registers [i + a + 1].take ();
|
||||
}
|
||||
|
||||
let value = &self.registers [offset];
|
||||
let closure = if let Some (x) = value.as_closure () {
|
||||
x
|
||||
}
|
||||
else {
|
||||
dbg! (self);
|
||||
panic! ("OP_TAILCALL only implemented for closures");
|
||||
};
|
||||
let closure = closure.borrow ();
|
||||
|
||||
// Jump into the other function
|
||||
|
||||
let frame = self.stack.last_mut ().unwrap ();
|
||||
frame.program_counter = 0;
|
||||
frame.block_idx = closure.idx;
|
||||
|
||||
// Skip the PC increment
|
||||
continue;
|
||||
},
|
||||
Instruction::Test (a, _k) => {
|
||||
if self.reg (*a).is_truthy() {
|
||||
next_pc += 1;
|
||||
|
@ -590,6 +645,7 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
dbg! (self);
|
||||
panic! ("Hit max iterations before block returned");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,10 +185,10 @@ fn floats () {
|
|||
|
||||
#[test]
|
||||
fn fma () {
|
||||
let bytecode = include_bytes! ("../test_vectors/fma.luac");
|
||||
let mut rdr = std::io::Cursor::new (bytecode);
|
||||
let chunk = crate::loader::parse_chunk (&mut rdr).unwrap ();
|
||||
assert_eq! (chunk.blocks.len (), 4);
|
||||
let source = include_bytes! ("../test_vectors/fma.lua");
|
||||
let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ());
|
||||
let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
|
||||
assert_eq! (chunk.blocks.len (), 5);
|
||||
|
||||
assert_eq! (chunk.blocks [3].upvalues.len (), 2);
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ impl fmt::Display for Value {
|
|||
Value::String (s) => write! (f, "{}", s),
|
||||
Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)),
|
||||
|
||||
Value::BogusClosure (_) => write! (f, "BogusClosure"),
|
||||
Value::BogusClosure (x) => write! (f, "BogusClosure: {:?}", std::rc::Rc::as_ptr (x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue