leo_passes/const_propagation/
const_propagate_statement.rsuse crate::ConstPropagator;
use leo_ast::{
AssertStatement,
AssertVariant,
AssignStatement,
Block,
ConditionalStatement,
ConsoleStatement,
ConstDeclaration,
DeclarationType,
DefinitionStatement,
Expression,
ExpressionReconstructor,
ExpressionStatement,
IterationStatement,
Node,
ReturnStatement,
Statement,
StatementReconstructor,
};
fn empty_statement() -> Statement {
Statement::Block(Block { statements: Vec::new(), span: Default::default(), id: Default::default() })
}
fn is_empty_statement(stmt: &Statement) -> bool {
let Statement::Block(block) = stmt else {
return false;
};
block.statements.is_empty()
}
impl StatementReconstructor for ConstPropagator<'_> {
fn reconstruct_assert(&mut self, mut input: AssertStatement) -> (Statement, Self::AdditionalOutput) {
input.variant = match input.variant {
AssertVariant::Assert(expr) => AssertVariant::Assert(self.reconstruct_expression(expr).0),
AssertVariant::AssertEq(lhs, rhs) => {
AssertVariant::AssertEq(self.reconstruct_expression(lhs).0, self.reconstruct_expression(rhs).0)
}
AssertVariant::AssertNeq(lhs, rhs) => {
AssertVariant::AssertNeq(self.reconstruct_expression(lhs).0, self.reconstruct_expression(rhs).0)
}
};
(Statement::Assert(input), None)
}
fn reconstruct_assign(&mut self, mut assign: AssignStatement) -> (Statement, Self::AdditionalOutput) {
assign.value = self.reconstruct_expression(assign.value).0;
(Statement::Assign(Box::new(assign)), None)
}
fn reconstruct_block(&mut self, mut block: Block) -> (Block, Self::AdditionalOutput) {
self.in_scope(block.id(), |slf| {
block.statements.retain_mut(|statement| {
let bogus_statement = empty_statement();
let this_statement = std::mem::replace(statement, bogus_statement);
*statement = slf.reconstruct_statement(this_statement).0;
!is_empty_statement(statement)
});
(block, None)
})
}
fn reconstruct_conditional(
&mut self,
mut conditional: ConditionalStatement,
) -> (Statement, Self::AdditionalOutput) {
conditional.condition = self.reconstruct_expression(conditional.condition).0;
conditional.then = self.reconstruct_block(conditional.then).0;
if let Some(mut otherwise) = conditional.otherwise {
*otherwise = self.reconstruct_statement(*otherwise).0;
conditional.otherwise = Some(otherwise);
}
(Statement::Conditional(conditional), None)
}
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_const(&mut self, mut input: ConstDeclaration) -> (Statement, Self::AdditionalOutput) {
let span = input.span();
let (expr, opt_value) = self.reconstruct_expression(input.value);
if opt_value.is_some() {
self.symbol_table.insert_const(self.program, input.place.name, expr.clone());
} else {
self.const_not_evaluated = Some(span);
}
input.value = expr;
(Statement::Const(input), None)
}
fn reconstruct_definition(&mut self, mut definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
let span = definition.span();
let (expr, opt_value) = self.reconstruct_expression(definition.value);
if definition.declaration_type == DeclarationType::Const {
if opt_value.is_some() {
let Expression::Identifier(id) = &definition.place else {
panic!("Const definitions always have identifiers as the place.");
};
self.symbol_table.insert_const(self.program, id.name, expr.clone());
} else {
self.const_not_evaluated = Some(span);
}
}
definition.value = expr;
(Statement::Definition(definition), None)
}
fn reconstruct_expression_statement(
&mut self,
mut input: ExpressionStatement,
) -> (Statement, Self::AdditionalOutput) {
input.expression = self.reconstruct_expression(input.expression).0;
if matches!(&input.expression, Expression::Unit(..) | Expression::Literal(..)) {
(empty_statement(), Default::default())
} else {
(Statement::Expression(input), Default::default())
}
}
fn reconstruct_iteration(&mut self, mut iteration: IterationStatement) -> (Statement, Self::AdditionalOutput) {
iteration.start = self.reconstruct_expression(iteration.start).0;
iteration.stop = self.reconstruct_expression(iteration.stop).0;
self.in_scope(iteration.id(), |slf| {
iteration.block = slf.reconstruct_block(iteration.block).0;
(Statement::Iteration(Box::new(iteration)), None)
})
}
fn reconstruct_return(&mut self, mut input: ReturnStatement) -> (Statement, Self::AdditionalOutput) {
input.expression = self.reconstruct_expression(input.expression).0;
(Statement::Return(input), Default::default())
}
}