use crate::DeadCodeEliminator;
use leo_ast::{
AccessExpression,
AssertStatement,
AssertVariant,
AssignStatement,
Block,
ConditionalStatement,
ConsoleStatement,
DefinitionStatement,
Expression,
ExpressionReconstructor,
ExpressionStatement,
IterationStatement,
ReturnStatement,
Statement,
StatementReconstructor,
};
impl StatementReconstructor for DeadCodeEliminator {
fn reconstruct_assert(&mut self, input: AssertStatement) -> (Statement, Self::AdditionalOutput) {
self.is_necessary = true;
let statement = Statement::Assert(AssertStatement {
variant: match input.variant {
AssertVariant::Assert(expr) => AssertVariant::Assert(self.reconstruct_expression(expr).0),
AssertVariant::AssertEq(left, right) => {
AssertVariant::AssertEq(self.reconstruct_expression(left).0, self.reconstruct_expression(right).0)
}
AssertVariant::AssertNeq(left, right) => {
AssertVariant::AssertNeq(self.reconstruct_expression(left).0, self.reconstruct_expression(right).0)
}
},
span: input.span,
});
self.is_necessary = false;
(statement, Default::default())
}
fn reconstruct_assign(&mut self, input: AssignStatement) -> (Statement, Self::AdditionalOutput) {
let lhs_is_used = match &input.place {
Expression::Identifier(identifier) => self.used_variables.contains(&identifier.name),
Expression::Tuple(tuple_expression) => tuple_expression
.elements
.iter()
.map(|element| match element {
Expression::Identifier(identifier) => identifier.name,
_ => unreachable!(
"The previous compiler passes guarantee the tuple elements on the lhs are identifiers."
),
})
.any(|symbol| self.used_variables.contains(&symbol)),
_ => unreachable!(
"The previous compiler passes guarantee that `place` is either an identifier or tuple of identifiers."
),
};
match lhs_is_used {
true => {
self.is_necessary = true;
let statement = Statement::Assign(Box::new(AssignStatement {
place: input.place,
value: self.reconstruct_expression(input.value).0,
span: input.span,
}));
self.is_necessary = false;
(statement, Default::default())
}
false => (Statement::dummy(Default::default()), Default::default()),
}
}
fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) {
let mut statements: Vec<Statement> =
block.statements.into_iter().rev().map(|statement| self.reconstruct_statement(statement).0).collect();
statements.reverse();
(Block { statements, span: block.span }, Default::default())
}
fn reconstruct_conditional(&mut self, _: ConditionalStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`ConditionalStatement`s should not be in the AST at this phase of compilation.")
}
fn reconstruct_console(&mut self, _: ConsoleStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`ConsoleStatement`s should not be in the AST at this phase of compilation.")
}
fn reconstruct_definition(&mut self, _: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`DefinitionStatement`s should not exist in the AST at this phase of compilation.")
}
fn reconstruct_expression_statement(&mut self, input: ExpressionStatement) -> (Statement, Self::AdditionalOutput) {
match input.expression {
Expression::Call(expression) => {
self.is_necessary = true;
let statement = Statement::Expression(ExpressionStatement {
expression: self.reconstruct_call(expression).0,
span: input.span,
});
self.is_necessary = false;
(statement, Default::default())
}
Expression::Access(AccessExpression::AssociatedFunction(associated_function)) => {
(
Statement::Expression(ExpressionStatement {
expression: self
.reconstruct_access(AccessExpression::AssociatedFunction(associated_function))
.0,
span: input.span,
}),
Default::default(),
)
}
_ => (Statement::dummy(Default::default()), Default::default()),
}
}
fn reconstruct_iteration(&mut self, _: IterationStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`IterationStatement`s should not be in the AST at this phase of compilation.");
}
fn reconstruct_return(&mut self, input: ReturnStatement) -> (Statement, Self::AdditionalOutput) {
self.is_necessary = true;
let statement = Statement::Return(ReturnStatement {
expression: self.reconstruct_expression(input.expression).0,
finalize_arguments: input.finalize_arguments.map(|arguments| {
arguments.into_iter().map(|argument| self.reconstruct_expression(argument).0).collect()
}),
span: input.span,
});
self.is_necessary = false;
(statement, Default::default())
}
}