use std::collections::HashSet;
use crate::wir::{WBlock, WIdent, WStmt, ZConverted};
pub fn used_open_idents(block: &WBlock<ZConverted>) -> HashSet<WIdent> {
let mut used_open = UsedOpen { scopes: vec![] };
used_open.open_block_idents(block)
}
struct UsedOpen {
scopes: Vec<HashSet<WIdent>>,
}
impl UsedOpen {
fn open_block_idents(&mut self, block: &WBlock<ZConverted>) -> HashSet<WIdent> {
let mut result = HashSet::new();
self.scopes.push(HashSet::new());
for stmt in &block.stmts {
result.extend(self.open_stmt_idents(stmt));
}
self.scopes.pop();
result
}
fn open_stmt_idents(&mut self, stmt: &WStmt<ZConverted>) -> HashSet<WIdent> {
match stmt {
WStmt::Assign(stmt_assign) => {
let right_idents = stmt_assign.right.idents();
let mut result = HashSet::new();
for right_ident in right_idents {
if self.is_open(&right_ident) {
result.insert(right_ident);
}
}
self.scopes
.last_mut()
.expect("Last scope should be present")
.insert(stmt_assign.left.clone());
result
}
WStmt::If(stmt_if) => {
let mut result = HashSet::new();
if self.is_open(&stmt_if.condition.ident) {
result.insert(stmt_if.condition.ident.clone());
}
result.extend(self.open_block_idents(&stmt_if.then_block));
result.extend(self.open_block_idents(&stmt_if.else_block));
result
}
}
}
fn is_open(&self, ident: &WIdent) -> bool {
for scope in &self.scopes {
if scope.contains(ident) {
return false;
}
}
true
}
}