diff --git a/.gitignore b/.gitignore index 350f73e..1c04bd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +/luac.out /target /untracked diff --git a/src/main.rs b/src/main.rs index 03d5bef..f0a03d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,14 @@ use std::collections::BTreeMap; +#[derive (Debug)] enum Instruction { - VarArgPrep (i32), + Add (u8, u8, u8), + + Call (u8, u8, u8), + Closure (u8, i32), + + // Equals Constant? + EqK (u8, u8, u8), // Get Table, Upvalue GetTabUp (u8, u8, u8), @@ -9,9 +16,6 @@ enum Instruction { // Get Immediate? GetI (u8, u8, u8), - // Equals Constant? - EqK (u8, u8, u8), - // Jump Jmp (i32), @@ -21,12 +25,15 @@ enum Instruction { // Load Constant LoadK (u8, i32), + // MetaMethod, Binary + MmBin (u8, u8, u8), - Call (u8, u8, u8), - Closure (u8, i32), + Move (u8, u8), // (A, B, _C) Return B - 1 registers starting with A Return (u8, u8, u8), + + VarArgPrep (i32), } #[derive (Clone, Debug, PartialEq)] @@ -35,7 +42,6 @@ enum Value { False, True, Float (f64), - Integer (i64), String (String), // These are all bogus, I haven't figured out how to implement @@ -66,7 +72,22 @@ impl From <&str> for Value { impl From for Value { fn from (x: i32) -> Self { - Self::Integer (x as i64) + Self::Float (f64::try_from (x).unwrap ()) + } +} + +impl From for Value { + fn from (x: f64) -> Self { + Self::Float (x) + } +} + +impl Value { + fn as_float (&self) -> Option { + match self { + Self::Float (x) => Some (*x), + _ => None, + } } } @@ -92,6 +113,20 @@ impl Default for VirtualMachine { } impl VirtualMachine { + fn upvalues_from_args > (args: I) -> Vec + { + let arg = args.map (|s| s.to_string ()).collect (); + + let env = BTreeMap::from_iter ([ + ("arg", Value::BogusArg (arg)), + ("print", Value::BogusPrint), + ].map (|(k, v)| (k.to_string (), v)).into_iter ()); + + vec! [ + Value::BogusEnv (env), + ] + } + fn execute_chunk (&mut self, chunk: &Chunk, upvalues: &Vec ) -> Vec { let max_iters = 2000; @@ -103,6 +138,16 @@ impl VirtualMachine { let k = &chunk.constants; match instruction { + Instruction::Add (a, b, c) => { + let a = usize::try_from (*a).unwrap (); + let b = usize::try_from (*b).unwrap (); + let c = usize::try_from (*c).unwrap (); + + let v_b = r [b].as_float ().unwrap (); + let v_c = r [c].as_float ().unwrap (); + + r [a] = (v_b + v_c).into (); + }, Instruction::Call (a, b, c) => { // Take arguments from registers [a + 1, a + b) // Call the function in register [a] @@ -112,14 +157,15 @@ impl VirtualMachine { // // e.g. CALL 0 2 1 mean "Call 0 with 1 argument, return 1 value", like for printing a constant - // TODO: Only implement printing constants for now + // TODO: Only implement printing values for now let a = usize::try_from (*a).unwrap (); + assert_eq! (r.get (a).unwrap (), &Value::BogusPrint); assert_eq! (*b, 2); assert_eq! (*c, 1); - println! ("{:?}", r [a + 1]); + println! ("{:?}", r.get (a + 1).unwrap ()); }, Instruction::EqK (a, b, c_k) => { let a = usize::try_from (*a).unwrap (); @@ -178,6 +224,26 @@ impl VirtualMachine { r [a] = k [bx].clone (); }, + Instruction::MmBin (a, b, c) => { + let a = usize::try_from (*a).unwrap (); + let b = usize::try_from (*b).unwrap (); + + let a = &r [a]; + let b = &r [b]; + + if a.as_float().is_some() && b.as_float().is_some () { + // No need for metamethods + } + else { + panic! ("Not sure how to implememtn OP_MMBIN for these 2 values {a:?}, {b:?}"); + } + }, + Instruction::Move (a, b) => { + let a = usize::try_from (*a).unwrap (); + let b = usize::try_from (*b).unwrap (); + + r [a] = r [b].clone (); + }, Instruction::Return (a, b, _c) => { let a = usize::try_from (*a).unwrap (); let b = usize::try_from (*b).unwrap (); @@ -185,7 +251,7 @@ impl VirtualMachine { return self.registers [a..(a + b - 1)].to_vec(); }, Instruction::VarArgPrep (_) => (), - _ => (), + x => panic! ("Unimplemented instruction {x:?}"), } self.program_counter += 1; @@ -196,45 +262,26 @@ impl VirtualMachine { } fn main() { - let arg: Vec <_> = std::env::args ().collect (); - let chunk = Chunk { instructions: vec! [ Instruction::VarArgPrep (0), - Instruction::GetTabUp (1, 0, 0), - Instruction::GetI (1, 1, 1), - Instruction::EqK (1, 1, 0), - Instruction::Jmp (6), - Instruction::GetTabUp (1, 0, 2), - Instruction::LoadK (2, 3), - Instruction::Call (1, 2, 1), - Instruction::LoadI (1, 0), - Instruction::Return (1, 2, 1), - Instruction::Jmp (5), - Instruction::GetTabUp (1, 0, 2), - Instruction::LoadK (2, 4), - Instruction::Call (1, 2, 1), - Instruction::LoadI (1, 1), - Instruction::Return (1, 2, 1), - Instruction::Return (1, 1, 1), + Instruction::LoadK (0, 0), + Instruction::LoadI (1, 3), + Instruction::Add (2, 0, 1), + Instruction::MmBin (0, 1, 6), + Instruction::GetTabUp (3, 0, 1), + Instruction::Move (4, 2), + Instruction::Call (3, 2, 1), + Instruction::Return (2, 2, 1), + Instruction::Return (3, 1, 1), ], constants: vec! [ - "arg", - "93", - "print", - "it's 93", - "it's not 93", - ].into_iter ().map (|s| Value::from (s)).collect (), + 0.5.into (), + "print".into (), + ], }; - let env = BTreeMap::from_iter ([ - ("arg", Value::BogusArg (arg.clone ())), - ("print", Value::BogusPrint), - ].map (|(k, v)| (k.to_string (), v)).into_iter ()); - - let upvalues = vec! [ - Value::BogusEnv (env), - ]; + let upvalues = VirtualMachine::upvalues_from_args (std::env::args ()); let mut vm = VirtualMachine::default (); println! ("Returned: {:?}", vm.execute_chunk (&chunk, &upvalues)); @@ -244,6 +291,48 @@ fn main() { mod tests { use super::*; + #[test] + fn floats () { + /* + local a = 0.5 + local b = 3 + + local x = a + b + + print (x) + return x + */ + + let chunk = Chunk { + instructions: vec! [ + Instruction::VarArgPrep (0), + Instruction::LoadK (0, 0), + Instruction::LoadI (1, 3), + Instruction::Add (2, 0, 1), + Instruction::MmBin (0, 1, 6), + Instruction::GetTabUp (3, 0, 1), + Instruction::Move (4, 2), + Instruction::Call (3, 2, 1), + Instruction::Return (2, 2, 1), + Instruction::Return (3, 1, 1), + ], + constants: vec! [ + 0.5.into (), + "print".into (), + ], + }; + + for (arg, expected) in [ + (vec! ["_exe_name"], vec! [3.5.into ()]), + ] { + let mut vm = VirtualMachine::default (); + let upvalues = VirtualMachine::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); + let actual = vm.execute_chunk (&chunk, &upvalues); + + assert_eq! (actual, expected); + } + } + #[test] fn is_93 () { /* @@ -290,18 +379,8 @@ mod tests { (vec! ["_exe_name", "93"], vec! [0.into ()]), (vec! ["_exe_name", "94"], vec! [1.into ()]), ] { - let arg = arg.into_iter ().map (|s| s.to_string ()).collect (); - - let env = BTreeMap::from_iter ([ - ("arg", Value::BogusArg (arg)), - ("print", Value::BogusPrint), - ].map (|(k, v)| (k.to_string (), v)).into_iter ()); - - let upvalues = vec! [ - Value::BogusEnv (env), - ]; - let mut vm = VirtualMachine::default (); + let upvalues = VirtualMachine::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let actual = vm.execute_chunk (&chunk, &upvalues); assert_eq! (actual, expected); diff --git a/test_vectors/floats.lua b/test_vectors/floats.lua new file mode 100644 index 0000000..00b67e9 --- /dev/null +++ b/test_vectors/floats.lua @@ -0,0 +1,7 @@ +local a = 0.5 +local b = 3 + +local x = a + b + +print (x) +return x