use super::FlatteningVisitor;
use leo_ast::{
Expression,
ExpressionReconstructor,
Identifier,
Location,
Node,
Statement,
StructExpression,
StructVariableInitializer,
TernaryExpression,
Type,
};
impl ExpressionReconstructor for FlatteningVisitor<'_> {
type AdditionalOutput = Vec<Statement>;
fn reconstruct_struct_init(&mut self, input: StructExpression) -> (Expression, Self::AdditionalOutput) {
let mut statements = Vec::new();
let mut members = Vec::with_capacity(input.members.len());
for member in input.members.into_iter() {
let (expr, stmts) = self.reconstruct_expression(member.expression.unwrap());
statements.extend(stmts);
members.push(StructVariableInitializer {
identifier: member.identifier,
expression: Some(expr),
span: member.span,
id: member.id,
});
}
(StructExpression { members, ..input }.into(), statements)
}
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
let if_true_type = self
.state
.type_table
.get(&input.if_true.id())
.expect("Type checking guarantees that all expressions are typed.");
let if_false_type = self
.state
.type_table
.get(&input.if_false.id())
.expect("Type checking guarantees that all expressions are typed.");
assert!(if_true_type.eq_flat_relaxed(&if_false_type));
fn as_identifier(ident_expr: Expression) -> Identifier {
let Expression::Identifier(identifier) = ident_expr else {
panic!("SSA form should have guaranteed this is an identifier: {}.", ident_expr);
};
identifier
}
match &if_true_type {
Type::Array(if_true_type) => self.ternary_array(
if_true_type,
&input.condition,
&as_identifier(input.if_true),
&as_identifier(input.if_false),
),
Type::Composite(if_true_type) => {
let program = if_true_type.program.unwrap_or(self.program);
let if_true_type = self
.state
.symbol_table
.lookup_struct(if_true_type.id.name)
.or_else(|| self.state.symbol_table.lookup_record(Location::new(program, if_true_type.id.name)))
.expect("This definition should exist")
.clone();
self.ternary_struct(
&if_true_type,
&input.condition,
&as_identifier(input.if_true),
&as_identifier(input.if_false),
)
}
Type::Tuple(if_true_type) => {
self.ternary_tuple(if_true_type, &input.condition, &input.if_true, &input.if_false)
}
_ => {
assert!(matches!(&input.if_true, Expression::Identifier(..)));
assert!(matches!(&input.if_false, Expression::Identifier(..)));
(input.into(), Default::default())
}
}
}
}