diff --git a/examples/test.lua b/examples/test.lua index 6945ecb..3d52d95 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -17,7 +17,7 @@ function min(x, y) end function f(x) - return x + 5 + return x + 5, add(10)(15) end global sometable = {} @@ -33,4 +33,5 @@ print(b) print(min(11, 9)) print(10 - 15) print("hello there!") -print(true or 0) \ No newline at end of file +print(true or 0) +print(f(10)) \ No newline at end of file diff --git a/src/compile.rs b/src/compile.rs index 5d7c797..a7a7a12 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -566,18 +566,23 @@ impl Expression { let mut param_scope = scope.clone(); let mut original_param_regs = Vec::new(); - for param in params.kind.0.iter() { + let mut vararg = false; + for (i, param) in params.kind.0.iter().enumerate() { let (instr, registers) = param.kind.compile( state, &mut param_scope, - if params.kind.0.len() == 1 { + if i == params.kind.0.len() - 1 { None } else { Some(1) }, ); instructions.extend(instr); - original_param_regs.extend(registers); + if registers.len() > 0 { + original_param_regs.push(*registers.first().unwrap()); + } else { + vararg = true; + } } let mut registers = scope @@ -600,6 +605,11 @@ impl Expression { instructions.push(Instruction::Move(function_reg, *old_function_reg)); } + if vararg { + let last_reg = param_regs.last().unwrap_or(&function_reg) + 1; + instructions.push(Instruction::MoveRetValues(last_reg)); + } + let last_param_reg = param_regs.last().unwrap_or(&function_reg); let mut return_regs = Vec::new(); @@ -616,7 +626,7 @@ impl Expression { instructions.push(Instruction::Call( *&function_reg, - param_regs.len() as u16, + if vararg { 0 } else { param_regs.len() as u16 }, if return_regs.len() == 0 { 0 } else { diff --git a/src/vm.rs b/src/vm.rs index 1670185..cd437ba 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -110,6 +110,8 @@ impl Debug for Constant { pub enum Instruction { /// R(A) := R(B) Move(u16, u16), + /// R(A) ... R(A + func_register - top) := previous function return values + MoveRetValues(u16), /// R(A) := K(Bx) LoadK(u16, u32), /// R(A), ..., R(B) := nil @@ -165,6 +167,7 @@ impl Debug for Instruction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Instruction::Move(arg0, arg1) => write!(f, "MOVE {} {}", arg0, arg1), + Instruction::MoveRetValues(arg0) => write!(f, "MOVERETVALS {}", arg0), Instruction::LoadK(arg0, arg1) => write!(f, "LOADK {} {}", arg0, arg1), Instruction::SetGlobal(arg0, arg1) => write!(f, "SETGLOBAL {} {}", arg0, arg1), Instruction::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1), @@ -708,6 +711,20 @@ impl ClosureRunner { let b = self.get_stack(*b); self.set_stack(*a, b); } + Instruction::MoveRetValues(res) => { + let length = self.top - self.function_register; + + let mut values = Vec::new(); + for i in 0..length { + let b = self.get_stack(self.function_register + i + 1); + values.push(b); + } + for (i, val) in values.into_iter().enumerate() { + self.set_stack(*res + i as u16, val); + } + + self.top = *res + length; + } Instruction::LoadK(reg, constant) => { self.set_stack( *reg, @@ -868,14 +885,10 @@ impl ClosureRunner { } } Instruction::Call(func_reg, param_len, ret_len) => { - let param_start_func_reg = if *param_len == 0 { - self.function_register - } else { - *func_reg - }; + let param_start_func_reg = *func_reg; let param_len = if *param_len == 0 { - self.top - self.top.min(param_start_func_reg) + self.top - self.top.min(param_start_func_reg + 1) } else { *param_len };