use super::SsaFormingVisitor;
use leo_ast::{
ArrayAccess,
ArrayExpression,
AssociatedFunctionExpression,
BinaryExpression,
CallExpression,
CastExpression,
Composite,
Expression,
ExpressionConsumer,
Identifier,
Literal,
Location,
LocatorExpression,
MemberAccess,
Statement,
StructExpression,
StructVariableInitializer,
TernaryExpression,
TupleAccess,
TupleExpression,
UnaryExpression,
UnitExpression,
};
use leo_span::{Symbol, sym};
use indexmap::IndexMap;
impl SsaFormingVisitor<'_> {
pub fn consume_expression_and_define(&mut self, input: Expression) -> (Expression, Vec<Statement>) {
let (expr, mut statements) = self.consume_expression(input);
if matches!(expr, Expression::Identifier(..) | Expression::Unit(..) | Expression::Err(..)) {
(expr, statements)
} else {
let (place, statement) = self.unique_simple_definition(expr);
statements.push(statement);
(place.into(), statements)
}
}
}
impl ExpressionConsumer for SsaFormingVisitor<'_> {
type Output = (Expression, Vec<Statement>);
fn consume_array_access(&mut self, input: ArrayAccess) -> Self::Output {
let (array, statements) = self.consume_expression_and_define(input.array);
(ArrayAccess { array, ..input }.into(), statements)
}
fn consume_member_access(&mut self, input: MemberAccess) -> Self::Output {
if let Expression::Identifier(Identifier { name, .. }) = input.inner {
if name == sym::SelfLower {
return (input.into(), Vec::new());
}
}
let (inner, statements) = self.consume_expression_and_define(input.inner);
(MemberAccess { inner, ..input }.into(), statements)
}
fn consume_tuple_access(&mut self, input: TupleAccess) -> Self::Output {
let (tuple, statements) = self.consume_expression_and_define(input.tuple);
(TupleAccess { tuple, ..input }.into(), statements)
}
fn consume_array(&mut self, input: ArrayExpression) -> Self::Output {
let mut statements = Vec::new();
let elements = input
.elements
.into_iter()
.map(|element| {
let (element, mut stmts) = self.consume_expression_and_define(element);
statements.append(&mut stmts);
element
})
.collect();
(ArrayExpression { elements, ..input }.into(), statements)
}
fn consume_binary(&mut self, input: BinaryExpression) -> Self::Output {
let (left, mut statements) = self.consume_expression_and_define(input.left);
let (right, mut right_statements) = self.consume_expression_and_define(input.right);
statements.append(&mut right_statements);
(BinaryExpression { left, right, ..input }.into(), statements)
}
fn consume_call(&mut self, input: CallExpression) -> Self::Output {
let mut statements = Vec::new();
let arguments = input
.arguments
.into_iter()
.map(|argument| {
let (argument, mut stmts) = self.consume_expression_and_define(argument);
statements.append(&mut stmts);
argument
})
.collect();
(
CallExpression {
arguments,
..input
}
.into(),
statements,
)
}
fn consume_cast(&mut self, input: CastExpression) -> Self::Output {
let (expression, statements) = self.consume_expression_and_define(input.expression);
(CastExpression { expression, ..input }.into(), statements)
}
fn consume_struct_init(&mut self, input: StructExpression) -> Self::Output {
let mut statements = Vec::new();
let members: Vec<StructVariableInitializer> = input
.members
.into_iter()
.map(|arg| {
let (expression, mut stmts) = if let Some(expr) = arg.expression {
self.consume_expression_and_define(expr)
} else {
self.consume_identifier(arg.identifier)
};
statements.append(&mut stmts);
StructVariableInitializer { expression: Some(expression), ..arg }
})
.collect();
let struct_definition: &Composite = self
.state
.symbol_table
.lookup_record(Location::new(self.program, input.name.name))
.or_else(|| self.state.symbol_table.lookup_struct(input.name.name))
.expect("Type checking guarantees this definition exists.");
let mut reordered_members = Vec::with_capacity(members.len());
let mut member_map: IndexMap<Symbol, StructVariableInitializer> =
members.into_iter().map(|member| (member.identifier.name, member)).collect();
if struct_definition.is_record {
reordered_members.push(member_map.shift_remove(&sym::owner).unwrap());
}
for member in &struct_definition.members {
if !(struct_definition.is_record && matches!(member.identifier.name, sym::owner)) {
reordered_members.push(member_map.shift_remove(&member.identifier.name).unwrap());
}
}
(StructExpression { members: reordered_members, ..input }.into(), statements)
}
fn consume_identifier(&mut self, identifier: Identifier) -> Self::Output {
let name = *self.rename_table.lookup(identifier.name).unwrap_or(&identifier.name);
(Identifier { name, ..identifier }.into(), Default::default())
}
fn consume_literal(&mut self, input: Literal) -> Self::Output {
(input.into(), Default::default())
}
fn consume_locator(&mut self, input: LocatorExpression) -> Self::Output {
(input.into(), Vec::new())
}
fn consume_ternary(&mut self, input: TernaryExpression) -> Self::Output {
let (cond_expr, mut statements) = self.consume_expression_and_define(input.condition);
let (if_true_expr, if_true_statements) = self.consume_expression_and_define(input.if_true);
let (if_false_expr, if_false_statements) = self.consume_expression_and_define(input.if_false);
statements.extend(if_true_statements);
statements.extend(if_false_statements);
(
TernaryExpression { condition: cond_expr, if_true: if_true_expr, if_false: if_false_expr, ..input }.into(),
statements,
)
}
fn consume_tuple(&mut self, input: TupleExpression) -> Self::Output {
let mut statements = Vec::new();
let elements = input
.elements
.into_iter()
.map(|element| {
let (element, mut stmts) = self.consume_expression_and_define(element);
statements.append(&mut stmts);
element
})
.collect();
(TupleExpression { elements, ..input }.into(), statements)
}
fn consume_unary(&mut self, input: UnaryExpression) -> Self::Output {
let (receiver, statements) = self.consume_expression_and_define(input.receiver);
(UnaryExpression { receiver, ..input }.into(), statements)
}
fn consume_unit(&mut self, input: UnitExpression) -> Self::Output {
(input.into(), Default::default())
}
fn consume_associated_constant(&mut self, input: leo_ast::AssociatedConstantExpression) -> Self::Output {
(input.into(), Default::default())
}
fn consume_associated_function(&mut self, input: leo_ast::AssociatedFunctionExpression) -> Self::Output {
let mut statements = Vec::new();
let expr = AssociatedFunctionExpression {
arguments: input
.arguments
.into_iter()
.map(|arg| {
let (arg, mut stmts) = self.consume_expression_and_define(arg);
statements.append(&mut stmts);
arg
})
.collect(),
..input
}
.into();
(expr, statements)
}
}