diff --git a/lunar_wave_vm/src/loader.rs b/lunar_wave_vm/src/loader.rs index c831147..4828512 100644 --- a/lunar_wave_vm/src/loader.rs +++ b/lunar_wave_vm/src/loader.rs @@ -160,6 +160,7 @@ pub fn parse_inst (buf: [u8; 4]) -> Option 0x4a => Inst::ForPrep (a, bx), 0x4e => Inst::SetList (a, b, c, k), 0x4f => Inst::Closure (a, bx), + 0x50 => unimplemented! ("OP_VARARG"), 0x51 => Inst::VarArgPrep (a.into ()), 0x52 => Inst::ExtraArg (ax), _ => return None, diff --git a/lunar_wave_vm/src/state.rs b/lunar_wave_vm/src/state.rs index 5fb9de0..9e09e97 100644 --- a/lunar_wave_vm/src/state.rs +++ b/lunar_wave_vm/src/state.rs @@ -82,7 +82,6 @@ fn lw_print (l: &mut State, num_args: usize) -> usize { } } println! (""); - *l.reg_mut (0) = Value::from (1993); 1 } @@ -107,9 +106,39 @@ fn lw_string_format (l: &mut State, num_args: usize) -> usize { 1 } -fn lw_tonumber (l: &mut State, num_args: usize) -> usize { - assert_eq! (num_args, 1, "tonumber only implemented for 1 argument"); - let output = match l.reg (0) { +fn lw_table_concat (l: &mut State, num_args: usize) -> usize { + assert_eq! (num_args, 2); + + let s = { + let t = l.reg (0).as_table ().unwrap ().borrow (); + let joiner = l.reg (1).as_str ().unwrap (); + + let mut s = String::new (); + + for i in 0..t.length () { + if i > 0 { + s.push_str (joiner); + } + let x = t.get_int (i + 1); + s.push_str (&format! ("{}", x)); + } + s + }; + *l.reg_mut (0) = Value::from (s); + 1 +} + +fn lw_table_pack (l: &mut State, num_args: usize) -> usize { + let mut v = vec! []; + for i in 0..num_args { + v.push (l.reg (u8::try_from (i).unwrap ()).clone ()); + } + *l.reg_mut (0) = Value::from_iter (v.into_iter ()); + 1 +} + +fn tonumber (value: &Value) -> Value { + match value { Value::Float (x) => Value::Float (*x), Value::Integer (x) => Value::Integer (*x), Value::String (x) => { @@ -124,7 +153,12 @@ fn lw_tonumber (l: &mut State, num_args: usize) -> usize { } }, _ => Value::Nil, - }; + } +} + +fn lw_tonumber (l: &mut State, num_args: usize) -> usize { + assert_eq! (num_args, 1, "tonumber only implemented for 1 argument"); + let output = tonumber (l.reg (0)); *l.reg_mut (0) = output; 1 } @@ -182,12 +216,18 @@ impl State { ("format", Value::RsFunc (lw_string_format)), ].into_iter ().map (|(k, v)| (k.to_string (), v)); + let table = [ + ("concat", Value::RsFunc (lw_table_concat)), + ("pack", Value::RsFunc (lw_table_pack)), + ].into_iter ().map (|(k, v)| (k.to_string (), v)); + let env = [ ("arg", arg), ("io", Value::from_iter (io.into_iter ())), ("math", Value::from_iter (math.into_iter ())), ("print", Value::RsFunc (lw_print)), ("string", Value::from_iter (string.into_iter ())), + ("table", Value::from_iter (table.into_iter ())), ("tonumber", Value::RsFunc (lw_tonumber)), ].into_iter ().map (|(k, v)| (k.to_string (), v)); @@ -336,7 +376,7 @@ impl State { }); let num_args = if b == 0 { - self.top - a as usize + self.top - new_offset } else { b - 1 @@ -385,7 +425,7 @@ impl State { upvalues: new_upvalues, }); }, - Instruction::Concat (a, b) => { + Instruction::Concat (_a, _b) => { unimplemented! ("OP_CONCAT") }, Instruction::Div (a, b, c) => { diff --git a/lunar_wave_vm/src/tests.rs b/lunar_wave_vm/src/tests.rs index 5fbae5e..137bbdc 100644 --- a/lunar_wave_vm/src/tests.rs +++ b/lunar_wave_vm/src/tests.rs @@ -208,9 +208,30 @@ fn function_calls () { vm.eval ("print (x ())").ok (); vm.eval ("x = function () return 5 end").ok (); + + // Currently failing because I don't have a way to jump into a Lua + // function that's no longer in the currently-executing chunk vm.eval ("print (x ())").ok (); } +#[test] +fn function_returns () { + let upvalues = crate::State::upvalues_from_args (vec! ["_exe_name".to_string ()].into_iter ()); + + let mut vm = crate::State::new (crate::Chunk::default (), upvalues); + + assert_eq! ( + vm.eval ("return ((function () return 5 end)())").unwrap (), + vec! [Value::from (5)] + ); + assert_eq! ( + vm.eval ("return (math.sqrt (25))").unwrap (), + vec! [Value::from (5.0)] + ); + + +} + #[test] fn heap () { use std::{