use crate::{Assigner, RenameTable};
use leo_ast::{
AssignStatement,
ConditionalStatement,
ConsoleStatement,
DefinitionStatement,
Expression,
ExpressionReconstructor,
Identifier,
IterationStatement,
ProgramReconstructor,
Statement,
StatementReconstructor,
StructExpression,
StructVariableInitializer,
};
use leo_span::Symbol;
pub struct AssignmentRenamer<'a> {
pub assigner: &'a Assigner,
pub rename_table: RenameTable,
pub is_lhs: bool,
}
impl<'a> AssignmentRenamer<'a> {
pub fn new(assigner: &'a Assigner) -> Self {
Self { assigner, rename_table: RenameTable::new(None), is_lhs: false }
}
pub fn load(&mut self, entries: impl Iterator<Item = (Symbol, Symbol)>) {
for (key, value) in entries {
self.rename_table.update(key, value);
}
}
pub fn clear(&mut self) {
self.rename_table = RenameTable::new(None);
}
}
impl ExpressionReconstructor for AssignmentRenamer<'_> {
type AdditionalOutput = ();
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
let name = match self.is_lhs {
true => {
let new_name = self.assigner.unique_symbol(input.name, "$");
self.rename_table.update(input.name, new_name);
new_name
}
false => *self.rename_table.lookup(input.name).unwrap_or(&input.name),
};
(Expression::Identifier(Identifier { name, span: input.span, id: input.id }), Default::default())
}
fn reconstruct_struct_init(&mut self, input: StructExpression) -> (Expression, Self::AdditionalOutput) {
(
Expression::Struct(StructExpression {
name: input.name,
members: input
.members
.into_iter()
.map(|member| StructVariableInitializer {
identifier: member.identifier,
expression: match member.expression {
Some(expression) => Some(self.reconstruct_expression(expression).0),
None => unreachable!(
"SSA guarantees that all struct members are always of the form `<id> : <expr>`."
),
},
span: member.span,
id: member.id,
})
.collect(),
span: input.span,
id: input.id,
}),
Default::default(),
)
}
}
impl StatementReconstructor for AssignmentRenamer<'_> {
fn reconstruct_assign(&mut self, input: AssignStatement) -> (Statement, Self::AdditionalOutput) {
let value = self.reconstruct_expression(input.value).0;
self.is_lhs = true;
let place = self.reconstruct_expression(input.place).0;
self.is_lhs = false;
(
Statement::Assign(Box::new(AssignStatement { place, value, span: input.span, id: input.id })),
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_iteration(&mut self, _: IterationStatement) -> (Statement, Self::AdditionalOutput) {
unreachable!("`IterationStatement`s should not be in the AST at this phase of compilation.");
}
}
impl ProgramReconstructor for AssignmentRenamer<'_> {}