Add varargs
This commit is contained in:
parent
b0fc0a1dce
commit
a0108b4fd4
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
function f(x, ...)
|
function f(x, ...)
|
||||||
return x + 5, ...
|
local b, c = ...
|
||||||
|
return x + 5, b, c
|
||||||
end
|
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,
|
AccessModifier, BinaryOperator, Block, Expression, IdentOrEllipsis, Literal, Statement,
|
||||||
UnaryOperator,
|
UnaryOperator,
|
||||||
},
|
},
|
||||||
vm::{Constant, Instruction, LuaBool, LuaInteger},
|
vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub constants: Vec<Constant>,
|
pub constants: Vec<Constant>,
|
||||||
pub prototypes: Vec<Vec<Instruction>>,
|
pub prototypes: Vec<Prototype>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@ -178,11 +178,19 @@ impl Statement {
|
|||||||
|
|
||||||
match access_modifier {
|
match access_modifier {
|
||||||
Some(AccessModifier::Local) => {
|
Some(AccessModifier::Local) => {
|
||||||
|
let mut vararg_applied = false;
|
||||||
for (i, (name, indexes)) in names.iter().enumerate() {
|
for (i, (name, indexes)) in names.iter().enumerate() {
|
||||||
instructions.push(Instruction::Move(
|
if let Some(expr_reg) = expr_regs.get(i) {
|
||||||
*new_registers.get(i).unwrap(),
|
instructions.push(Instruction::Move(
|
||||||
expr_regs.get(i).cloned().unwrap(),
|
*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 {
|
if indexes.len() > 0 {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@ -559,7 +567,14 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let instructions = block.compile(state, &mut inner_scope);
|
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();
|
let mut instructions = Vec::new();
|
||||||
instructions.push(Instruction::Close(scope.register_counter.0));
|
instructions.push(Instruction::Close(scope.register_counter.0));
|
||||||
|
|||||||
@ -70,7 +70,10 @@ impl Debug for CompilationUnit {
|
|||||||
|
|
||||||
impl CompilationUnit {
|
impl CompilationUnit {
|
||||||
pub fn with_virtual_machine<'a>(&self, vm: &'a mut VirtualMachine) -> ExecutionUnit<'a> {
|
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 {
|
for prototype in &self.state.prototypes {
|
||||||
vm.new_prototype(prototype.clone());
|
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)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct VirtualMachine {
|
pub struct VirtualMachine {
|
||||||
pub(super) environment: Rc<RefCell<Environment>>,
|
pub(super) environment: Rc<RefCell<Environment>>,
|
||||||
pub(super) constants: Vec<Constant>,
|
pub(super) constants: Vec<Constant>,
|
||||||
pub(super) prototypes: HashMap<u32, Vec<Instruction>>,
|
pub(super) prototypes: HashMap<u32, Prototype>,
|
||||||
pub(super) proto_counter: u32,
|
pub(super) proto_counter: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualMachine {
|
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;
|
let proto_id = self.proto_counter;
|
||||||
self.proto_counter += 1;
|
self.proto_counter += 1;
|
||||||
self.prototypes.insert(proto_id, instructions);
|
self.prototypes.insert(proto_id, instructions);
|
||||||
@ -656,7 +662,10 @@ impl ClosureRunner {
|
|||||||
pub fn execute(&mut self, unit: &CompilationUnit) -> ClosureRunner {
|
pub fn execute(&mut self, unit: &CompilationUnit) -> ClosureRunner {
|
||||||
let mut vm = self.closure.vm.clone();
|
let mut vm = self.closure.vm.clone();
|
||||||
vm.constants = unit.constants.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 {
|
for prototype in &unit.state.prototypes {
|
||||||
vm.new_prototype(prototype.clone());
|
vm.new_prototype(prototype.clone());
|
||||||
}
|
}
|
||||||
@ -701,7 +710,7 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let instructions = self
|
let prototype = self
|
||||||
.closure
|
.closure
|
||||||
.vm
|
.vm
|
||||||
.prototypes
|
.prototypes
|
||||||
@ -710,7 +719,7 @@ impl ClosureRunner {
|
|||||||
.clone();
|
.clone();
|
||||||
let constants = self.closure.vm.constants.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 {
|
match instr {
|
||||||
Instruction::Move(a, b) => {
|
Instruction::Move(a, b) => {
|
||||||
let b = self.get_stack(*b);
|
let b = self.get_stack(*b);
|
||||||
@ -1090,9 +1099,16 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
Instruction::Vararg(reg) => {
|
Instruction::Vararg(reg) => {
|
||||||
self.function_register = reg - 1;
|
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()));
|
self.set_stack(*reg + i as u16, StackValue::Value(param.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user