diff --git a/examples/test.lua b/examples/test.lua index 5200a0e..4bf4084 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1,6 +1,7 @@ function f(x, ...) - return x + 5, ... + local b, c = ... + return x + 5, b, c end -print(123, f(10, 11, 12)) \ No newline at end of file +print(123, f(10, 11, 12)) diff --git a/src/compile.rs b/src/compile.rs index 63258be..7be1ede 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -5,13 +5,13 @@ use crate::{ AccessModifier, BinaryOperator, Block, Expression, IdentOrEllipsis, Literal, Statement, UnaryOperator, }, - vm::{Constant, Instruction, LuaBool, LuaInteger}, + vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype}, }; #[derive(Clone, Debug)] pub struct State { pub constants: Vec, - pub prototypes: Vec>, + pub prototypes: Vec, } impl State { @@ -178,11 +178,19 @@ impl Statement { match access_modifier { Some(AccessModifier::Local) => { + let mut vararg_applied = false; for (i, (name, indexes)) in names.iter().enumerate() { - instructions.push(Instruction::Move( - *new_registers.get(i).unwrap(), - expr_regs.get(i).cloned().unwrap(), - )); + if let Some(expr_reg) = expr_regs.get(i) { + instructions.push(Instruction::Move( + *new_registers.get(i).unwrap(), + *expr_reg, + )); + } else if !vararg_applied { + instructions.push(Instruction::MoveRetValues( + *new_registers.get(i).unwrap(), + )); + vararg_applied = true; + } if indexes.len() > 0 { todo!() } @@ -559,7 +567,14 @@ impl Expression { } let instructions = block.compile(state, &mut inner_scope); - state.prototypes.push(instructions); + state.prototypes.push(Prototype { + instructions, + parameters: if inner_scope.is_vararg { + params.len() - 1 + } else { + params.len() + }, + }); let mut instructions = Vec::new(); instructions.push(Instruction::Close(scope.register_counter.0)); diff --git a/src/lib.rs b/src/lib.rs index ade9cc6..403156a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,10 @@ impl Debug for CompilationUnit { impl CompilationUnit { pub fn with_virtual_machine<'a>(&self, vm: &'a mut VirtualMachine) -> ExecutionUnit<'a> { - let chunk_id = vm.new_prototype(self.instructions.clone()); + let chunk_id = vm.new_prototype(vm::Prototype { + instructions: self.instructions.clone(), + parameters: 0, + }); for prototype in &self.state.prototypes { vm.new_prototype(prototype.clone()); } diff --git a/src/vm.rs b/src/vm.rs index f743aa2..f44167f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -512,16 +512,22 @@ impl From for Value { } } +#[derive(Debug, Clone, Default)] +pub struct Prototype { + pub instructions: Vec, + pub parameters: usize, +} + #[derive(Debug, Clone, Default)] pub struct VirtualMachine { pub(super) environment: Rc>, pub(super) constants: Vec, - pub(super) prototypes: HashMap>, + pub(super) prototypes: HashMap, pub(super) proto_counter: u32, } impl VirtualMachine { - pub fn new_prototype(&mut self, instructions: Vec) -> u32 { + pub fn new_prototype(&mut self, instructions: Prototype) -> u32 { let proto_id = self.proto_counter; self.proto_counter += 1; self.prototypes.insert(proto_id, instructions); @@ -656,7 +662,10 @@ impl ClosureRunner { pub fn execute(&mut self, unit: &CompilationUnit) -> ClosureRunner { let mut vm = self.closure.vm.clone(); vm.constants = unit.constants.clone(); - let proto_id = vm.new_prototype(unit.instructions.clone()); + let proto_id = vm.new_prototype(Prototype { + instructions: unit.instructions.clone(), + parameters: 0, + }); for prototype in &unit.state.prototypes { vm.new_prototype(prototype.clone()); } @@ -701,7 +710,7 @@ impl ClosureRunner { } } - let instructions = self + let prototype = self .closure .vm .prototypes @@ -710,7 +719,7 @@ impl ClosureRunner { .clone(); let constants = self.closure.vm.constants.clone(); - if let Some(instr) = instructions.get(self.program_counter) { + if let Some(instr) = prototype.instructions.get(self.program_counter) { match instr { Instruction::Move(a, b) => { let b = self.get_stack(*b); @@ -1090,9 +1099,16 @@ impl ClosureRunner { } Instruction::Vararg(reg) => { self.function_register = reg - 1; - self.top = self.function_register + self.parameters.len() as u16; + self.top = self.function_register + self.parameters.len() as u16 + - prototype.parameters as u16; - for (i, param) in self.parameters.clone().iter().enumerate() { + for (i, param) in self + .parameters + .clone() + .iter() + .skip(prototype.parameters) + .enumerate() + { self.set_stack(*reg + i as u16, StackValue::Value(param.clone())); } }