♻️ refactor: extract a single step method for State
parent
f0d4f25cec
commit
a9e14d0f47
|
@ -57,14 +57,16 @@ fn main () {
|
||||||
dbg! (&chunk);
|
dbg! (&chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = State::default ();
|
let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args));
|
||||||
|
|
||||||
|
let mut vm = State::new (&chunk, &upvalues);
|
||||||
if std::env::var("LUA_DEBUG").is_ok() {
|
if std::env::var("LUA_DEBUG").is_ok() {
|
||||||
vm.debug_print = true;
|
vm.debug_print = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args));
|
|
||||||
|
|
||||||
vm.breakpoints = breakpoints;
|
vm.breakpoints = breakpoints;
|
||||||
|
|
||||||
vm.execute_chunk (&chunk, &upvalues);
|
vm.execute_chunk ();
|
||||||
}
|
}
|
||||||
|
|
80
src/state.rs
80
src/state.rs
|
@ -47,7 +47,7 @@ pub struct Breakpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Debug)]
|
#[derive (Debug)]
|
||||||
pub struct State {
|
pub struct State <'a> {
|
||||||
registers: Vec <Value>,
|
registers: Vec <Value>,
|
||||||
// Currently only used for native function calls
|
// Currently only used for native function calls
|
||||||
top: usize,
|
top: usize,
|
||||||
|
@ -56,25 +56,8 @@ pub struct State {
|
||||||
pub debug_print: bool,
|
pub debug_print: bool,
|
||||||
pub breakpoints: Vec <Breakpoint>,
|
pub breakpoints: Vec <Breakpoint>,
|
||||||
step_count: u32,
|
step_count: u32,
|
||||||
}
|
chunk: &'a Chunk,
|
||||||
|
upvalues: &'a [Value],
|
||||||
impl Default for State {
|
|
||||||
fn default () -> Self {
|
|
||||||
Self {
|
|
||||||
registers: vec! [Value::Nil; 16],
|
|
||||||
top: 0,
|
|
||||||
stack: vec! [
|
|
||||||
StackFrame {
|
|
||||||
program_counter: 0,
|
|
||||||
block_idx: 0,
|
|
||||||
register_offset: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
debug_print: false,
|
|
||||||
breakpoints: Default::default(),
|
|
||||||
step_count: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lw_print (l: &mut State) -> i32 {
|
fn lw_print (l: &mut State) -> i32 {
|
||||||
|
@ -93,7 +76,30 @@ fn lw_print (l: &mut State) -> i32 {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
pub enum StepOutput {
|
||||||
|
ChunkReturned (Vec <Value>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a> State <'a> {
|
||||||
|
pub fn new (chunk: &'a Chunk, upvalues: &'a [Value]) -> Self {
|
||||||
|
Self {
|
||||||
|
registers: vec! [Value::Nil; 16],
|
||||||
|
top: 0,
|
||||||
|
stack: vec! [
|
||||||
|
StackFrame {
|
||||||
|
program_counter: 0,
|
||||||
|
block_idx: 0,
|
||||||
|
register_offset: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
debug_print: false,
|
||||||
|
breakpoints: Default::default(),
|
||||||
|
step_count: 0,
|
||||||
|
chunk,
|
||||||
|
upvalues,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn upvalues_from_args <I: Iterator <Item = String>> (args: I) -> Vec <Value>
|
pub fn upvalues_from_args <I: Iterator <Item = String>> (args: I) -> Vec <Value>
|
||||||
{
|
{
|
||||||
let arg = args.map (|s| Value::from (s)).enumerate ();
|
let arg = args.map (|s| Value::from (s)).enumerate ();
|
||||||
|
@ -131,11 +137,8 @@ impl State {
|
||||||
self.top - self.stack.last ().unwrap ().register_offset
|
self.top - self.stack.last ().unwrap ().register_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_chunk (&mut self, chunk: &Chunk, upvalues: &[Value])
|
pub fn step (&mut self) -> Option <StepOutput> {
|
||||||
-> Vec <Value> {
|
let chunk = self.chunk;
|
||||||
let max_iters = 2000;
|
|
||||||
|
|
||||||
for _ in 0..max_iters {
|
|
||||||
self.step_count += 1;
|
self.step_count += 1;
|
||||||
|
|
||||||
let frame = self.stack.last_mut ().unwrap ().clone ();
|
let frame = self.stack.last_mut ().unwrap ().clone ();
|
||||||
|
@ -217,7 +220,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the PC increment at the bottom of the loop
|
// Skip the PC increment at the bottom of the loop
|
||||||
continue;
|
return None;
|
||||||
},
|
},
|
||||||
Value::RsFunc (x) => {
|
Value::RsFunc (x) => {
|
||||||
let current_frame = self.stack.last ().unwrap ();
|
let current_frame = self.stack.last ().unwrap ();
|
||||||
|
@ -260,7 +263,7 @@ impl State {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: This isn't really correct
|
// TODO: This isn't really correct
|
||||||
upvalues [usize::from (uv.idx)].clone ()
|
self.upvalues [usize::from (uv.idx)].clone ()
|
||||||
};
|
};
|
||||||
new_upvalues.push (val);
|
new_upvalues.push (val);
|
||||||
}
|
}
|
||||||
|
@ -346,7 +349,7 @@ impl State {
|
||||||
|
|
||||||
let frame = self.stack.last ().unwrap ();
|
let frame = self.stack.last ().unwrap ();
|
||||||
let value = if frame.register_offset == 0 {
|
let value = if frame.register_offset == 0 {
|
||||||
upvalues.get (b).unwrap ().clone ()
|
self.upvalues.get (b).unwrap ().clone ()
|
||||||
}
|
}
|
||||||
else if let Some (cell) = self.registers [frame.register_offset - 1].as_closure ()
|
else if let Some (cell) = self.registers [frame.register_offset - 1].as_closure ()
|
||||||
{
|
{
|
||||||
|
@ -355,7 +358,7 @@ impl State {
|
||||||
value.clone ()
|
value.clone ()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
upvalues.get (b).unwrap ().clone ()
|
self.upvalues.get (b).unwrap ().clone ()
|
||||||
};
|
};
|
||||||
|
|
||||||
let table = value.as_table ().expect ("GetTabUp only works on tables").borrow ();
|
let table = value.as_table ().expect ("GetTabUp only works on tables").borrow ();
|
||||||
|
@ -520,7 +523,7 @@ impl State {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Return from the entire program
|
// Return from the entire program
|
||||||
return self.registers [a..(a + b - 1)].to_vec();
|
return Some (StepOutput::ChunkReturned (self.registers [a..(a + b - 1)].to_vec()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Instruction::Return0 => {
|
Instruction::Return0 => {
|
||||||
|
@ -628,7 +631,7 @@ impl State {
|
||||||
frame.block_idx = closure.idx;
|
frame.block_idx = closure.idx;
|
||||||
|
|
||||||
// Skip the PC increment
|
// Skip the PC increment
|
||||||
continue;
|
return None;
|
||||||
},
|
},
|
||||||
Instruction::Test (a, _k) => {
|
Instruction::Test (a, _k) => {
|
||||||
if self.reg (*a).is_truthy() {
|
if self.reg (*a).is_truthy() {
|
||||||
|
@ -643,6 +646,19 @@ impl State {
|
||||||
let frame = self.stack.last_mut ().unwrap ();
|
let frame = self.stack.last_mut ().unwrap ();
|
||||||
frame.program_counter = next_pc;
|
frame.program_counter = next_pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_chunk (&mut self)
|
||||||
|
-> Vec <Value> {
|
||||||
|
let max_iters = 2000;
|
||||||
|
|
||||||
|
for _ in 0..max_iters {
|
||||||
|
match self.step () {
|
||||||
|
None => (),
|
||||||
|
Some (StepOutput::ChunkReturned (x)) => return x,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg! (self);
|
dbg! (self);
|
||||||
|
|
17
src/tests.rs
17
src/tests.rs
|
@ -23,9 +23,9 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
|
||||||
/// 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 mut vm = State::default ();
|
|
||||||
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 ()));
|
||||||
vm.execute_chunk (chunk, &upvalues)
|
let mut vm = State::new (chunk, &upvalues);
|
||||||
|
vm.execute_chunk ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes arguments and Lua bytecode, loads it, runs it,
|
/// Takes arguments and Lua bytecode, loads it, runs it,
|
||||||
|
@ -118,10 +118,9 @@ fn bools () {
|
||||||
] {
|
] {
|
||||||
let expected: Vec <Value> = expected;
|
let expected: Vec <Value> = expected;
|
||||||
|
|
||||||
let mut vm = State::default ();
|
|
||||||
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 actual = vm.execute_chunk (&chunk, &upvalues);
|
let actual = vm.execute_chunk ();
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,9 +174,9 @@ fn floats () {
|
||||||
(vec! ["_exe_name", " "], vec! [3.5.into ()]),
|
(vec! ["_exe_name", " "], vec! [3.5.into ()]),
|
||||||
] {
|
] {
|
||||||
let expected: Vec <Value> = expected;
|
let expected: Vec <Value> = expected;
|
||||||
let mut vm = State::default ();
|
|
||||||
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 actual = vm.execute_chunk (&chunk, &upvalues);
|
let mut vm = State::new (&chunk, &upvalues);
|
||||||
|
let actual = vm.execute_chunk ();
|
||||||
|
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
}
|
}
|
||||||
|
@ -197,9 +196,9 @@ fn fma () {
|
||||||
(vec! ["_exe_name"], vec! [122.into ()]),
|
(vec! ["_exe_name"], vec! [122.into ()]),
|
||||||
] {
|
] {
|
||||||
let expected: Vec <Value> = expected;
|
let expected: Vec <Value> = expected;
|
||||||
let mut vm = State::default ();
|
|
||||||
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 actual = vm.execute_chunk (&chunk, &upvalues);
|
let mut vm = State::new (&chunk, &upvalues);
|
||||||
|
let actual = vm.execute_chunk ();
|
||||||
|
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue