Move function call compilation to own function
This commit is contained in:
parent
11f4e4e8a3
commit
2e853f29b4
178
src/compile.rs
178
src/compile.rs
@ -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)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user