use crate::HashMap;
use crate::ir::expression::ProtoExpression;
use crate::ir::statement::{ProtoForBound, ProtoForRange, ProtoStatement};
use crate::ir::variable::VarOffset;
pub type FutureReads = HashMap<VarOffset, Vec<usize>>;
pub fn compute_read_positions(stmts: &[ProtoStatement]) -> FutureReads {
let mut reads: FutureReads = HashMap::default();
for (i, s) in stmts.iter().enumerate() {
walk_stmt(s, i, &mut reads);
}
reads
}
fn walk_stmt(s: &ProtoStatement, idx: usize, reads: &mut FutureReads) {
match s {
ProtoStatement::Assign(a) => {
walk_expr(&a.expr, idx, reads);
if let Some(dyn_sel) = &a.dynamic_select {
walk_expr(&dyn_sel.index_expr, idx, reads);
}
}
ProtoStatement::AssignDynamic(a) => {
walk_expr(&a.dst_index_expr, idx, reads);
walk_expr(&a.expr, idx, reads);
if let Some(dyn_sel) = &a.dynamic_select {
walk_expr(&dyn_sel.index_expr, idx, reads);
}
}
ProtoStatement::If(if_stmt) => {
if let Some(cond) = &if_stmt.cond {
walk_expr(cond, idx, reads);
}
for sub in &if_stmt.true_side {
walk_stmt(sub, idx, reads);
}
for sub in &if_stmt.false_side {
walk_stmt(sub, idx, reads);
}
}
ProtoStatement::For(f) => {
let walk_bound = |b: &ProtoForBound, r: &mut FutureReads| {
if let ProtoForBound::Dynamic(expr) = b {
walk_expr(expr, idx, r);
}
};
match &f.range {
ProtoForRange::Forward { start, end, .. }
| ProtoForRange::Reverse { start, end, .. }
| ProtoForRange::Stepped { start, end, .. } => {
walk_bound(start, reads);
walk_bound(end, reads);
}
}
for sub in &f.body {
walk_stmt(sub, idx, reads);
}
}
ProtoStatement::SequentialBlock(body) => {
for sub in body {
walk_stmt(sub, idx, reads);
}
}
ProtoStatement::SystemFunctionCall(_)
| ProtoStatement::CompiledBlock(_)
| ProtoStatement::TbMethodCall { .. }
| ProtoStatement::Break => {}
}
}
fn walk_expr(expr: &ProtoExpression, idx: usize, reads: &mut FutureReads) {
match expr {
ProtoExpression::Variable {
var_offset,
dynamic_select,
..
} => {
let v = reads.entry(*var_offset).or_default();
if v.last().copied() != Some(idx) {
v.push(idx);
}
if let Some(dyn_sel) = dynamic_select {
walk_expr(&dyn_sel.index_expr, idx, reads);
}
}
ProtoExpression::DynamicVariable {
index_expr,
dynamic_select,
..
} => {
walk_expr(index_expr, idx, reads);
if let Some(dyn_sel) = dynamic_select {
walk_expr(&dyn_sel.index_expr, idx, reads);
}
}
ProtoExpression::Unary { x, .. } => walk_expr(x, idx, reads),
ProtoExpression::Binary { x, y, .. } => {
walk_expr(x, idx, reads);
walk_expr(y, idx, reads);
}
ProtoExpression::Ternary {
cond,
true_expr,
false_expr,
..
} => {
walk_expr(cond, idx, reads);
walk_expr(true_expr, idx, reads);
walk_expr(false_expr, idx, reads);
}
ProtoExpression::Concatenation { elements, .. } => {
for (e, _, _) in elements {
walk_expr(e, idx, reads);
}
}
ProtoExpression::Value { .. } => {}
}
}