use crate::CompilerState;
use leo_ast::{Expression, FromStrRadix, Literal, LiteralVariant, Location, Node, NodeID, const_eval::Value};
use leo_errors::Formatted;
use leo_span::{Span, Symbol};
use indexmap::IndexMap;
pub struct SsaConstPropagationVisitor<'a> {
pub state: &'a mut CompilerState,
pub program: Symbol,
pub constants: IndexMap<Symbol, Value>,
pub atom_fielded_composites: IndexMap<Symbol, IndexMap<Symbol, Expression>>,
pub changed: bool,
}
pub fn is_atom(expr: &Expression) -> bool {
matches!(expr, Expression::Path(_) | Expression::Literal(_))
}
fn parse_literal_value(s: &str) -> Option<i128> {
let clean = s.replace('_', "");
i128::from_str_by_radix(&clean).ok()
}
pub fn is_zero_literal(lit: &Literal) -> bool {
match &lit.variant {
LiteralVariant::Integer(_, s)
| LiteralVariant::Field(s)
| LiteralVariant::Group(s)
| LiteralVariant::Scalar(s)
| LiteralVariant::Unsuffixed(s) => parse_literal_value(s) == Some(0),
LiteralVariant::Boolean(b) => !b,
_ => false,
}
}
pub fn is_one_literal(lit: &Literal) -> bool {
match &lit.variant {
LiteralVariant::Integer(_, s)
| LiteralVariant::Field(s)
| LiteralVariant::Scalar(s)
| LiteralVariant::Unsuffixed(s) => parse_literal_value(s) == Some(1),
LiteralVariant::Boolean(b) => *b,
_ => false,
}
}
pub fn same_ssa_atom(a: &Expression, b: &Expression) -> bool {
match (a, b) {
(Expression::Path(pa), Expression::Path(pb)) => {
let sa = pa.try_local_symbol();
let sb = pb.try_local_symbol();
sa == sb && sa.is_some()
}
_ => false,
}
}
impl SsaConstPropagationVisitor<'_> {
pub fn emit_err(&self, err: Formatted) {
self.state.handler.emit_err(err);
}
pub fn value_to_expression(&mut self, value: &Value, span: Span, id: NodeID) -> Option<(Expression, NodeID)> {
let ty = self.state.type_table.get(&id)?.clone();
let symbol_table = &self.state.symbol_table;
let struct_lookup = |loc: &Location| {
symbol_table
.lookup_struct(self.program, loc)
.unwrap()
.members
.iter()
.map(|mem| (mem.identifier.name, mem.type_.clone()))
.collect()
};
let new_expr = value.to_expression(span, &self.state.node_builder, &ty, &struct_lookup)?;
let new_id = new_expr.id();
self.copy_types_recursively(&new_expr, &ty);
Some((new_expr, new_id))
}
fn copy_types_recursively(&mut self, expr: &Expression, ty: &leo_ast::Type) {
use leo_ast::Type;
self.state.type_table.insert(expr.id(), ty.clone());
match (expr, ty) {
(Expression::Array(array_expr), Type::Array(array_ty)) => {
for element in &array_expr.elements {
self.copy_types_recursively(element, array_ty.element_type());
}
}
(Expression::Tuple(tuple_expr), Type::Tuple(tuple_ty)) => {
for (element, elem_ty) in tuple_expr.elements.iter().zip(tuple_ty.elements()) {
self.copy_types_recursively(element, elem_ty);
}
}
(Expression::Composite(composite_expr), Type::Composite(composite_ty)) => {
let member_types: Vec<leo_ast::Type> = self
.state
.symbol_table
.lookup_struct(self.program, composite_ty.path.expect_global_location())
.map(|struct_def| struct_def.members.iter().map(|m| m.type_.clone()).collect())
.unwrap_or_default();
for (member, member_ty) in composite_expr.members.iter().zip(member_types.iter()) {
if let Some(expr) = &member.expression {
self.copy_types_recursively(expr, member_ty);
}
}
}
_ => {
}
}
}
}