♻️ refactor: State owns its Chunk now

main
_ 2023-10-01 20:31:30 -05:00
parent 700b273a11
commit db84365c27
5 changed files with 138 additions and 147 deletions

View File

@ -51,7 +51,7 @@ fn main () -> Result <(), lwvm::StepError> {
let upvalues = lwvm::State::upvalues_from_args ([exe_name].into_iter ().chain (args)); let upvalues = lwvm::State::upvalues_from_args ([exe_name].into_iter ().chain (args));
let mut vm = lwvm::State::new (&chunk, &upvalues); let mut vm = lwvm::State::new (chunk, upvalues);
if std::env::var("LWVM_DEBUG").is_ok() { if std::env::var("LWVM_DEBUG").is_ok() {
vm.debug_print = true; vm.debug_print = true;
} }

View File

@ -9,11 +9,9 @@ use crate::{
}; };
pub fn compile_bytecode_from_file (path: &str) -> Vec <u8> { pub fn compile_bytecode_from_file (path: &str) -> Vec <u8> {
use std::{ use std::process::{
process::{
Command, Command,
Stdio, Stdio,
},
}; };
let child = Command::new ("luac5.4") let child = Command::new ("luac5.4")

View File

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

View File

@ -22,9 +22,9 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
/// Takes arguments and a parsed Lua chunk, runs its, /// Takes arguments and a parsed Lua chunk, runs its,
/// and returns the output /// and returns the output
fn run_chunk (args: &[&str], chunk: &Chunk) -> Vec <Value> { fn run_chunk (args: &[&str], chunk: Chunk) -> Vec <Value> {
let upvalues = State::upvalues_from_args (args.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (args.into_iter ().map (|s| s.to_string ()));
let mut vm = State::new (chunk, &upvalues); let mut vm = State::new (chunk, upvalues);
vm.execute_chunk (&[]).unwrap () vm.execute_chunk (&[]).unwrap ()
} }
@ -33,7 +33,7 @@ fn run_chunk (args: &[&str], chunk: &Chunk) -> Vec <Value> {
fn run_bytecode (args: &[&str], bc: &[u8]) -> Vec <Value> { fn run_bytecode (args: &[&str], bc: &[u8]) -> Vec <Value> {
let chunk = loader::parse_chunk_from_bytes (&bc).unwrap (); let chunk = loader::parse_chunk_from_bytes (&bc).unwrap ();
run_chunk (args, &chunk) run_chunk (args, chunk)
} }
/// Takes arguments and Lua source code, /// Takes arguments and Lua source code,
@ -119,7 +119,7 @@ fn bools () {
let expected: Vec <Value> = expected; let expected: Vec <Value> = expected;
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
let mut vm = State::new (&chunk, &upvalues); let mut vm = State::new (chunk.clone (), upvalues);
let actual = vm.execute_chunk (&[]).unwrap (); let actual = vm.execute_chunk (&[]).unwrap ();
assert_eq! (actual, expected); assert_eq! (actual, expected);
} }
@ -131,7 +131,7 @@ fn closure () {
let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ()); let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ());
let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap (); let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
assert_eq! (run_chunk (&["_exe_name"], &chunk), vec! [Value::from (23i64)]); assert_eq! (run_chunk (&["_exe_name"], chunk), vec! [Value::from (23i64)]);
} }
#[test] #[test]
@ -175,7 +175,7 @@ fn floats () {
] { ] {
let expected: Vec <Value> = expected; let expected: Vec <Value> = expected;
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
let mut vm = State::new (&chunk, &upvalues); let mut vm = State::new (chunk.clone (), upvalues);
let actual = vm.execute_chunk (&[]).unwrap (); let actual = vm.execute_chunk (&[]).unwrap ();
assert_eq! (actual, expected); assert_eq! (actual, expected);
@ -191,17 +191,13 @@ fn fma () {
assert_eq! (chunk.blocks [3].upvalues.len (), 2); assert_eq! (chunk.blocks [3].upvalues.len (), 2);
for (arg, expected) in [ let arg = vec! ["_exe_name"];
(vec! ["_exe_name"], vec! [122.into ()]),
(vec! ["_exe_name"], vec! [122.into ()]),
] {
let expected: Vec <Value> = expected;
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
let mut vm = State::new (&chunk, &upvalues); let mut vm = State::new (chunk, upvalues);
let actual = vm.execute_chunk (&[]).unwrap (); let actual = vm.execute_chunk (&[]).unwrap ();
let expected = vec! [Value::from (122)];
assert_eq! (actual, expected); assert_eq! (actual, expected);
}
} }
#[test] #[test]
@ -286,22 +282,22 @@ fn is_93 () {
let run = run_chunk; let run = run_chunk;
assert_eq! (run (&[""], &chunk), vec! [Value::from (1)]); assert_eq! (run (&[""], chunk.clone ()), vec! [Value::from (1)]);
assert_eq! (run (&["", "93"], &chunk), vec! [Value::from (0)]); assert_eq! (run (&["", "93"], chunk.clone ()), vec! [Value::from (0)]);
assert_eq! (run (&["", "94"], &chunk), vec! [Value::from (1)]); assert_eq! (run (&["", "94"], chunk.clone ()), vec! [Value::from (1)]);
} }
#[test] #[test]
fn native_functions () { fn native_functions () {
fn add (l: &mut State) -> i32 { fn add (_: &mut State) -> i32 {
0 0
} }
fn multiply (l: &mut State) -> i32 { fn multiply (_: &mut State) -> i32 {
0 0
} }
fn greet (l: &mut State) -> i32 { fn greet (_: &mut State) -> i32 {
0 0
} }
@ -372,7 +368,7 @@ fn tailcall () {
assert_eq! (chunk.blocks [0].instructions [3], Instruction::TailCall (0, 2, 1, false)); assert_eq! (chunk.blocks [0].instructions [3], Instruction::TailCall (0, 2, 1, false));
let actual = run_chunk (&[], &chunk); let actual = run_chunk (&[], chunk);
let expected = vec! [Value::from (5)]; let expected = vec! [Value::from (5)];
assert_eq! (actual, expected); assert_eq! (actual, expected);

View File

@ -35,7 +35,7 @@ fn embedding () {
Value::from_iter (env.into_iter ()), Value::from_iter (env.into_iter ()),
]; ];
let mut vm = State::new (&chunk, &upvalues); let mut vm = State::new (chunk, upvalues);
let output = vm.execute_chunk (&vec! []).unwrap (); let output = vm.execute_chunk (&vec! []).unwrap ();
assert_eq! (output, vec! [Value::from (2019)]); assert_eq! (output, vec! [Value::from (2019)]);