🚧 wip: always keep at least one stack frame handy
This removes a bunch of unwraps but doesn't make it any fastermain
parent
66fe54adef
commit
11fd5b6cbc
|
@ -26,7 +26,7 @@ pub struct Chunk {
|
||||||
pub blocks: Vec <Block>,
|
pub blocks: Vec <Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Clone, Debug, Default)]
|
#[derive (Clone, Copy, Debug, Default)]
|
||||||
pub struct StackFrame {
|
pub struct StackFrame {
|
||||||
// Starts at 0 right after OP_CALL
|
// Starts at 0 right after OP_CALL
|
||||||
|
|
||||||
|
@ -50,15 +50,12 @@ pub struct State {
|
||||||
// Currently only used for native function calls
|
// Currently only used for native function calls
|
||||||
top: usize,
|
top: usize,
|
||||||
pub stack: Vec <StackFrame>,
|
pub stack: Vec <StackFrame>,
|
||||||
|
stack_top: StackFrame,
|
||||||
|
|
||||||
pub debug_print: bool,
|
pub debug_print: bool,
|
||||||
step_count: u32,
|
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
pub upvalues: Vec <Value>,
|
pub upvalues: Vec <Value>,
|
||||||
pub si: Interner,
|
pub si: Interner,
|
||||||
register_offset: usize,
|
|
||||||
block_idx: usize,
|
|
||||||
next_pc: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lw_io_write (l: &mut State, num_args: usize) -> usize {
|
fn lw_io_write (l: &mut State, num_args: usize) -> usize {
|
||||||
|
@ -188,17 +185,12 @@ impl State {
|
||||||
// idk 10,000. I thought it was fixed at 256.
|
// idk 10,000. I thought it was fixed at 256.
|
||||||
registers: vec! [Value::Nil; 256],
|
registers: vec! [Value::Nil; 256],
|
||||||
top: 0,
|
top: 0,
|
||||||
stack: vec! [
|
stack: vec! [],
|
||||||
StackFrame::default (),
|
stack_top: Default::default (),
|
||||||
],
|
|
||||||
debug_print: false,
|
debug_print: false,
|
||||||
step_count: 0,
|
|
||||||
chunk,
|
chunk,
|
||||||
upvalues,
|
upvalues,
|
||||||
si: Default::default (),
|
si: Default::default (),
|
||||||
register_offset: 0,
|
|
||||||
block_idx: 0,
|
|
||||||
next_pc: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,22 +202,17 @@ impl State {
|
||||||
// idk 10,000. I thought it was fixed at 256.
|
// idk 10,000. I thought it was fixed at 256.
|
||||||
registers: vec! [Value::Nil; 256],
|
registers: vec! [Value::Nil; 256],
|
||||||
top: 0,
|
top: 0,
|
||||||
stack: vec! [
|
stack: vec! [],
|
||||||
StackFrame::default (),
|
stack_top: Default::default (),
|
||||||
],
|
|
||||||
debug_print: false,
|
debug_print: false,
|
||||||
step_count: 0,
|
|
||||||
chunk,
|
chunk,
|
||||||
upvalues,
|
upvalues,
|
||||||
si,
|
si,
|
||||||
register_offset: 0,
|
|
||||||
block_idx: 0,
|
|
||||||
next_pc: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at_breakpoint (&self, bp: &Breakpoint) -> bool {
|
pub fn at_breakpoint (&self, bp: &Breakpoint) -> bool {
|
||||||
let frame = self.stack.last ().unwrap ();
|
let frame = &self.stack_top;
|
||||||
frame.block_idx == bp.block_idx && frame.program_counter == bp.program_counter
|
frame.block_idx == bp.block_idx && frame.program_counter == bp.program_counter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,29 +254,29 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_window (&self) -> &[Value] {
|
fn register_window (&self) -> &[Value] {
|
||||||
let frame = self.stack.last ().unwrap ();
|
let frame = &self.stack_top;
|
||||||
&self.registers [frame.register_offset..]
|
&self.registers [frame.register_offset..]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Short form to get access to a register within our window
|
/// Short form to get access to a register within our window
|
||||||
|
|
||||||
pub fn reg (&self, i: u8) -> &Value {
|
pub fn reg (&self, i: u8) -> &Value {
|
||||||
&self.registers [self.register_offset + i as usize]
|
&self.registers [self.stack_top.register_offset + i as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reg_mut (&mut self, i: u8) -> &mut Value {
|
pub fn reg_mut (&mut self, i: u8) -> &mut Value {
|
||||||
&mut self.registers [self.register_offset + i as usize]
|
&mut self.registers [self.stack_top.register_offset + i as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
// For native functions to check how many args they got
|
// For native functions to check how many args they got
|
||||||
pub fn get_top (&self) -> usize {
|
pub fn get_top (&self) -> usize {
|
||||||
self.top - self.stack.last ().unwrap ().register_offset
|
self.top - self.stack_top.register_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_step_error (&self, msg: &'static str, inst: &Instruction) -> StepError
|
fn make_step_error (&self, msg: &'static str, inst: &Instruction) -> StepError
|
||||||
{
|
{
|
||||||
StepError::Generic {
|
StepError::Generic {
|
||||||
frame: self.stack.last ().unwrap ().clone (),
|
frame: self.stack_top.clone (),
|
||||||
inst: inst.clone (),
|
inst: inst.clone (),
|
||||||
msg,
|
msg,
|
||||||
}
|
}
|
||||||
|
@ -332,35 +319,31 @@ impl State {
|
||||||
|
|
||||||
let target_block = idx;
|
let target_block = idx;
|
||||||
|
|
||||||
let new_frame = StackFrame {
|
self.stack.push (self.stack_top);
|
||||||
|
self.stack_top = StackFrame {
|
||||||
program_counter: 0,
|
program_counter: 0,
|
||||||
block_idx: target_block,
|
block_idx: target_block,
|
||||||
register_offset: self.register_offset + a as usize + 1,
|
register_offset: self.stack_top.register_offset + a as usize + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.next_pc = 0;
|
|
||||||
self.block_idx = target_block;
|
|
||||||
self.register_offset = new_frame.register_offset;
|
|
||||||
|
|
||||||
self.stack.push (new_frame);
|
|
||||||
|
|
||||||
// Skip the PC increment at the bottom of the loop
|
// Skip the PC increment at the bottom of the loop
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
Value::RsFunc (x) => {
|
Value::RsFunc (x) => {
|
||||||
let old_offset = self.register_offset;
|
let old_offset = self.stack_top.register_offset;
|
||||||
self.register_offset = old_offset + usize::from (a) + 1;
|
self.stack_top.register_offset = old_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
|
||||||
self.stack.push (StackFrame {
|
self.stack.push (self.stack_top);
|
||||||
|
self.stack_top = StackFrame {
|
||||||
program_counter: 65535, // Bogus for native functions
|
program_counter: 65535, // Bogus for native functions
|
||||||
block_idx: 65535, // Bogus
|
block_idx: 65535, // Bogus
|
||||||
register_offset: self.register_offset,
|
register_offset: self.stack_top.register_offset,
|
||||||
});
|
};
|
||||||
|
|
||||||
let num_args = if b == 0 {
|
let num_args = if b == 0 {
|
||||||
self.top - self.register_offset
|
self.top - self.stack_top.register_offset
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b - 1
|
b - 1
|
||||||
|
@ -369,8 +352,9 @@ impl State {
|
||||||
// Call
|
// Call
|
||||||
let num_results = x (self, num_args);
|
let num_results = x (self, num_args);
|
||||||
|
|
||||||
let popped_frame = self.stack.pop ().unwrap ();
|
let popped_frame = self.stack_top;
|
||||||
self.register_offset = old_offset;
|
self.stack_top = self.stack.pop ().unwrap ();
|
||||||
|
self.stack_top.register_offset = old_offset;
|
||||||
let offset = old_offset + usize::from (a);
|
let offset = old_offset + usize::from (a);
|
||||||
|
|
||||||
for i in (offset)..(offset + usize::try_from (num_results).unwrap ()) {
|
for i in (offset)..(offset + usize::try_from (num_results).unwrap ()) {
|
||||||
|
@ -406,7 +390,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_get_field (&mut self, a: u8, b: u8, c: u8) {
|
fn op_get_field (&mut self, a: u8, b: u8, c: u8) {
|
||||||
let block = self.chunk.blocks.get (self.block_idx).unwrap ();
|
let block = self.chunk.blocks.get (self.stack_top.block_idx).unwrap ();
|
||||||
let constants = &block.constants;
|
let constants = &block.constants;
|
||||||
|
|
||||||
let key = match &constants [usize::from (c)] {
|
let key = match &constants [usize::from (c)] {
|
||||||
|
@ -414,7 +398,7 @@ impl State {
|
||||||
_ => panic! ("K[C] must be a string"),
|
_ => panic! ("K[C] must be a string"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let val = match &self.registers [self.register_offset + usize::from (b)] {
|
let val = match &self.registers [self.stack_top.register_offset + usize::from (b)] {
|
||||||
Value::Nil => panic! ("R[B] must not be nil"),
|
Value::Nil => panic! ("R[B] must not be nil"),
|
||||||
Value::Table (t) => t.borrow ().get_str (*key).clone (),
|
Value::Table (t) => t.borrow ().get_str (*key).clone (),
|
||||||
_ => panic! ("R[B] must be a table"),
|
_ => panic! ("R[B] must be a table"),
|
||||||
|
@ -464,7 +448,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_set_field (&mut self, a: u8, b: u8, c: u8, k: bool) {
|
fn op_set_field (&mut self, a: u8, b: u8, c: u8, k: bool) {
|
||||||
let frame = self.stack.last ().unwrap ();
|
let frame = &self.stack_top;
|
||||||
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
||||||
let constants = &block.constants;
|
let constants = &block.constants;
|
||||||
|
|
||||||
|
@ -505,11 +489,11 @@ impl State {
|
||||||
|
|
||||||
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
||||||
{
|
{
|
||||||
let block = self.chunk.blocks.get (self.block_idx).unwrap ();
|
let block = self.chunk.blocks.get (self.stack_top.block_idx).unwrap ();
|
||||||
let instruction = match block.instructions.get (self.next_pc) {
|
let instruction = match block.instructions.get (self.stack_top.program_counter) {
|
||||||
Some (x) => *x,
|
Some (x) => *x,
|
||||||
None => {
|
None => {
|
||||||
dbg! (&self.stack);
|
dbg! (&self.stack, &self.stack_top);
|
||||||
panic! ("program_counter went out of bounds");
|
panic! ("program_counter went out of bounds");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -523,7 +507,7 @@ impl State {
|
||||||
match instruction {
|
match instruction {
|
||||||
Instruction::Add (a, b, c) => {
|
Instruction::Add (a, b, c) => {
|
||||||
if self.op_add (a, b, c) {
|
if self.op_add (a, b, c) {
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::AddI (a, b, s_c) => {
|
Instruction::AddI (a, b, s_c) => {
|
||||||
|
@ -549,7 +533,7 @@ 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 = self.block_idx + b + 1;
|
let idx = self.stack_top.block_idx + b + 1;
|
||||||
let block = &self.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 ());
|
||||||
|
@ -574,20 +558,20 @@ impl State {
|
||||||
},
|
},
|
||||||
Instruction::Div (a, b, c) => {
|
Instruction::Div (a, b, c) => {
|
||||||
if self.op_div (a, b, c) {
|
if self.op_div (a, b, c) {
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
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
|
||||||
{
|
{
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 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 {
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::ExtraArg (ax) => {
|
Instruction::ExtraArg (ax) => {
|
||||||
|
@ -604,7 +588,7 @@ impl State {
|
||||||
let stop = self.reg (a + 1).as_int ().unwrap ();
|
let stop = self.reg (a + 1).as_int ().unwrap ();
|
||||||
|
|
||||||
if iter <= stop {
|
if iter <= stop {
|
||||||
self.next_pc -= usize::try_from (bx).unwrap ();
|
self.stack_top.program_counter -= usize::try_from (bx).unwrap ();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::ForPrep (a, bx) => {
|
Instruction::ForPrep (a, bx) => {
|
||||||
|
@ -612,7 +596,7 @@ impl State {
|
||||||
let stop = self.reg (a + 1).as_int ().unwrap ();
|
let stop = self.reg (a + 1).as_int ().unwrap ();
|
||||||
|
|
||||||
if start > stop {
|
if start > stop {
|
||||||
self.next_pc += usize::try_from (bx).unwrap () + 1;
|
self.stack_top.program_counter += usize::try_from (bx).unwrap () + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*self.reg_mut (a + 3) = start.into ();
|
*self.reg_mut (a + 3) = start.into ();
|
||||||
|
@ -630,7 +614,7 @@ impl State {
|
||||||
// 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
|
||||||
|
|
||||||
let frame = self.stack.last ().unwrap ();
|
let frame = &self.stack_top;
|
||||||
let value = if frame.register_offset == 0 {
|
let value = if frame.register_offset == 0 {
|
||||||
self.upvalues.get (b).unwrap ().clone ()
|
self.upvalues.get (b).unwrap ().clone ()
|
||||||
}
|
}
|
||||||
|
@ -664,7 +648,7 @@ impl State {
|
||||||
*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_top.register_offset - 1;
|
||||||
let closure = match &self.registers [this_func] {
|
let closure = match &self.registers [this_func] {
|
||||||
Value::BogusClosure (rc) => rc.clone (),
|
Value::BogusClosure (rc) => rc.clone (),
|
||||||
_ => panic! ("Can't do GetUpVal outside a closure"),
|
_ => panic! ("Can't do GetUpVal outside a closure"),
|
||||||
|
@ -681,7 +665,7 @@ impl State {
|
||||||
};
|
};
|
||||||
*self.reg_mut (a) = upvalue;
|
*self.reg_mut (a) = upvalue;
|
||||||
},
|
},
|
||||||
Instruction::Jmp (s_j) => self.next_pc = usize::try_from (i32::try_from (self.next_pc).unwrap () + s_j).unwrap (),
|
Instruction::Jmp (s_j) => self.stack_top.program_counter = usize::try_from (i32::try_from (self.stack_top.program_counter).unwrap () + s_j).unwrap (),
|
||||||
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"))?,
|
||||||
|
@ -742,7 +726,7 @@ impl State {
|
||||||
// skip the OP_MMBIN that probably comes after this
|
// skip the OP_MMBIN that probably comes after this
|
||||||
|
|
||||||
if self.op_mul (a, b, c) {
|
if self.op_mul (a, b, c) {
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::MulK (a, b, c) => {
|
Instruction::MulK (a, b, c) => {
|
||||||
|
@ -771,7 +755,7 @@ impl State {
|
||||||
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_top;
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -802,10 +786,8 @@ impl State {
|
||||||
println! ("stack_depth: {stack_depth}");
|
println! ("stack_depth: {stack_depth}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some (new_frame) = self.stack.last() {
|
if let Some (new_frame) = self.stack.pop () {
|
||||||
self.block_idx = new_frame.block_idx;
|
self.stack_top = new_frame;
|
||||||
self.next_pc = new_frame.program_counter;
|
|
||||||
self.register_offset = new_frame.register_offset;
|
|
||||||
|
|
||||||
// Shift our output registers down so the caller
|
// Shift our output registers down so the caller
|
||||||
// can grab them
|
// can grab them
|
||||||
|
@ -827,24 +809,17 @@ impl State {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::Return0 => {
|
Instruction::Return0 => {
|
||||||
let popped_frame = self.stack.pop ().unwrap ();
|
let popped_frame = self.stack_top;
|
||||||
let new_frame = self.stack.last ().unwrap ();
|
self.stack_top = self.stack.pop ().unwrap ();
|
||||||
self.block_idx = new_frame.block_idx;
|
|
||||||
self.next_pc = new_frame.program_counter;
|
|
||||||
self.register_offset = new_frame.register_offset;
|
|
||||||
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_top;
|
||||||
|
|
||||||
|
|
||||||
self.registers [popped_frame.register_offset - 1] = self.register_window ()[a].clone ();
|
self.registers [popped_frame.register_offset - 1] = self.register_window ()[a].clone ();
|
||||||
|
|
||||||
let frame = self.stack.last ().unwrap ();
|
self.stack_top = self.stack.pop ().unwrap ();
|
||||||
self.block_idx = frame.block_idx;
|
|
||||||
self.next_pc = frame.program_counter;
|
|
||||||
self.register_offset = frame.register_offset;
|
|
||||||
|
|
||||||
// Shift output register down
|
// Shift output register down
|
||||||
let offset = popped_frame.register_offset;
|
let offset = popped_frame.register_offset;
|
||||||
|
@ -901,14 +876,14 @@ impl State {
|
||||||
},
|
},
|
||||||
Instruction::Sub (a, b, c) => {
|
Instruction::Sub (a, b, c) => {
|
||||||
if self.op_sub (a, b, c) {
|
if self.op_sub (a, b, c) {
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
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 = self.register_offset;
|
let offset = self.stack_top.register_offset;
|
||||||
let value = self.registers [offset + a].take ();
|
let value = self.registers [offset + a].take ();
|
||||||
match value {
|
match value {
|
||||||
Value::BogusClosure (closure) => {
|
Value::BogusClosure (closure) => {
|
||||||
|
@ -931,11 +906,9 @@ impl State {
|
||||||
|
|
||||||
// Jump into the other function
|
// Jump into the other function
|
||||||
|
|
||||||
let frame = self.stack.last_mut ().unwrap ();
|
self.stack_top.program_counter = 0;
|
||||||
frame.program_counter = 0;
|
self.stack_top.block_idx = closure.idx;
|
||||||
frame.block_idx = closure.idx;
|
self.stack_top.program_counter = 0;
|
||||||
self.block_idx = closure.idx;
|
|
||||||
self.next_pc = 0;
|
|
||||||
|
|
||||||
// Skip the PC increment
|
// Skip the PC increment
|
||||||
return Ok (None);
|
return Ok (None);
|
||||||
|
@ -947,10 +920,9 @@ impl State {
|
||||||
self.registers [i] = self.registers [i + a + 1].take ();
|
self.registers [i] = self.registers [i + a + 1].take ();
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = self.stack.last_mut ().unwrap ();
|
|
||||||
// Trash the stack frame so it doesn't point
|
// Trash the stack frame so it doesn't point
|
||||||
// to any valid Lua function
|
// to any valid Lua function
|
||||||
*frame = StackFrame {
|
self.stack_top = StackFrame {
|
||||||
block_idx: 65535,
|
block_idx: 65535,
|
||||||
program_counter: 65535,
|
program_counter: 65535,
|
||||||
register_offset: offset,
|
register_offset: offset,
|
||||||
|
@ -965,12 +937,13 @@ impl State {
|
||||||
|
|
||||||
// Call
|
// Call
|
||||||
let num_results = x (self, num_args);
|
let num_results = x (self, num_args);
|
||||||
let popped_frame = self.stack.pop ().unwrap ();
|
|
||||||
|
|
||||||
if let Some (new_frame) = self.stack.last () {
|
// Pop and handle outputs
|
||||||
self.block_idx = new_frame.block_idx;
|
|
||||||
self.next_pc = new_frame.program_counter;
|
let popped_frame = self.stack_top;
|
||||||
self.register_offset = new_frame.register_offset;
|
|
||||||
|
if let Some (new_frame) = self.stack.pop () {
|
||||||
|
self.stack_top = new_frame;
|
||||||
|
|
||||||
// Set up top for the next call
|
// Set up top for the next call
|
||||||
if c == 0 {
|
if c == 0 {
|
||||||
|
@ -983,14 +956,14 @@ impl State {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
dbg! (&self.stack);
|
dbg! (&self.stack, &self.stack_top);
|
||||||
panic! ("OP_TAILCALL argument must be a function");
|
panic! ("OP_TAILCALL argument must be a function");
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::Test (a, k_flag) => {
|
Instruction::Test (a, k_flag) => {
|
||||||
if self.reg (a).is_truthy() != k_flag {
|
if self.reg (a).is_truthy() != k_flag {
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::UnM (a, b) => {
|
Instruction::UnM (a, b) => {
|
||||||
|
@ -1010,12 +983,7 @@ impl State {
|
||||||
Instruction::VarArgPrep (_) => (),
|
Instruction::VarArgPrep (_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.next_pc += 1;
|
self.stack_top.program_counter += 1;
|
||||||
{
|
|
||||||
let frame = self.stack.last_mut ().unwrap ();
|
|
||||||
frame.program_counter = self.next_pc;
|
|
||||||
self.register_offset = frame.register_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok (None)
|
Ok (None)
|
||||||
}
|
}
|
||||||
|
@ -1045,11 +1013,9 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_chunk (&mut self, chunk: Chunk) {
|
pub fn set_chunk (&mut self, chunk: Chunk) {
|
||||||
self.stack = vec! [Default::default ()];
|
self.stack = vec! [];
|
||||||
|
self.stack_top = Default::default ();
|
||||||
self.chunk = chunk;
|
self.chunk = chunk;
|
||||||
self.block_idx = 0;
|
|
||||||
self.next_pc = 0;
|
|
||||||
self.register_offset = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string (&mut self, s: &str) -> Value {
|
pub fn to_string (&mut self, s: &str) -> Value {
|
||||||
|
|
Loading…
Reference in New Issue