|
|
|
@ -1,5 +1,3 @@
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
instruction::Instruction,
|
|
|
|
|
value::{
|
|
|
|
@ -8,21 +6,21 @@ use crate::{
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[derive (Debug)]
|
|
|
|
|
#[derive (Clone, Debug)]
|
|
|
|
|
pub struct Upvalue {
|
|
|
|
|
pub in_stack: bool,
|
|
|
|
|
pub idx: u8,
|
|
|
|
|
pub kind: u8,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive (Debug)]
|
|
|
|
|
#[derive (Clone, Debug)]
|
|
|
|
|
pub struct Block {
|
|
|
|
|
pub instructions: Vec <Instruction>,
|
|
|
|
|
pub constants: Vec <Value>,
|
|
|
|
|
pub upvalues: Vec <Upvalue>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive (Debug)]
|
|
|
|
|
#[derive (Clone, Debug)]
|
|
|
|
|
pub struct Chunk {
|
|
|
|
|
pub blocks: Vec <Block>,
|
|
|
|
|
}
|
|
|
|
@ -47,7 +45,7 @@ pub struct Breakpoint {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive (Debug)]
|
|
|
|
|
pub struct State <'a> {
|
|
|
|
|
pub struct State {
|
|
|
|
|
pub registers: Vec <Value>,
|
|
|
|
|
// Currently only used for native function calls
|
|
|
|
|
top: usize,
|
|
|
|
@ -55,8 +53,8 @@ pub struct State <'a> {
|
|
|
|
|
|
|
|
|
|
pub debug_print: bool,
|
|
|
|
|
step_count: u32,
|
|
|
|
|
chunk: &'a Chunk,
|
|
|
|
|
upvalues: &'a [Value],
|
|
|
|
|
chunk: Chunk,
|
|
|
|
|
upvalues: Vec <Value>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lw_io_write (l: &mut State, num_args: usize) -> usize {
|
|
|
|
@ -142,8 +140,8 @@ pub struct StepError {
|
|
|
|
|
msg: &'static str,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl <'a> State <'a> {
|
|
|
|
|
pub fn new (chunk: &'a Chunk, upvalues: &'a [Value]) -> Self {
|
|
|
|
|
impl State {
|
|
|
|
|
pub fn new (chunk: Chunk, upvalues: Vec <Value>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
// TODO: Stack is actually supposed to grow to a limit of
|
|
|
|
|
// idk 10,000. I thought it was fixed at 256.
|
|
|
|
@ -232,11 +230,10 @@ impl <'a> State <'a> {
|
|
|
|
|
|
|
|
|
|
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
|
|
|
|
{
|
|
|
|
|
let chunk = self.chunk;
|
|
|
|
|
self.step_count += 1;
|
|
|
|
|
|
|
|
|
|
let frame = self.stack.last_mut ().unwrap ().clone ();
|
|
|
|
|
let block = chunk.blocks.get (frame.block_idx).unwrap ();
|
|
|
|
|
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
|
|
|
|
|
|
|
|
|
let mut next_pc = frame.program_counter;
|
|
|
|
|
|
|
|
|
@ -256,10 +253,10 @@ impl <'a> State <'a> {
|
|
|
|
|
self.make_step_error (msg, instruction)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match instruction {
|
|
|
|
|
match instruction.clone () {
|
|
|
|
|
Instruction::Add (a, b, c) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_c = self.reg (*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 ())
|
|
|
|
|
{
|
|
|
|
@ -271,24 +268,24 @@ impl <'a> State <'a> {
|
|
|
|
|
Value::from (v_b + v_c)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = x;
|
|
|
|
|
*self.reg_mut (a) = x;
|
|
|
|
|
},
|
|
|
|
|
Instruction::AddI (a, b, s_c) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_b = self.reg (b);
|
|
|
|
|
|
|
|
|
|
let x = if let Some (v_b) = v_b.as_int ()
|
|
|
|
|
{
|
|
|
|
|
Value::from (v_b + *s_c as i64)
|
|
|
|
|
Value::from (v_b + s_c as i64)
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
|
|
|
|
|
Value::from (v_b + f64::from (*s_c))
|
|
|
|
|
Value::from (v_b + f64::from (s_c))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = x;
|
|
|
|
|
*self.reg_mut (a) = x;
|
|
|
|
|
},
|
|
|
|
|
Instruction::Call (a, b, c) => {
|
|
|
|
|
let b = usize::from (*b);
|
|
|
|
|
let b = usize::from (b);
|
|
|
|
|
|
|
|
|
|
// Take arguments from registers [a + 1, a + b)
|
|
|
|
|
// Call the function in register [a]
|
|
|
|
@ -301,7 +298,7 @@ impl <'a> State <'a> {
|
|
|
|
|
// Do a clone here to avoid a borow problem.
|
|
|
|
|
// Should be fixable with more clever code.
|
|
|
|
|
|
|
|
|
|
let v_a = self.reg (*a).clone ();
|
|
|
|
|
let v_a = self.reg (a).clone ();
|
|
|
|
|
|
|
|
|
|
match v_a {
|
|
|
|
|
Value::BogusClosure (rc) => {
|
|
|
|
@ -315,7 +312,7 @@ impl <'a> State <'a> {
|
|
|
|
|
self.stack.push (StackFrame {
|
|
|
|
|
program_counter: 0,
|
|
|
|
|
block_idx: target_block,
|
|
|
|
|
register_offset: current_frame.register_offset + *a as usize + 1,
|
|
|
|
|
register_offset: current_frame.register_offset + a as usize + 1,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if self.debug_print {
|
|
|
|
@ -329,7 +326,7 @@ impl <'a> State <'a> {
|
|
|
|
|
},
|
|
|
|
|
Value::RsFunc (x) => {
|
|
|
|
|
let current_frame = self.stack.last ().unwrap ();
|
|
|
|
|
let new_offset = current_frame.register_offset + usize::from (*a) + 1;
|
|
|
|
|
let new_offset = current_frame.register_offset + usize::from (a) + 1;
|
|
|
|
|
|
|
|
|
|
// Trash the stack frame so it doesn't point to a
|
|
|
|
|
// valid Lua function
|
|
|
|
@ -340,7 +337,7 @@ impl <'a> State <'a> {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let num_args = if b == 0 {
|
|
|
|
|
self.top - *a as usize
|
|
|
|
|
self.top - a as usize
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
b - 1
|
|
|
|
@ -357,7 +354,7 @@ impl <'a> State <'a> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set up top for the next call
|
|
|
|
|
if *c == 0 {
|
|
|
|
|
if c == 0 {
|
|
|
|
|
self.top = popped_frame.register_offset - 1 + num_results;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@ -367,10 +364,10 @@ impl <'a> State <'a> {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Instruction::Closure (a, b) => {
|
|
|
|
|
let b = usize::try_from (*b).unwrap ();
|
|
|
|
|
let b = usize::try_from (b).unwrap ();
|
|
|
|
|
|
|
|
|
|
let idx = frame.block_idx + b + 1;
|
|
|
|
|
let block = &chunk.blocks [idx];
|
|
|
|
|
let block = &self.chunk.blocks [idx];
|
|
|
|
|
|
|
|
|
|
let mut new_upvalues = Vec::with_capacity (block.upvalues.len ());
|
|
|
|
|
for uv in &block.upvalues {
|
|
|
|
@ -384,31 +381,31 @@ impl <'a> State <'a> {
|
|
|
|
|
new_upvalues.push (val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = Value::from (BogusClosure {
|
|
|
|
|
*self.reg_mut (a) = Value::from (BogusClosure {
|
|
|
|
|
idx,
|
|
|
|
|
upvalues: new_upvalues,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
Instruction::Div (a, b, c) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_c = self.reg (*c);
|
|
|
|
|
let v_b = self.reg (b);
|
|
|
|
|
let v_c = self.reg (c);
|
|
|
|
|
|
|
|
|
|
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
|
|
|
|
|
|
|
|
|
|
let v_c = v_c.as_float ().ok_or_else (|| make_step_error ("C must be a number"))?;
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = Value::from (v_b / v_c);
|
|
|
|
|
*self.reg_mut (a) = Value::from (v_b / v_c);
|
|
|
|
|
},
|
|
|
|
|
Instruction::EqI (a, sb, k_flag) => {
|
|
|
|
|
if (self.reg (*a).as_int ().unwrap () == *sb as i64) != *k_flag
|
|
|
|
|
if (self.reg (a).as_int ().unwrap () == sb as i64) != k_flag
|
|
|
|
|
{
|
|
|
|
|
next_pc += 1;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Instruction::EqK (a, b, k_flag) => {
|
|
|
|
|
let b = usize::from (*b);
|
|
|
|
|
let b = usize::from (b);
|
|
|
|
|
|
|
|
|
|
if (*self.reg (*a) == k [b]) != *k_flag {
|
|
|
|
|
if (*self.reg (a) == k [b]) != k_flag {
|
|
|
|
|
next_pc += 1;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@ -416,60 +413,60 @@ impl <'a> State <'a> {
|
|
|
|
|
// This is used for NewTable. Maybe it's for reserving
|
|
|
|
|
// capacity in the array or something?
|
|
|
|
|
|
|
|
|
|
assert_eq! (*ax, 0, "implemented only for ax == 0");
|
|
|
|
|
assert_eq! (ax, 0, "implemented only for ax == 0");
|
|
|
|
|
},
|
|
|
|
|
Instruction::ForLoop (a, bx) => {
|
|
|
|
|
let mut iter = self.reg (*a + 3).as_int ().unwrap ();
|
|
|
|
|
let mut iter = self.reg (a + 3).as_int ().unwrap ();
|
|
|
|
|
iter += 1;
|
|
|
|
|
*self.reg_mut (*a + 3) = iter.into ();
|
|
|
|
|
*self.reg_mut (a + 3) = iter.into ();
|
|
|
|
|
|
|
|
|
|
let stop = self.reg (*a + 1).as_int ().unwrap ();
|
|
|
|
|
let stop = self.reg (a + 1).as_int ().unwrap ();
|
|
|
|
|
|
|
|
|
|
if iter <= stop {
|
|
|
|
|
next_pc -= i32::try_from (*bx).unwrap ();
|
|
|
|
|
next_pc -= i32::try_from (bx).unwrap ();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Instruction::ForPrep (a, bx) => {
|
|
|
|
|
let start = self.reg (*a).as_int ().unwrap ();
|
|
|
|
|
let stop = self.reg (*a + 1).as_int ().unwrap ();
|
|
|
|
|
let start = self.reg (a).as_int ().unwrap ();
|
|
|
|
|
let stop = self.reg (a + 1).as_int ().unwrap ();
|
|
|
|
|
|
|
|
|
|
if start > stop {
|
|
|
|
|
next_pc += i32::try_from (*bx).unwrap () + 1;
|
|
|
|
|
next_pc += i32::try_from (bx).unwrap () + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a + 3) = start.into ();
|
|
|
|
|
*self.reg_mut (a + 3) = start.into ();
|
|
|
|
|
},
|
|
|
|
|
Instruction::GetField (a, b, c) => {
|
|
|
|
|
let t = match self.reg (*b) {
|
|
|
|
|
let t = match self.reg (b) {
|
|
|
|
|
Value::Nil => Err (make_step_error ("R[B] must not be nil"))?,
|
|
|
|
|
Value::Table (t) => t,
|
|
|
|
|
_ => Err (make_step_error ("R[B] must be a table"))?,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let key = match &k [usize::from (*c)] {
|
|
|
|
|
let key = match &k [usize::from (c)] {
|
|
|
|
|
Value::String (s) => s,
|
|
|
|
|
_ => panic! ("K[C] must be a string"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let val = t.borrow ().get_str (key.as_str ()).clone ();
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = val;
|
|
|
|
|
*self.reg_mut (a) = val;
|
|
|
|
|
},
|
|
|
|
|
Instruction::GetTable (a, b, c) => {
|
|
|
|
|
let t = match self.reg (*b) {
|
|
|
|
|
let t = match self.reg (b) {
|
|
|
|
|
Value::Table (t) => t,
|
|
|
|
|
_ => panic! ("R[B] must be a table"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let key = self.reg (*c);
|
|
|
|
|
let key = self.reg (c);
|
|
|
|
|
|
|
|
|
|
let val = t.borrow ().get (key.clone ());
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = val;
|
|
|
|
|
*self.reg_mut (a) = val;
|
|
|
|
|
},
|
|
|
|
|
Instruction::GetTabUp (a, b, c) => {
|
|
|
|
|
let b = usize::try_from (*b).unwrap ();
|
|
|
|
|
let c = usize::try_from (*c).unwrap ();
|
|
|
|
|
let b = usize::try_from (b).unwrap ();
|
|
|
|
|
let c = usize::try_from (c).unwrap ();
|
|
|
|
|
|
|
|
|
|
// If we're inside a closure, use its upvalues
|
|
|
|
|
// instead of the chunk's upvalues
|
|
|
|
@ -495,17 +492,17 @@ impl <'a> State <'a> {
|
|
|
|
|
_ => panic! ("GetTabUp only supports string keys"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = table.get (key);
|
|
|
|
|
*self.reg_mut (a) = table.get (key);
|
|
|
|
|
},
|
|
|
|
|
Instruction::GetI (a, b, c) => {
|
|
|
|
|
let key = i64::try_from (*c).unwrap ();
|
|
|
|
|
let key = i64::try_from (c).unwrap ();
|
|
|
|
|
|
|
|
|
|
let value = {
|
|
|
|
|
let table = self.reg (*b).as_table ().expect ("GetI only works on tables").borrow ();
|
|
|
|
|
let table = self.reg (b).as_table ().expect ("GetI only works on tables").borrow ();
|
|
|
|
|
table.get_int (key)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = value;
|
|
|
|
|
*self.reg_mut (a) = value;
|
|
|
|
|
},
|
|
|
|
|
Instruction::GetUpVal (a, b) => {
|
|
|
|
|
let this_func = self.stack.last ().unwrap ().register_offset - 1;
|
|
|
|
@ -514,20 +511,20 @@ impl <'a> State <'a> {
|
|
|
|
|
_ => panic! ("Can't do GetUpVal outside a closure"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let b = usize::try_from (*b).unwrap ();
|
|
|
|
|
let b = usize::try_from (b).unwrap ();
|
|
|
|
|
|
|
|
|
|
let upvalue = match closure.borrow ().upvalues.get (b) {
|
|
|
|
|
Some (x) => x.clone (),
|
|
|
|
|
None => {
|
|
|
|
|
dbg! (chunk, &self);
|
|
|
|
|
dbg! (&self);
|
|
|
|
|
panic! ("Missing upvalue");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
*self.reg_mut (*a) = upvalue;
|
|
|
|
|
*self.reg_mut (a) = upvalue;
|
|
|
|
|
},
|
|
|
|
|
Instruction::Jmp (s_j) => next_pc += s_j,
|
|
|
|
|
Instruction::Len (a, b) => {
|
|
|
|
|
let len = match self.reg (*b) {
|
|
|
|
|
let len = match self.reg (b) {
|
|
|
|
|
Value::BogusClosure (_) => Err (make_step_error ("attempt to get length of a function value"))?,
|
|
|
|
|
Value::Boolean (_) => Err (make_step_error ("attempt to get length of a boolean value"))?,
|
|
|
|
|
Value::Float (_) => Err (make_step_error ("attempt to get length of a number value"))?,
|
|
|
|
@ -538,31 +535,31 @@ impl <'a> State <'a> {
|
|
|
|
|
Value::Table (t) => t.borrow ().length ().into (),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = len;
|
|
|
|
|
*self.reg_mut (a) = len;
|
|
|
|
|
}
|
|
|
|
|
Instruction::LoadF (a, sbx) => {
|
|
|
|
|
*self.reg_mut (*a) = Value::Float (*sbx as f64);
|
|
|
|
|
*self.reg_mut (a) = Value::Float (sbx as f64);
|
|
|
|
|
}
|
|
|
|
|
Instruction::LoadFalse (a) => {
|
|
|
|
|
*self.reg_mut (*a) = false.into ();
|
|
|
|
|
*self.reg_mut (a) = false.into ();
|
|
|
|
|
},
|
|
|
|
|
Instruction::LoadI (a, sbx) => {
|
|
|
|
|
*self.reg_mut (*a) = Value::Integer (*sbx as i64);
|
|
|
|
|
*self.reg_mut (a) = Value::Integer (sbx as i64);
|
|
|
|
|
},
|
|
|
|
|
Instruction::LoadK (a, bx) => {
|
|
|
|
|
let bx = usize::try_from (*bx).unwrap ();
|
|
|
|
|
let bx = usize::try_from (bx).unwrap ();
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = k [bx].clone ();
|
|
|
|
|
*self.reg_mut (a) = k [bx].clone ();
|
|
|
|
|
},
|
|
|
|
|
Instruction::LoadNil (a) => {
|
|
|
|
|
*self.reg_mut (*a) = Value::Nil;
|
|
|
|
|
*self.reg_mut (a) = Value::Nil;
|
|
|
|
|
},
|
|
|
|
|
Instruction::LoadTrue (a) => {
|
|
|
|
|
*self.reg_mut (*a) = true.into ();
|
|
|
|
|
*self.reg_mut (a) = true.into ();
|
|
|
|
|
},
|
|
|
|
|
Instruction::MmBin (a, b, _c) => {
|
|
|
|
|
let a = self.reg (*a);
|
|
|
|
|
let b = self.reg (*b);
|
|
|
|
|
let a = self.reg (a);
|
|
|
|
|
let b = self.reg (b);
|
|
|
|
|
|
|
|
|
|
if a.as_float().is_some() && b.as_float().is_some () {
|
|
|
|
|
// No need for metamethods
|
|
|
|
@ -578,20 +575,20 @@ impl <'a> State <'a> {
|
|
|
|
|
// Ignore
|
|
|
|
|
},
|
|
|
|
|
Instruction::ModK (a, b, c) => {
|
|
|
|
|
let b = self.reg (*b).as_int().unwrap ();
|
|
|
|
|
let c = k [usize::from (*c)].as_int ().unwrap ();
|
|
|
|
|
let b = self.reg (b).as_int().unwrap ();
|
|
|
|
|
let c = k [usize::from (c)].as_int ().unwrap ();
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = (b % c).into ();
|
|
|
|
|
*self.reg_mut (a) = (b % c).into ();
|
|
|
|
|
},
|
|
|
|
|
Instruction::Move (a, b) => {
|
|
|
|
|
// If the value in b is deleted instead of duplicated,
|
|
|
|
|
// a bunch of tests fail
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = self.reg (*b).clone ();
|
|
|
|
|
*self.reg_mut (a) = self.reg (b).clone ();
|
|
|
|
|
},
|
|
|
|
|
Instruction::Mul (a, b, c) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_c = self.reg (*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 ())
|
|
|
|
|
{
|
|
|
|
@ -603,11 +600,11 @@ impl <'a> State <'a> {
|
|
|
|
|
Value::from (v_b * v_c)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = x;
|
|
|
|
|
*self.reg_mut (a) = x;
|
|
|
|
|
},
|
|
|
|
|
Instruction::MulK (a, b, c) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_c = &k [usize::from (*c)];
|
|
|
|
|
let v_b = self.reg (b);
|
|
|
|
|
let v_c = &k [usize::from (c)];
|
|
|
|
|
|
|
|
|
|
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
|
|
|
|
|
{
|
|
|
|
@ -619,30 +616,30 @@ impl <'a> State <'a> {
|
|
|
|
|
Value::from (v_b * v_c)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = x;
|
|
|
|
|
*self.reg_mut (a) = x;
|
|
|
|
|
},
|
|
|
|
|
Instruction::NewTable (a) => {
|
|
|
|
|
*self.reg_mut (*a) = Value::Table (Default::default ());
|
|
|
|
|
*self.reg_mut (a) = Value::Table (Default::default ());
|
|
|
|
|
},
|
|
|
|
|
Instruction::Not (a, b) => {
|
|
|
|
|
*self.reg_mut (*a) = Value::Boolean (! self.reg (*b).is_truthy());
|
|
|
|
|
*self.reg_mut (a) = Value::Boolean (! self.reg (b).is_truthy());
|
|
|
|
|
}
|
|
|
|
|
Instruction::Return (a, b, _c, k) => {
|
|
|
|
|
let a = usize::try_from (*a).unwrap ();
|
|
|
|
|
let b = usize::try_from (*b).unwrap ();
|
|
|
|
|
Instruction::Return (a, b, _c, k_flag) => {
|
|
|
|
|
let a = usize::try_from (a).unwrap ();
|
|
|
|
|
let b = usize::try_from (b).unwrap ();
|
|
|
|
|
|
|
|
|
|
let popped_frame = self.stack.pop ().unwrap ();
|
|
|
|
|
|
|
|
|
|
// Build closure if needed. No point building if we're
|
|
|
|
|
// popping the last frame and exiting the program.
|
|
|
|
|
|
|
|
|
|
if *k && ! self.stack.is_empty () {
|
|
|
|
|
if k_flag && ! self.stack.is_empty () {
|
|
|
|
|
let closure_idx = match &self.registers [popped_frame.register_offset + a] {
|
|
|
|
|
Value::BogusClosure (rc) => rc.borrow ().idx,
|
|
|
|
|
_ => panic! ("Impossible"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let upvalue_count = chunk.blocks [closure_idx].upvalues.len ();
|
|
|
|
|
let upvalue_count = self.chunk.blocks [closure_idx].upvalues.len ();
|
|
|
|
|
|
|
|
|
|
let start_reg = a + popped_frame.register_offset - upvalue_count;
|
|
|
|
|
|
|
|
|
@ -690,7 +687,7 @@ impl <'a> State <'a> {
|
|
|
|
|
self.top = popped_frame.register_offset - 1 + 0;
|
|
|
|
|
},
|
|
|
|
|
Instruction::Return1 (a) => {
|
|
|
|
|
let a = usize::try_from (*a).unwrap ();
|
|
|
|
|
let a = usize::try_from (a).unwrap ();
|
|
|
|
|
let popped_frame = self.stack.pop ().unwrap ();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -715,58 +712,58 @@ impl <'a> State <'a> {
|
|
|
|
|
self.top = popped_frame.register_offset - 1 + 1;
|
|
|
|
|
},
|
|
|
|
|
Instruction::SetField (a, b, c, k_flag) => {
|
|
|
|
|
let value = if *k_flag {
|
|
|
|
|
&k [usize::from (*c)]
|
|
|
|
|
let value = if k_flag {
|
|
|
|
|
&k [usize::from (c)]
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
self.reg (*c)
|
|
|
|
|
self.reg (c)
|
|
|
|
|
}
|
|
|
|
|
.clone ();
|
|
|
|
|
|
|
|
|
|
let b = usize::try_from (*b).unwrap ();
|
|
|
|
|
let b = usize::try_from (b).unwrap ();
|
|
|
|
|
|
|
|
|
|
let key = match k.get (b).unwrap () {
|
|
|
|
|
Value::String (s) => s.as_ref (),
|
|
|
|
|
_ => panic! ("SetField only supports string keys"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut dst = self.reg (*a).as_table ()
|
|
|
|
|
let mut dst = self.reg (a).as_table ()
|
|
|
|
|
.expect ("SetField only works on tables").borrow_mut ();
|
|
|
|
|
|
|
|
|
|
dst.insert_str (key.as_str (), value);
|
|
|
|
|
},
|
|
|
|
|
Instruction::SetI (a, b, c, k_flag) => {
|
|
|
|
|
let value = if *k_flag {
|
|
|
|
|
&k [usize::from (*c)]
|
|
|
|
|
let value = if k_flag {
|
|
|
|
|
&k [usize::from (c)]
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
self.reg (*c)
|
|
|
|
|
self.reg (c)
|
|
|
|
|
}
|
|
|
|
|
.clone ();
|
|
|
|
|
|
|
|
|
|
let mut dst = self.reg_mut (*a).as_table ().expect ("SetI only works on tables").borrow_mut ();
|
|
|
|
|
let mut dst = self.reg_mut (a).as_table ().expect ("SetI only works on tables").borrow_mut ();
|
|
|
|
|
|
|
|
|
|
dst.insert_int (i64::from (*b), value);
|
|
|
|
|
dst.insert_int (i64::from (b), value);
|
|
|
|
|
},
|
|
|
|
|
Instruction::SetList (a, b, c, k) => {
|
|
|
|
|
if *b == 0 {
|
|
|
|
|
Instruction::SetList (a, b, c, k_flag) => {
|
|
|
|
|
if b == 0 {
|
|
|
|
|
panic! ("SetList with b == 0 not implemented");
|
|
|
|
|
}
|
|
|
|
|
if *k {
|
|
|
|
|
if k_flag {
|
|
|
|
|
panic! ("SetList with k = true not implemented");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut dst = self.reg (*a).as_table ().expect ("SetList only works on tables").borrow_mut ();
|
|
|
|
|
let mut dst = self.reg (a).as_table ().expect ("SetList only works on tables").borrow_mut ();
|
|
|
|
|
|
|
|
|
|
for i in 1..=*b {
|
|
|
|
|
let src = self.reg (*a + i);
|
|
|
|
|
dst.insert_int (i64::from (*c + i), src.clone ());
|
|
|
|
|
for i in 1..=b {
|
|
|
|
|
let src = self.reg (a + i);
|
|
|
|
|
dst.insert_int (i64::from (c + i), src.clone ());
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Instruction::SetTabUp (_a, _b, _c) => unimplemented! (),
|
|
|
|
|
Instruction::Sub (a, b, c) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_c = self.reg (*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 ())
|
|
|
|
|
{
|
|
|
|
@ -778,10 +775,10 @@ impl <'a> State <'a> {
|
|
|
|
|
Value::from (v_b - v_c)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = x;
|
|
|
|
|
*self.reg_mut (a) = x;
|
|
|
|
|
},
|
|
|
|
|
Instruction::TailCall (a, b, c, k) => {
|
|
|
|
|
let a = usize::from (*a);
|
|
|
|
|
let a = usize::from (a);
|
|
|
|
|
assert! (!k, "closing over values in tail calls not implemented");
|
|
|
|
|
|
|
|
|
|
let offset = frame.register_offset;
|
|
|
|
@ -792,7 +789,7 @@ impl <'a> State <'a> {
|
|
|
|
|
|
|
|
|
|
// Shift inputs into place
|
|
|
|
|
|
|
|
|
|
let b = usize::from (*b);
|
|
|
|
|
let b = usize::from (b);
|
|
|
|
|
|
|
|
|
|
let num_args = if b == 0 {
|
|
|
|
|
self.top - a
|
|
|
|
@ -816,7 +813,7 @@ impl <'a> State <'a> {
|
|
|
|
|
},
|
|
|
|
|
Value::RsFunc (x) => {
|
|
|
|
|
// Shift inputs into place
|
|
|
|
|
let b = usize::from (*b);
|
|
|
|
|
let b = usize::from (b);
|
|
|
|
|
for i in (offset)..(offset + b) {
|
|
|
|
|
self.registers [i] = self.registers [i + a + 1].take ();
|
|
|
|
|
}
|
|
|
|
@ -847,7 +844,7 @@ impl <'a> State <'a> {
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Set up top for the next call
|
|
|
|
|
if *c == 0 {
|
|
|
|
|
if c == 0 {
|
|
|
|
|
self.top = popped_frame.register_offset - 1 + num_results;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -858,13 +855,13 @@ impl <'a> State <'a> {
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Instruction::Test (a, k) => {
|
|
|
|
|
if self.reg (*a).is_truthy() != *k {
|
|
|
|
|
Instruction::Test (a, k_flag) => {
|
|
|
|
|
if self.reg (a).is_truthy() != k_flag {
|
|
|
|
|
next_pc += 1;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Instruction::UnM (a, b) => {
|
|
|
|
|
let v_b = self.reg (*b);
|
|
|
|
|
let v_b = self.reg (b);
|
|
|
|
|
|
|
|
|
|
let x = if let Some (v_b) = v_b.as_int ()
|
|
|
|
|
{
|
|
|
|
@ -875,7 +872,7 @@ impl <'a> State <'a> {
|
|
|
|
|
Value::from (-v_b)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
*self.reg_mut (*a) = x;
|
|
|
|
|
*self.reg_mut (a) = x;
|
|
|
|
|
},
|
|
|
|
|
Instruction::VarArgPrep (_) => (),
|
|
|
|
|
}
|
|
|
|
|