diff --git a/src/compile.rs b/src/compile.rs index 2f1ca3a..1ba8b5d 100644 --- a/src/compile.rs +++ b/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, + params: Node, + state: &mut State, + scope: &mut Scope, + expected_values: Option, +) -> (Vec, Vec) { + 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) +}