use std::collections::HashSet;
use sv_lang::{SemNode, Symbol};
use sv_lang_kinds::{ExpressionKind, PatternKind, StatementKind};
use crate::symid::{SymbolId, SymbolUid};
pub fn pattern_vars<'d>(root: SemNode<'d>) -> Vec<Symbol<'d>> {
let mut out = Vec::new();
let mut seen: HashSet<SymbolId> = HashSet::new();
collect(root, &mut out, &mut seen);
out
}
fn collect<'d>(root: SemNode<'d>, out: &mut Vec<Symbol<'d>>, seen: &mut HashSet<SymbolId>) {
let mut stack = vec![root];
while let Some(node) = stack.pop() {
let mut kids = node.children();
if let Some(p) = node.as_pattern()
&& p.kind() == PatternKind::Variable
&& let Some(v) = p.variable()
&& !v.name().is_empty()
&& seen.insert(v.uid())
{
out.push(v);
}
if let Some(s) = node.as_statement() {
if s.kind() == StatementKind::Conditional {
for c in s.conditions() {
kids.extend(c.pattern().map(|p| p.as_sem_node()));
}
} else if s.kind() == StatementKind::PatternCase {
for item in s.pattern_case_items() {
kids.push(item.pattern().as_sem_node());
kids.push(item.stmt().as_sem_node());
}
}
}
if let Some(e) = node.as_expression()
&& e.kind() == ExpressionKind::ConditionalOp
{
for c in e.conditions() {
kids.extend(c.pattern().map(|p| p.as_sem_node()));
}
}
kids.reverse();
stack.extend(kids);
}
}
pub fn pattern_case_expr<'d>(stmt: sv_lang::Statement<'d>) -> Option<sv_lang::Expression<'d>> {
if stmt.kind() != StatementKind::PatternCase {
return None;
}
let exprs: Vec<_> = stmt
.as_sem_node()
.children()
.into_iter()
.filter_map(|c| c.as_expression())
.collect();
let filters = stmt
.pattern_case_items()
.iter()
.filter(|i| i.filter().is_some())
.count();
(exprs.len() == 1 + filters).then(|| exprs[0])
}