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::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
AccessModifier, BinaryOperator, Block, Expression, IdentOrEllipsis, Literal, Statement,
|
AccessModifier, BinaryOperator, Block, Expression, ExpressionList, IdentOrEllipsis,
|
||||||
UnaryOperator,
|
Literal, Node, Statement, UnaryOperator,
|
||||||
},
|
},
|
||||||
vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype},
|
vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype},
|
||||||
};
|
};
|
||||||
@ -786,88 +786,7 @@ impl Expression {
|
|||||||
(instructions, vec![local])
|
(instructions, vec![local])
|
||||||
}
|
}
|
||||||
Expression::FunctionCall(expr, params) => {
|
Expression::FunctionCall(expr, params) => {
|
||||||
let mut instructions = Vec::new();
|
compile_function_call(*expr.clone(), params.clone(), state, scope, expected_values)
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
Expression::Literal(literal) => {
|
Expression::Literal(literal) => {
|
||||||
let mut instructions = Vec::new();
|
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