diff --git a/src/instruction.rs b/src/instruction.rs index ed5b22d..6a4502c 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -10,6 +10,10 @@ pub enum Instruction { ExtraArg (u32), + ForLoop (u8, u32), + + ForPrep (u8, u32), + GetField (u8, u8, u8), // Get Immediate? diff --git a/src/loader.rs b/src/loader.rs index d3c09aa..3d53bde 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -88,6 +88,8 @@ pub fn parse_inst (buf: [u8; 4]) -> Option 0x46 => Inst::Return (a, b, c, k), 0x47 => Inst::Return0, 0x48 => Inst::Return1 (a), + 0x49 => Inst::ForLoop (a, bx), + 0x4a => Inst::ForPrep (a, bx), 0x4e => Inst::SetList (a, b, c, k), 0x4f => Inst::Closure (a, bx), 0x51 => Inst::VarArgPrep (a.into ()), diff --git a/src/main.rs b/src/main.rs index b3be927..bcac3d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +// cargo run -- --script test_vectors/fizz_buzz.lua + mod instruction; mod loader; mod state; @@ -9,8 +11,21 @@ mod tests; fn main () { use state::State; + let mut script = String::from ("test_vectors/hello.lua"); + + let mut args = std::env::args (); + let exe_name = args.next ().unwrap (); + + while let Some (arg) = args.next () { + match arg.as_str () { + "--script" => script = args.next ().unwrap (), + "--" => break, + _ => panic! ("can't parse args"), + } + } + let lua_file = { - let source = std::fs::read ("test_vectors/hello.lua").expect ("couldn't load Lua source code"); + let source = std::fs::read (script).expect ("couldn't load Lua source code"); let bytecode = loader::compile_bytecode(source); let mut rdr = std::io::Cursor::new (bytecode); loader::parse_chunk (&mut rdr).unwrap () @@ -21,7 +36,7 @@ fn main () { vm.debug_print = true; } - let upvalues = State::upvalues_from_args (std::env::args ()); + let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args)); vm.breakpoints.push (state::Breakpoint { block_idx: 3, diff --git a/src/state.rs b/src/state.rs index 722810b..ad234ac 100644 --- a/src/state.rs +++ b/src/state.rs @@ -214,6 +214,27 @@ impl State { assert_eq! (*ax, 0, "implemented only for ax == 0"); }, + Instruction::ForLoop (a, bx) => { + let mut iter = self.reg (*a + 3).as_int ().unwrap (); + iter += 1; + *self.reg_mut (*a + 3) = iter.into (); + + let stop = self.reg (*a + 1).as_int ().unwrap (); + + if iter <= stop { + 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 (); + + if start > stop { + next_pc += i32::try_from (*bx).unwrap () + 1; + } + + *self.reg_mut (*a + 3) = start.into (); + }, Instruction::GetField (a, b, c) => { let t = match self.reg (*b) { Value::Table (t) => t, diff --git a/src/value.rs b/src/value.rs index 4547065..ad2b8b7 100644 --- a/src/value.rs +++ b/src/value.rs @@ -146,6 +146,13 @@ impl Value { } } + pub fn as_int (&self) -> Option { + match self { + Self::Integer (x) => Some (*x), + _ => None, + } + } + pub fn as_table (&self) -> Option <&Rc >> { match self { Self::Table (t) => Some (t), diff --git a/test_vectors/fizz_buzz.lua b/test_vectors/fizz_buzz.lua new file mode 100644 index 0000000..2ec0f58 --- /dev/null +++ b/test_vectors/fizz_buzz.lua @@ -0,0 +1,3 @@ +for i = 1, 50 do + print (i) +end