use itertools::Itertools;
use leo_ast::*;
use leo_span::{Span, Symbol};
use crate::{unroller::Unroller, VariableSymbol, VariableType};
impl StatementReconstructor for Unroller<'_> {
fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
let scope_index = self.current_scope_index();
let previous_scope_index = self.enter_scope(scope_index);
let block = Block {
statements: input.statements.into_iter().map(|s| self.reconstruct_statement(s).0).collect(),
span: input.span,
};
self.exit_scope(previous_scope_index);
(block, Default::default())
}
fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
if self.is_unrolling {
let declaration =
if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut };
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
if let Err(err) =
self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration })
{
self.handler.emit_err(err);
}
};
match &input.place {
Expression::Identifier(identifier) => {
insert_variable(identifier.name, input.type_.clone(), identifier.span, declaration)
}
Expression::Tuple(tuple_expression) => {
let tuple_type = match input.type_ {
Type::Tuple(ref tuple_type) => tuple_type,
_ => unreachable!(
"Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple."
),
};
tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| {
let identifier = match expression {
Expression::Identifier(identifier) => identifier,
_ => unreachable!("Type checking guarantees that if the lhs is a tuple, all of its elements are identifiers.")
};
insert_variable(identifier.name, type_.clone(), identifier.span, declaration)
});
}
_ => unreachable!(
"Type checking guarantees that the lhs of a `DefinitionStatement` is either an identifier or tuple."
),
}
}
(Statement::Definition(input), Default::default())
}
fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
match (input.start_value.clone().into_inner(), input.stop_value.clone().into_inner()) {
(Some(start), Some(stop)) => match (Type::from(&start), Type::from(&stop)) {
(Type::Integer(IntegerType::I8), Type::Integer(IntegerType::I8))
| (Type::Integer(IntegerType::I16), Type::Integer(IntegerType::I16))
| (Type::Integer(IntegerType::I32), Type::Integer(IntegerType::I32))
| (Type::Integer(IntegerType::I64), Type::Integer(IntegerType::I64))
| (Type::Integer(IntegerType::I128), Type::Integer(IntegerType::I128)) => {
(self.unroll_iteration_statement::<i128>(input, start, stop), Default::default())
}
(Type::Integer(IntegerType::U8), Type::Integer(IntegerType::U8))
| (Type::Integer(IntegerType::U16), Type::Integer(IntegerType::U16))
| (Type::Integer(IntegerType::U32), Type::Integer(IntegerType::U32))
| (Type::Integer(IntegerType::U64), Type::Integer(IntegerType::U64))
| (Type::Integer(IntegerType::U128), Type::Integer(IntegerType::U128)) => {
(self.unroll_iteration_statement::<u128>(input, start, stop), Default::default())
}
_ => unreachable!("Type checking ensures that `start` and `stop` have the same type."),
},
_ => (Statement::Iteration(Box::from(input)), Default::default()),
}
}
}