use crate::Destructurer;
use leo_ast::{
AssignStatement,
Block,
ConditionalStatement,
ConsoleStatement,
DefinitionPlace,
DefinitionStatement,
Expression,
ExpressionReconstructor,
Identifier,
IterationStatement,
Node,
ReturnStatement,
Statement,
StatementReconstructor,
TupleExpression,
Type,
};
use itertools::Itertools;
impl StatementReconstructor for Destructurer<'_> {
fn reconstruct_assign(&mut self, _assign: AssignStatement) -> (Statement, Self::AdditionalOutput) {
panic!("`AssignStatement`s should not exist in the AST at this phase of compilation.")
}
fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) {
let mut statements = Vec::with_capacity(block.statements.len());
for statement in block.statements {
let (reconstructed_statement, additional_statements) = self.reconstruct_statement(statement);
statements.extend(additional_statements);
statements.push(reconstructed_statement);
}
(Block { span: block.span, statements, id: self.node_builder.next_id() }, Default::default())
}
fn reconstruct_conditional(&mut self, input: ConditionalStatement) -> (Statement, Self::AdditionalOutput) {
if !self.is_async {
unreachable!("`ConditionalStatement`s should not be in the AST at this phase of compilation.")
} else {
(
Statement::Conditional(ConditionalStatement {
condition: self.reconstruct_expression(input.condition).0,
then: self.reconstruct_block(input.then).0,
otherwise: input.otherwise.map(|n| Box::new(self.reconstruct_statement(*n).0)),
span: input.span,
id: input.id,
}),
Default::default(),
)
}
}
fn reconstruct_console(&mut self, _: ConsoleStatement) -> (Statement, Self::AdditionalOutput) {
panic!("`ConsoleStatement`s should not be in the AST at this phase of compilation.")
}
fn reconstruct_definition(&mut self, definition: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
use DefinitionPlace::*;
let (value, mut statements) = self.reconstruct_expression(definition.value);
let ty = self.type_table.get(&value.id()).expect("Expressions should have a type.");
match (definition.place, value, ty) {
(Single(identifier), Expression::Tuple(tuple), Type::Tuple(..)) => {
self.tuples.insert(identifier.name, tuple);
(Statement::dummy(), statements)
}
(Single(identifier), Expression::Identifier(rhs), Type::Tuple(..)) => {
let tuple_expr = self.tuples.get(&rhs.name).expect("We should have encountered this tuple by now");
self.tuples.insert(identifier.name, tuple_expr.clone());
(Statement::dummy(), statements)
}
(Single(identifier), Expression::Call(rhs), Type::Tuple(tuple_type)) => {
let identifiers: Vec<Identifier> = (0..tuple_type.elements().len())
.map(|i| {
Identifier::new(
self.assigner.unique_symbol(identifier.name, format!("$index${i}$")),
self.node_builder.next_id(),
)
})
.collect();
let expressions: Vec<Expression> = identifiers
.iter()
.zip_eq(tuple_type.elements().iter())
.map(|(identifier, type_)| {
let expr = Expression::Identifier(*identifier);
self.type_table.insert(expr.id(), type_.clone());
expr
})
.collect();
let expr = TupleExpression {
elements: expressions,
span: Default::default(),
id: self.node_builder.next_id(),
};
self.type_table.insert(expr.id(), Type::Tuple(tuple_type));
self.tuples.insert(identifier.name, expr);
let stmt = Statement::Definition(DefinitionStatement {
place: Multiple(identifiers),
type_: Type::Err,
value: Expression::Call(rhs),
span: Default::default(),
id: self.node_builder.next_id(),
});
(stmt, statements)
}
(Multiple(identifiers), Expression::Tuple(tuple), Type::Tuple(..)) => {
for (identifier, expr) in identifiers.into_iter().zip_eq(tuple.elements) {
let stmt = Statement::Definition(DefinitionStatement {
place: Single(identifier),
type_: Type::Err,
value: expr,
span: Default::default(),
id: self.node_builder.next_id(),
});
statements.push(stmt);
}
(Statement::dummy(), statements)
}
(Multiple(identifiers), Expression::Identifier(identifier), Type::Tuple(..)) => {
let tuple = self.tuples.get(&identifier.name).expect("We should have encountered this tuple by now");
for (identifier, expr) in identifiers.into_iter().zip_eq(tuple.elements.iter()) {
let stmt = Statement::Definition(DefinitionStatement {
place: Single(identifier),
type_: Type::Err,
value: expr.clone(),
span: Default::default(),
id: self.node_builder.next_id(),
});
statements.push(stmt);
}
(Statement::dummy(), statements)
}
(m @ Multiple(..), value @ Expression::Call(..), Type::Tuple(..)) => {
let stmt = Statement::Definition(DefinitionStatement {
place: m,
type_: Type::Err,
value,
span: definition.span,
id: definition.id,
});
(stmt, statements)
}
(_, Expression::Ternary(..), Type::Tuple(..)) => {
panic!("Ternary conditionals of tuple type should have been removed by flattening");
}
(_, _, Type::Tuple(..)) => {
panic!("Expressions of tuple type can only be tuple literals, identifiers, or calls.");
}
(Single(identifier), rhs, _) => {
(
Statement::Definition(DefinitionStatement {
place: Single(identifier),
type_: Type::Err,
value: rhs,
span: Default::default(),
id: definition.id,
}),
statements,
)
}
(Multiple(_), _, _) => panic!("A definition with multiple identifiers must have tuple type"),
}
}
fn reconstruct_iteration(&mut self, _: IterationStatement) -> (Statement, Self::AdditionalOutput) {
panic!("`IterationStatement`s should not be in the AST at this phase of compilation.");
}
fn reconstruct_return(&mut self, input: ReturnStatement) -> (Statement, Self::AdditionalOutput) {
let expression = match input.expression {
Expression::Identifier(identifier) if self.tuples.contains_key(&identifier.name) => {
let tuple = self.tuples.get(&identifier.name).unwrap().clone();
Expression::Tuple(tuple)
}
_ => input.expression,
};
(Statement::Return(ReturnStatement { expression, span: input.span, id: input.id }), Default::default())
}
}