diff --git a/src/main.rs b/src/main.rs index 5bd590f..acd91dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,12 +14,24 @@ fn main () { let mut list_bytecode = false; let mut pipe_bytecode = false; let mut script = None; + let mut breakpoints = vec![]; let mut args = std::env::args (); let exe_name = args.next ().unwrap (); while let Some (arg) = args.next () { match arg.as_str () { + "--break" => { + let s = args.next ().unwrap (); + let (block_idx, program_counter) = s.split_once (":").unwrap (); + let block_idx = str::parse (block_idx).unwrap (); + let program_counter = str::parse (program_counter).unwrap (); + + breakpoints.push (state::Breakpoint { + block_idx, + program_counter, + }); + }, "--list-bytecode" => list_bytecode = true, "--pipe-bytecode" => pipe_bytecode = true, "--script" => script = Some (args.next ().unwrap ()), @@ -52,10 +64,7 @@ fn main () { let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args)); - vm.breakpoints.push (state::Breakpoint { - block_idx: 3, - program_counter: 0, - }); + vm.breakpoints = breakpoints; vm.execute_chunk (&chunk, &upvalues); } diff --git a/src/state.rs b/src/state.rs index 086142e..f1afaad 100644 --- a/src/state.rs +++ b/src/state.rs @@ -172,7 +172,9 @@ impl State { Value::from (v_b + v_c) } else { - Value::from (v_b.as_float ().unwrap () + v_c.as_float ().unwrap ()) + 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) = sum; @@ -195,7 +197,7 @@ impl State { match v_a { Value::BogusClosure (rc) => { - let idx = rc.idx; + let idx = rc.borrow ().idx; let block_idx = frame.block_idx; let target_block = idx; @@ -248,10 +250,17 @@ impl State { Instruction::Closure (a, b) => { let b = usize::try_from (*b).unwrap (); - *self.reg_mut (*a) = Value::BogusClosure (BogusClosure { - idx: b + frame.block_idx + 1, - upvalues: vec! [], - }.into ()); + let idx = b + frame.block_idx + 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 (); + + *self.reg_mut (*a) = Value::from (BogusClosure { + idx, + upvalues, + }); }, Instruction::EqI (a, sb, k_flag) => { if (self.reg (*a).as_int ().unwrap () == *sb as i64) != *k_flag @@ -324,7 +333,24 @@ impl State { let b = usize::try_from (*b).unwrap (); let c = usize::try_from (*c).unwrap (); - let table = upvalues.get (b).unwrap ().as_table ().expect ("GetTabUp only works on tables").borrow (); + // If we're inside a closure, use its upvalues + // instead of the chunk's upvalues + + let frame = self.stack.last ().unwrap (); + let value = if frame.register_offset == 0 { + upvalues.get (b).unwrap ().clone () + } + else if let Some (cell) = self.registers [frame.register_offset - 1].as_closure () + { + let closure = cell.borrow (); + let value = closure.upvalues.get (b).unwrap (); + value.clone () + } + else { + upvalues.get (b).unwrap ().clone () + }; + + let table = value.as_table ().expect ("GetTabUp only works on tables").borrow (); let key = match k.get (c).unwrap () { Value::String (s) => String::from (s.as_ref()), @@ -345,14 +371,14 @@ impl State { }, Instruction::GetUpVal (a, b) => { let this_func = self.stack.last ().unwrap ().register_offset - 1; - let upvalues = match &self.registers [this_func] { - Value::BogusClosure (rc) => &rc.upvalues, + let closure = match &self.registers [this_func] { + Value::BogusClosure (rc) => rc.clone (), _ => panic! ("Can't do GetUpVal outside a closure"), }; let b = usize::try_from (*b).unwrap (); - let upvalue = match upvalues.get (b) { + let upvalue = match closure.borrow ().upvalues.get (b) { Some (x) => x.clone (), None => { dbg! (chunk, &self); @@ -430,7 +456,7 @@ impl State { if *k { let closure_idx = match &self.registers [popped_frame.register_offset + a] { - Value::BogusClosure (rc) => rc.idx, + Value::BogusClosure (rc) => rc.borrow ().idx, _ => panic! ("Impossible"), }; @@ -440,10 +466,10 @@ impl State { let upvalues = self.registers [start_reg..start_reg+upvalue_count].iter ().cloned ().collect (); - self.registers [a + popped_frame.register_offset] = Value::BogusClosure (BogusClosure { + self.registers [a + popped_frame.register_offset] = Value::from (BogusClosure { idx: closure_idx, upvalues, - }.into ()); + }); } if self.debug_print { diff --git a/src/value.rs b/src/value.rs index 648dd5b..d1569bc 100644 --- a/src/value.rs +++ b/src/value.rs @@ -32,7 +32,7 @@ pub enum Value { // These are all bogus, I haven't figured out how to implement // closures yet - BogusClosure (Rc ), + BogusClosure (Rc >), } impl Default for Value { @@ -58,6 +58,12 @@ impl fmt::Display for Value { } } +impl From for Value { + fn from (x: BogusClosure) -> Self { + Self::BogusClosure (Rc::new (RefCell::new (x))) + } +} + impl From for Value { fn from (x: bool) -> Self { Self::Boolean (x) @@ -156,6 +162,13 @@ impl PartialEq for Value { } impl Value { + pub fn as_closure (&self) -> Option <&Rc >> { + match self { + Self::BogusClosure (x) => Some (x), + _ => None, + } + } + /// Coerces ints to float pub fn as_float (&self) -> Option { diff --git a/test_vectors/closure.lua b/test_vectors/closure.lua index d15dfb3..1a8f357 100644 --- a/test_vectors/closure.lua +++ b/test_vectors/closure.lua @@ -1,11 +1,11 @@ -local function make_closure (x) - print (x) +local function make_closure (t) return function (y) - return x + y + return t.x + y end end -local f = make_closure (11) +local f = make_closure ({ x = 11 }) +local t = {} local x = f (12) print (x) return x