implement a couple more opcodes fighting the closure issue

main
_ 2023-09-29 16:15:00 -05:00
parent 4da634a2aa
commit f0d4f25cec
3 changed files with 72 additions and 16 deletions

View File

@ -167,7 +167,7 @@ impl State {
let v_b = self.reg (*b); let v_b = self.reg (*b);
let v_c = self.reg (*c); 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) Value::from (v_b + v_c)
} }
@ -177,7 +177,7 @@ impl State {
Value::from (v_b + v_c) Value::from (v_b + v_c)
}; };
*self.reg_mut (*a) = sum; *self.reg_mut (*a) = x;
}, },
Instruction::Call (a, b, _c) => { Instruction::Call (a, b, _c) => {
let b = usize::from (*b); let b = usize::from (*b);
@ -250,16 +250,24 @@ impl State {
Instruction::Closure (a, b) => { Instruction::Closure (a, b) => {
let b = usize::try_from (*b).unwrap (); let b = usize::try_from (*b).unwrap ();
let idx = b + frame.block_idx + 1; let idx = b + 1;
let block = &chunk.blocks [idx]; let block = &chunk.blocks [idx];
let upvalues = block.upvalues.iter ().map (|uv| {
assert! (uv.in_stack, "off-stack upvalues not implemented"); 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 () self.reg (uv.idx).clone ()
}).collect (); }
else {
// TODO: This isn't really correct
upvalues [usize::from (uv.idx)].clone ()
};
new_upvalues.push (val);
}
*self.reg_mut (*a) = Value::from (BogusClosure { *self.reg_mut (*a) = Value::from (BogusClosure {
idx, idx,
upvalues, upvalues: new_upvalues,
}); });
}, },
Instruction::EqI (a, sb, k_flag) => { Instruction::EqI (a, sb, k_flag) => {
@ -439,7 +447,22 @@ impl State {
Instruction::Move (a, b) => { Instruction::Move (a, b) => {
*self.reg_mut (*a) = self.reg (*b).clone (); *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) => { Instruction::NewTable (a) => {
*self.reg_mut (*a) = Value::Table (Default::default ()); *self.reg_mut (*a) = Value::Table (Default::default ());
}, },
@ -500,7 +523,10 @@ impl State {
return self.registers [a..(a + b - 1)].to_vec(); 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) => { Instruction::Return1 (a) => {
let a = usize::try_from (*a).unwrap (); let a = usize::try_from (*a).unwrap ();
let popped_frame = self.stack.pop ().unwrap (); let popped_frame = self.stack.pop ().unwrap ();
@ -574,7 +600,36 @@ impl State {
} }
}, },
Instruction::SetTabUp (_a, _b, _c) => unimplemented! (), 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) => { Instruction::Test (a, _k) => {
if self.reg (*a).is_truthy() { if self.reg (*a).is_truthy() {
next_pc += 1; next_pc += 1;
@ -590,6 +645,7 @@ impl State {
} }
} }
dbg! (self);
panic! ("Hit max iterations before block returned"); panic! ("Hit max iterations before block returned");
} }
} }

View File

@ -185,10 +185,10 @@ fn floats () {
#[test] #[test]
fn fma () { fn fma () {
let bytecode = include_bytes! ("../test_vectors/fma.luac"); let source = include_bytes! ("../test_vectors/fma.lua");
let mut rdr = std::io::Cursor::new (bytecode); let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ());
let chunk = crate::loader::parse_chunk (&mut rdr).unwrap (); let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
assert_eq! (chunk.blocks.len (), 4); assert_eq! (chunk.blocks.len (), 5);
assert_eq! (chunk.blocks [3].upvalues.len (), 2); assert_eq! (chunk.blocks [3].upvalues.len (), 2);

View File

@ -53,7 +53,7 @@ impl fmt::Display for Value {
Value::String (s) => write! (f, "{}", s), Value::String (s) => write! (f, "{}", s),
Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)), 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)),
} }
} }
} }