From f0d4f25cecb1a749573c47565d724b4412632e1b Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Fri, 29 Sep 2023 16:15:00 -0500 Subject: [PATCH] implement a couple more opcodes fighting the closure issue --- src/state.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++-------- src/tests.rs | 8 +++--- src/value.rs | 2 +- 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/state.rs b/src/state.rs index f1afaad..8b42999 100644 --- a/src/state.rs +++ b/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"); } } diff --git a/src/tests.rs b/src/tests.rs index b2dd596..5956353 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -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); diff --git a/src/value.rs b/src/value.rs index d1569bc..60eb2ef 100644 --- a/src/value.rs +++ b/src/value.rs @@ -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)), } } }