use crate::{FunctionInliner, Replacer};
use leo_ast::{
CallExpression,
Expression,
ExpressionReconstructor,
Identifier,
ReturnStatement,
Statement,
StatementReconstructor,
UnitExpression,
Variant,
};
use indexmap::IndexMap;
use itertools::Itertools;
impl ExpressionReconstructor for FunctionInliner<'_> {
type AdditionalOutput = Vec<Statement>;
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
if input.external.is_some() {
return (Expression::Call(input), Default::default());
}
let function_name = match *input.function {
Expression::Identifier(identifier) => identifier.name,
_ => unreachable!("Parser guarantees that `input.function` is always an identifier."),
};
let callee = self.reconstructed_functions.get(&function_name).unwrap();
match callee.variant {
Variant::Transition | Variant::Standard => (Expression::Call(input), Default::default()),
Variant::Inline => {
let parameter_to_argument = callee
.input
.iter()
.map(|input| input.identifier().name)
.zip_eq(input.arguments.into_iter())
.collect::<IndexMap<_, _>>();
self.assignment_renamer
.load(callee.input.iter().map(|input| (input.identifier().name, input.identifier().name)));
let unique_block = self.assignment_renamer.reconstruct_block(callee.block.clone()).0;
self.assignment_renamer.clear();
let replace = |identifier: &Identifier| match parameter_to_argument.get(&identifier.name) {
Some(expression) => expression.clone(),
None => Expression::Identifier(*identifier),
};
let mut inlined_statements = Replacer::new(replace).reconstruct_block(unique_block).0.statements;
let result = match inlined_statements.last() {
Some(Statement::Return(_)) => {
match inlined_statements.pop().unwrap() {
Statement::Return(ReturnStatement { expression, .. }) => expression,
_ => unreachable!("This branch checks that the last statement is a return statement."),
}
}
_ => Expression::Unit(UnitExpression { span: Default::default() }),
};
(result, inlined_statements)
}
}
}
}