use std::collections::BTreeSet;
use crate::ast::traverse::{
traverse_call_children, traverse_expr_children, traverse_lvalue_children,
traverse_stmt_children,
};
use crate::ast::{AstExpr, AstFeature, AstGlobalAttr, AstLocalAttr, AstModule, AstStmt};
pub(crate) fn collect_ast_features(module: &AstModule) -> BTreeSet<AstFeature> {
let mut features = BTreeSet::new();
collect_block_features(&module.body, &mut features);
features
}
fn collect_block_features(block: &crate::ast::AstBlock, features: &mut BTreeSet<AstFeature>) {
for stmt in &block.stmts {
collect_stmt_features(stmt, features);
}
}
fn collect_stmt_features(stmt: &AstStmt, features: &mut BTreeSet<AstFeature>) {
match stmt {
AstStmt::LocalDecl(local_decl) => {
for binding in &local_decl.bindings {
match binding.attr {
AstLocalAttr::Const => {
features.insert(AstFeature::LocalConst);
}
AstLocalAttr::Close => {
features.insert(AstFeature::LocalClose);
}
AstLocalAttr::None => {}
}
}
}
AstStmt::GlobalDecl(global_decl) => {
features.insert(AstFeature::GlobalDecl);
for binding in &global_decl.bindings {
if binding.attr == AstGlobalAttr::Const {
features.insert(AstFeature::GlobalConst);
}
}
}
AstStmt::Continue => {
features.insert(AstFeature::ContinueStmt);
}
AstStmt::Goto(_) | AstStmt::Label(_) | AstStmt::Error(_) => {
features.insert(AstFeature::GotoLabel);
}
_ => {}
}
traverse_stmt_children!(
stmt,
iter = iter,
opt = as_ref,
borrow = [&],
expr(e) => { collect_expr_features(e, features); },
lvalue(lv) => {
traverse_lvalue_children!(
lv,
borrow = [&],
expr(e) => { collect_expr_features(e, features); }
);
},
block(b) => { collect_block_features(b, features); },
function(f) => { collect_block_features(&f.body, features); },
condition(c) => { collect_expr_features(c, features); },
call(c) => {
traverse_call_children!(
c,
iter = iter,
borrow = [&],
expr(e) => { collect_expr_features(e, features); }
);
}
);
}
fn collect_expr_features(expr: &AstExpr, features: &mut BTreeSet<AstFeature>) {
traverse_expr_children!(
expr,
iter = iter,
borrow = [&],
expr(e) => { collect_expr_features(e, features); },
function(f) => { collect_block_features(&f.body, features); }
);
}