mod cse;
mod dce;
mod guards;
mod hoisting;
mod i128;
mod identity;
mod increment;
mod struct_mutation;
pub use cse::eliminate_common_subexprs;
pub use dce::eliminate_dead_vars;
pub use guards::{fold_constant_guards, normalize_comparisons};
pub use hoisting::hoist_scoped_bindings;
pub use i128::collapse_i128_patterns;
pub use identity::{eliminate_identity_bindings, inline_single_use_bindings, split_client_calls};
pub use increment::reconstruct_increment_pattern;
pub use struct_mutation::reconstruct_struct_mutation;
use std::collections::HashMap;
use crate::ir::{Expr, MethodCall, Statement};
pub(super) fn rename_stmt_vars(stmt: Statement, renames: &HashMap<String, String>) -> Statement {
match stmt {
Statement::Let { name, mutable, value } => Statement::Let {
name,
mutable,
value: rename_expr_vars(&value, renames),
},
Statement::Assign { target, value } => Statement::Assign {
target: rename_expr_vars(&target, renames),
value: rename_expr_vars(&value, renames),
},
Statement::Expr(e) => Statement::Expr(rename_expr_vars(&e, renames)),
Statement::Return(Some(e)) => Statement::Return(Some(rename_expr_vars(&e, renames))),
Statement::Return(None) => Statement::Return(None),
Statement::If { condition, then_body, else_body } => Statement::If {
condition: rename_expr_vars(&condition, renames),
then_body: then_body.into_iter().map(|s| rename_stmt_vars(s, renames)).collect(),
else_body: else_body.into_iter().map(|s| rename_stmt_vars(s, renames)).collect(),
},
Statement::While { condition, body } => Statement::While {
condition: rename_expr_vars(&condition, renames),
body: body.into_iter().map(|s| rename_stmt_vars(s, renames)).collect(),
},
Statement::Loop { body } => Statement::Loop {
body: body.into_iter().map(|s| rename_stmt_vars(s, renames)).collect(),
},
Statement::ForEach { var_name, collection, body } => Statement::ForEach {
var_name,
collection: rename_expr_vars(&collection, renames),
body: body.into_iter().map(|s| rename_stmt_vars(s, renames)).collect(),
},
Statement::ForRange { var_name, bound, body } => Statement::ForRange {
var_name,
bound: rename_expr_vars(&bound, renames),
body: body.into_iter().map(|s| rename_stmt_vars(s, renames)).collect(),
},
}
}
pub(super) fn rename_expr_vars(expr: &Expr, renames: &HashMap<String, String>) -> Expr {
match expr {
Expr::Var(name) => {
let (prefix, bare) = if let Some(stripped) = name.strip_prefix('&') {
("&", stripped)
} else {
("", name.as_str())
};
if let Some(new_name) = renames.get(bare) {
Expr::Var(format!("{}{}", prefix, new_name))
} else if let Some(dot_pos) = bare.find('.') {
let base = &bare[..dot_pos];
let suffix = &bare[dot_pos..]; if let Some(new_base) = renames.get(base) {
Expr::Var(format!("{}{}{}", prefix, new_base, suffix))
} else {
expr.clone()
}
} else {
expr.clone()
}
}
Expr::BinOp { left, op, right } => Expr::BinOp {
left: Box::new(rename_expr_vars(left, renames)),
op: *op,
right: Box::new(rename_expr_vars(right, renames)),
},
Expr::UnOp { op, operand } => Expr::UnOp {
op: *op,
operand: Box::new(rename_expr_vars(operand, renames)),
},
Expr::MethodChain { receiver, calls } => Expr::MethodChain {
receiver: Box::new(rename_expr_vars(receiver, renames)),
calls: calls.iter().map(|c| MethodCall {
name: c.name.clone(),
args: c.args.iter().map(|a| rename_expr_vars(a, renames)).collect(),
}).collect(),
},
Expr::HostCall { module, name, args } => Expr::HostCall {
module: module.clone(),
name: name.clone(),
args: args.iter().map(|a| rename_expr_vars(a, renames)).collect(),
},
Expr::MacroCall { name, args } => Expr::MacroCall {
name: name.clone(),
args: args.iter().map(|a| rename_expr_vars(a, renames)).collect(),
},
Expr::StructLiteral { name, fields } => Expr::StructLiteral {
name: name.clone(),
fields: fields.iter().map(|(k, v)| (k.clone(), rename_expr_vars(v, renames))).collect(),
},
Expr::EnumVariant { enum_name, variant_name, fields } => Expr::EnumVariant {
enum_name: enum_name.clone(),
variant_name: variant_name.clone(),
fields: fields.iter().map(|f| rename_expr_vars(f, renames)).collect(),
},
Expr::Ref(inner) => Expr::Ref(Box::new(rename_expr_vars(inner, renames))),
Expr::Literal(_) | Expr::Raw(_) => expr.clone(),
}
}
pub(super) fn expr_has_side_effects(expr: &Expr) -> bool {
match expr {
Expr::MethodChain { calls, .. } => {
if let Some(last) = calls.last() {
let read_only = matches!(last.name.as_str(),
"has" | "get" | "sequence" | "timestamp"
| "current_contract_address" | "ledger"
| "storage" | "persistent" | "instance" | "temporary"
| "len" | "cmp" | "keys" | "values"
| "unwrap_or_default" | "unwrap"
);
!read_only
} else {
true
}
}
Expr::HostCall { name, .. } => {
!matches!(name.as_str(), "new" | "from_str")
}
Expr::Ref(inner) => expr_has_side_effects(inner),
_ => false,
}
}
pub(super) fn collect_expr_var_names(expr: &Expr, names: &mut std::collections::BTreeSet<String>) {
match expr {
Expr::Var(name) => {
let bare = name.strip_prefix('&').unwrap_or(name);
names.insert(bare.to_string());
}
Expr::BinOp { left, right, .. } => {
collect_expr_var_names(left, names);
collect_expr_var_names(right, names);
}
Expr::UnOp { operand, .. } => collect_expr_var_names(operand, names),
Expr::Ref(inner) => collect_expr_var_names(inner, names),
Expr::MethodChain { receiver, calls } => {
collect_expr_var_names(receiver, names);
for call in calls {
for arg in &call.args { collect_expr_var_names(arg, names); }
}
}
Expr::HostCall { args, .. } | Expr::MacroCall { args, .. } => {
for arg in args { collect_expr_var_names(arg, names); }
}
Expr::StructLiteral { fields, .. } => {
for (_, val) in fields { collect_expr_var_names(val, names); }
}
Expr::EnumVariant { fields, .. } => {
for f in fields { collect_expr_var_names(f, names); }
}
Expr::Literal(_) | Expr::Raw(_) => {}
}
}