Move function call compilation to own function

This commit is contained in:
Sofia 2026-03-19 22:43:51 +02:00
parent 11f4e4e8a3
commit 2e853f29b4

View File

@ -2,8 +2,8 @@ use std::collections::{HashMap, HashSet};
use crate::{
ast::{
AccessModifier, BinaryOperator, Block, Expression, IdentOrEllipsis, Literal, Statement,
UnaryOperator,
AccessModifier, BinaryOperator, Block, Expression, ExpressionList, IdentOrEllipsis,
Literal, Node, Statement, UnaryOperator,
},
vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype},
};
@ -786,88 +786,7 @@ impl Expression {
(instructions, vec![local])
}
Expression::FunctionCall(expr, params) => {
let mut instructions = Vec::new();
let (instr, registers) = expr.kind.compile(state, scope, Some(1));
instructions.extend(instr);
let old_function_reg = registers.first().unwrap();
let mut registers = scope
.register_counter
.consecutive(params.kind.0.len() + 1)
.into_iter();
let mut param_scope = scope.clone();
let mut original_param_regs = Vec::new();
let mut vararg = false;
for (i, param) in params.kind.0.iter().enumerate() {
let (instr, registers) = param.kind.compile(
state,
&mut param_scope,
if i == params.kind.0.len() - 1 {
None
} else {
Some(1)
},
);
instructions.extend(instr);
if registers.len() > 0 {
original_param_regs.push(*registers.first().unwrap());
} else {
vararg = true;
}
}
let function_reg = registers.next().unwrap();
let mut param_regs = Vec::new();
for _ in &original_param_regs {
param_regs.push(registers.next().unwrap());
}
for (i, param_reg) in original_param_regs.iter().enumerate().rev() {
let new_reg = param_regs.get(i).unwrap();
if param_reg != new_reg {
instructions.push(PreInstr::Instr(Instruction::Move(*new_reg, *param_reg)));
}
}
if function_reg != *old_function_reg {
instructions.push(PreInstr::Instr(Instruction::Move(
function_reg,
*old_function_reg,
)));
}
if vararg {
let last_reg = param_regs.last().unwrap_or(&function_reg) + 1;
instructions.push(PreInstr::Instr(Instruction::MoveRetValues(last_reg)));
}
let last_param_reg = param_regs.last().unwrap_or(&function_reg);
let mut return_regs = Vec::new();
if let Some(expected_values) = expected_values {
for i in 0..expected_values {
let return_reg = i as u16 + function_reg;
if return_reg > *last_param_reg {
return_regs.push(scope.register_counter.next());
} else {
return_regs.push(return_reg);
}
}
}
instructions.push(PreInstr::Instr(Instruction::Call(
*&function_reg,
if vararg { 0 } else { param_regs.len() as u16 },
if return_regs.len() == 0 {
0
} else {
return_regs.len() as u16 + 1
},
)));
(instructions, return_regs)
compile_function_call(*expr.clone(), params.clone(), state, scope, expected_values)
}
Expression::Literal(literal) => {
let mut instructions = Vec::new();
@ -967,3 +886,94 @@ impl Expression {
}
}
}
fn compile_function_call(
expr: Node<Expression>,
params: Node<ExpressionList>,
state: &mut State,
scope: &mut Scope,
expected_values: Option<usize>,
) -> (Vec<PreInstr>, Vec<u16>) {
let mut instructions = Vec::new();
let (instr, registers) = expr.kind.compile(state, scope, Some(1));
instructions.extend(instr);
let old_function_reg = registers.first().unwrap();
let mut registers = scope
.register_counter
.consecutive(params.kind.0.len() + 1)
.into_iter();
let mut param_scope = scope.clone();
let mut original_param_regs = Vec::new();
let mut vararg = false;
for (i, param) in params.kind.0.iter().enumerate() {
let (instr, registers) = param.kind.compile(
state,
&mut param_scope,
if i == params.kind.0.len() - 1 {
None
} else {
Some(1)
},
);
instructions.extend(instr);
if registers.len() > 0 {
original_param_regs.push(*registers.first().unwrap());
} else {
vararg = true;
}
}
let function_reg = registers.next().unwrap();
let mut param_regs = Vec::new();
for _ in &original_param_regs {
param_regs.push(registers.next().unwrap());
}
for (i, param_reg) in original_param_regs.iter().enumerate().rev() {
let new_reg = param_regs.get(i).unwrap();
if param_reg != new_reg {
instructions.push(PreInstr::Instr(Instruction::Move(*new_reg, *param_reg)));
}
}
if function_reg != *old_function_reg {
instructions.push(PreInstr::Instr(Instruction::Move(
function_reg,
*old_function_reg,
)));
}
if vararg {
let last_reg = param_regs.last().unwrap_or(&function_reg) + 1;
instructions.push(PreInstr::Instr(Instruction::MoveRetValues(last_reg)));
}
let last_param_reg = param_regs.last().unwrap_or(&function_reg);
let mut return_regs = Vec::new();
if let Some(expected_values) = expected_values {
for i in 0..expected_values {
let return_reg = i as u16 + function_reg;
if return_reg > *last_param_reg {
return_regs.push(scope.register_counter.next());
} else {
return_regs.push(return_reg);
}
}
}
instructions.push(PreInstr::Instr(Instruction::Call(
*&function_reg,
if vararg { 0 } else { param_regs.len() as u16 },
if return_regs.len() == 0 {
0
} else {
return_regs.len() as u16 + 1
},
)));
(instructions, return_regs)
}