Add varargs

This commit is contained in:
Sofia 2026-03-18 19:33:41 +02:00
parent b0fc0a1dce
commit a0108b4fd4
4 changed files with 52 additions and 17 deletions

View File

@ -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))

View File

@ -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<Constant>,
pub prototypes: Vec<Vec<Instruction>>,
pub prototypes: Vec<Prototype>,
}
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));

View File

@ -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());
}

View File

@ -512,16 +512,22 @@ impl<T: RustFunction + 'static> From<T> for Value {
}
}
#[derive(Debug, Clone, Default)]
pub struct Prototype {
pub instructions: Vec<Instruction>,
pub parameters: usize,
}
#[derive(Debug, Clone, Default)]
pub struct VirtualMachine {
pub(super) environment: Rc<RefCell<Environment>>,
pub(super) constants: Vec<Constant>,
pub(super) prototypes: HashMap<u32, Vec<Instruction>>,
pub(super) prototypes: HashMap<u32, Prototype>,
pub(super) proto_counter: u32,
}
impl VirtualMachine {
pub fn new_prototype(&mut self, instructions: Vec<Instruction>) -> 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()));
}
}