use std::collections::BTreeMap;
use crate::hir::common::{
HirCallExpr, HirDecisionTarget, HirExpr, HirLValue, HirStmt, HirTableConstructor,
HirTableField, HirTableKey, LocalId, TempId,
};
pub(super) fn call_expr(call: &mut HirCallExpr, mapping: &BTreeMap<TempId, LocalId>) -> bool {
let callee_changed = expr(&mut call.callee, mapping);
let mut args_changed = false;
for arg in &mut call.args {
args_changed |= expr(arg, mapping);
}
callee_changed || args_changed
}
pub(super) fn expr(node: &mut HirExpr, mapping: &BTreeMap<TempId, LocalId>) -> bool {
match node {
HirExpr::TempRef(temp) => {
if let Some(local) = mapping.get(temp) {
*node = HirExpr::LocalRef(*local);
true
} else {
false
}
}
HirExpr::TableAccess(access) => {
let base_changed = expr(&mut access.base, mapping);
let key_changed = expr(&mut access.key, mapping);
base_changed || key_changed
}
HirExpr::Unary(unary) => expr(&mut unary.expr, mapping),
HirExpr::Binary(binary) => {
let lhs_changed = expr(&mut binary.lhs, mapping);
let rhs_changed = expr(&mut binary.rhs, mapping);
lhs_changed || rhs_changed
}
HirExpr::LogicalAnd(logical) | HirExpr::LogicalOr(logical) => {
let lhs_changed = expr(&mut logical.lhs, mapping);
let rhs_changed = expr(&mut logical.rhs, mapping);
lhs_changed || rhs_changed
}
HirExpr::Decision(decision) => {
let mut changed = false;
for node in &mut decision.nodes {
let test_changed = expr(&mut node.test, mapping);
let truthy_changed = decision_target(&mut node.truthy, mapping);
let falsy_changed = decision_target(&mut node.falsy, mapping);
changed |= test_changed || truthy_changed || falsy_changed;
}
changed
}
HirExpr::Call(call) => call_expr(call, mapping),
HirExpr::TableConstructor(table) => table_constructor(table, mapping),
HirExpr::Closure(closure) => {
let mut changed = false;
for capture in &mut closure.captures {
changed |= expr(&mut capture.value, mapping);
}
changed
}
HirExpr::Nil
| HirExpr::Boolean(_)
| HirExpr::Integer(_)
| HirExpr::Number(_)
| HirExpr::String(_)
| HirExpr::Int64(_)
| HirExpr::UInt64(_)
| HirExpr::Complex { .. }
| HirExpr::ParamRef(_)
| HirExpr::LocalRef(_)
| HirExpr::UpvalueRef(_)
| HirExpr::GlobalRef(_)
| HirExpr::VarArg
| HirExpr::Unresolved(_) => false,
}
}
fn decision_target(target: &mut HirDecisionTarget, mapping: &BTreeMap<TempId, LocalId>) -> bool {
match target {
HirDecisionTarget::Expr(expr) => self::expr(expr, mapping),
HirDecisionTarget::Node(_) | HirDecisionTarget::CurrentValue => false,
}
}
fn table_constructor(table: &mut HirTableConstructor, mapping: &BTreeMap<TempId, LocalId>) -> bool {
let mut fields_changed = false;
for field in &mut table.fields {
let field_changed = match field {
HirTableField::Array(expr) => self::expr(expr, mapping),
HirTableField::Record(field) => {
let key_changed = match &mut field.key {
HirTableKey::Name(_) => false,
HirTableKey::Expr(expr) => self::expr(expr, mapping),
};
let value_changed = self::expr(&mut field.value, mapping);
key_changed || value_changed
}
};
fields_changed |= field_changed;
}
let trailing_changed = table
.trailing_multivalue
.as_mut()
.is_some_and(|expr| self::expr(expr, mapping));
fields_changed || trailing_changed
}
pub(super) fn lvalue(lvalue: &mut HirLValue, mapping: &BTreeMap<TempId, LocalId>) -> bool {
match lvalue {
HirLValue::Temp(temp) => {
if let Some(local) = mapping.get(temp) {
*lvalue = HirLValue::Local(*local);
true
} else {
false
}
}
HirLValue::TableAccess(access) => {
let base_changed = expr(&mut access.base, mapping);
let key_changed = expr(&mut access.key, mapping);
base_changed || key_changed
}
HirLValue::Param(_)
| HirLValue::Local(_)
| HirLValue::Upvalue(_)
| HirLValue::Global(_) => false,
}
}
pub(super) fn forward_capture_refs(stmt: &mut HirStmt, mapping: &BTreeMap<TempId, LocalId>) {
match stmt {
HirStmt::Assign(assign) => {
for expr in &mut assign.values {
closure_capture_temps(expr, mapping);
}
}
HirStmt::LocalDecl(local_decl) => {
for expr in &mut local_decl.values {
closure_capture_temps(expr, mapping);
}
}
_ => {}
}
}
fn closure_capture_temps(expr: &mut HirExpr, mapping: &BTreeMap<TempId, LocalId>) {
if let HirExpr::Closure(closure) = expr {
for capture in &mut closure.captures {
self::expr(&mut capture.value, mapping);
}
}
}