Add varargs
This commit is contained in:
parent
b0fc0a1dce
commit
a0108b4fd4
@ -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))
|
||||
print(123, f(10, 11, 12))
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
30
src/vm.rs
30
src/vm.rs
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user