133d722a9Sopenharmony_ciuse crate::gen::{CfgEvaluator, CfgResult};
233d722a9Sopenharmony_ciuse crate::syntax::cfg::CfgExpr;
333d722a9Sopenharmony_ciuse crate::syntax::report::Errors;
433d722a9Sopenharmony_ciuse crate::syntax::Api;
533d722a9Sopenharmony_ciuse quote::quote;
633d722a9Sopenharmony_ciuse std::collections::BTreeSet as Set;
733d722a9Sopenharmony_ciuse syn::Error;
833d722a9Sopenharmony_ci
933d722a9Sopenharmony_cipub(super) struct UnsupportedCfgEvaluator;
1033d722a9Sopenharmony_ci
1133d722a9Sopenharmony_ciimpl CfgEvaluator for UnsupportedCfgEvaluator {
1233d722a9Sopenharmony_ci    fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
1333d722a9Sopenharmony_ci        let _ = name;
1433d722a9Sopenharmony_ci        let _ = value;
1533d722a9Sopenharmony_ci        let msg = "cfg attribute is not supported".to_owned();
1633d722a9Sopenharmony_ci        CfgResult::Undetermined { msg }
1733d722a9Sopenharmony_ci    }
1833d722a9Sopenharmony_ci}
1933d722a9Sopenharmony_ci
2033d722a9Sopenharmony_cipub(super) fn strip(
2133d722a9Sopenharmony_ci    cx: &mut Errors,
2233d722a9Sopenharmony_ci    cfg_errors: &mut Set<String>,
2333d722a9Sopenharmony_ci    cfg_evaluator: &dyn CfgEvaluator,
2433d722a9Sopenharmony_ci    apis: &mut Vec<Api>,
2533d722a9Sopenharmony_ci) {
2633d722a9Sopenharmony_ci    apis.retain(|api| eval(cx, cfg_errors, cfg_evaluator, api.cfg()));
2733d722a9Sopenharmony_ci    for api in apis {
2833d722a9Sopenharmony_ci        match api {
2933d722a9Sopenharmony_ci            Api::Struct(strct) => strct
3033d722a9Sopenharmony_ci                .fields
3133d722a9Sopenharmony_ci                .retain(|field| eval(cx, cfg_errors, cfg_evaluator, &field.cfg)),
3233d722a9Sopenharmony_ci            Api::Enum(enm) => enm
3333d722a9Sopenharmony_ci                .variants
3433d722a9Sopenharmony_ci                .retain(|variant| eval(cx, cfg_errors, cfg_evaluator, &variant.cfg)),
3533d722a9Sopenharmony_ci            _ => {}
3633d722a9Sopenharmony_ci        }
3733d722a9Sopenharmony_ci    }
3833d722a9Sopenharmony_ci}
3933d722a9Sopenharmony_ci
4033d722a9Sopenharmony_cipub(super) fn eval(
4133d722a9Sopenharmony_ci    cx: &mut Errors,
4233d722a9Sopenharmony_ci    cfg_errors: &mut Set<String>,
4333d722a9Sopenharmony_ci    cfg_evaluator: &dyn CfgEvaluator,
4433d722a9Sopenharmony_ci    expr: &CfgExpr,
4533d722a9Sopenharmony_ci) -> bool {
4633d722a9Sopenharmony_ci    match try_eval(cfg_evaluator, expr) {
4733d722a9Sopenharmony_ci        Ok(value) => value,
4833d722a9Sopenharmony_ci        Err(errors) => {
4933d722a9Sopenharmony_ci            for error in errors {
5033d722a9Sopenharmony_ci                if cfg_errors.insert(error.to_string()) {
5133d722a9Sopenharmony_ci                    cx.push(error);
5233d722a9Sopenharmony_ci                }
5333d722a9Sopenharmony_ci            }
5433d722a9Sopenharmony_ci            false
5533d722a9Sopenharmony_ci        }
5633d722a9Sopenharmony_ci    }
5733d722a9Sopenharmony_ci}
5833d722a9Sopenharmony_ci
5933d722a9Sopenharmony_cifn try_eval(cfg_evaluator: &dyn CfgEvaluator, expr: &CfgExpr) -> Result<bool, Vec<Error>> {
6033d722a9Sopenharmony_ci    match expr {
6133d722a9Sopenharmony_ci        CfgExpr::Unconditional => Ok(true),
6233d722a9Sopenharmony_ci        CfgExpr::Eq(ident, string) => {
6333d722a9Sopenharmony_ci            let key = ident.to_string();
6433d722a9Sopenharmony_ci            let value = string.as_ref().map(|string| string.value());
6533d722a9Sopenharmony_ci            match cfg_evaluator.eval(&key, value.as_deref()) {
6633d722a9Sopenharmony_ci                CfgResult::True => Ok(true),
6733d722a9Sopenharmony_ci                CfgResult::False => Ok(false),
6833d722a9Sopenharmony_ci                CfgResult::Undetermined { msg } => {
6933d722a9Sopenharmony_ci                    let span = quote!(#ident #string);
7033d722a9Sopenharmony_ci                    Err(vec![Error::new_spanned(span, msg)])
7133d722a9Sopenharmony_ci                }
7233d722a9Sopenharmony_ci            }
7333d722a9Sopenharmony_ci        }
7433d722a9Sopenharmony_ci        CfgExpr::All(list) => {
7533d722a9Sopenharmony_ci            let mut all_errors = Vec::new();
7633d722a9Sopenharmony_ci            for subexpr in list {
7733d722a9Sopenharmony_ci                match try_eval(cfg_evaluator, subexpr) {
7833d722a9Sopenharmony_ci                    Ok(true) => {}
7933d722a9Sopenharmony_ci                    Ok(false) => return Ok(false),
8033d722a9Sopenharmony_ci                    Err(errors) => all_errors.extend(errors),
8133d722a9Sopenharmony_ci                }
8233d722a9Sopenharmony_ci            }
8333d722a9Sopenharmony_ci            if all_errors.is_empty() {
8433d722a9Sopenharmony_ci                Ok(true)
8533d722a9Sopenharmony_ci            } else {
8633d722a9Sopenharmony_ci                Err(all_errors)
8733d722a9Sopenharmony_ci            }
8833d722a9Sopenharmony_ci        }
8933d722a9Sopenharmony_ci        CfgExpr::Any(list) => {
9033d722a9Sopenharmony_ci            let mut all_errors = Vec::new();
9133d722a9Sopenharmony_ci            for subexpr in list {
9233d722a9Sopenharmony_ci                match try_eval(cfg_evaluator, subexpr) {
9333d722a9Sopenharmony_ci                    Ok(true) => return Ok(true),
9433d722a9Sopenharmony_ci                    Ok(false) => {}
9533d722a9Sopenharmony_ci                    Err(errors) => all_errors.extend(errors),
9633d722a9Sopenharmony_ci                }
9733d722a9Sopenharmony_ci            }
9833d722a9Sopenharmony_ci            if all_errors.is_empty() {
9933d722a9Sopenharmony_ci                Ok(false)
10033d722a9Sopenharmony_ci            } else {
10133d722a9Sopenharmony_ci                Err(all_errors)
10233d722a9Sopenharmony_ci            }
10333d722a9Sopenharmony_ci        }
10433d722a9Sopenharmony_ci        CfgExpr::Not(subexpr) => match try_eval(cfg_evaluator, subexpr) {
10533d722a9Sopenharmony_ci            Ok(value) => Ok(!value),
10633d722a9Sopenharmony_ci            Err(errors) => Err(errors),
10733d722a9Sopenharmony_ci        },
10833d722a9Sopenharmony_ci    }
10933d722a9Sopenharmony_ci}
11033d722a9Sopenharmony_ci
11133d722a9Sopenharmony_ciimpl Api {
11233d722a9Sopenharmony_ci    fn cfg(&self) -> &CfgExpr {
11333d722a9Sopenharmony_ci        match self {
11433d722a9Sopenharmony_ci            Api::Include(include) => &include.cfg,
11533d722a9Sopenharmony_ci            Api::Struct(strct) => &strct.cfg,
11633d722a9Sopenharmony_ci            Api::Enum(enm) => &enm.cfg,
11733d722a9Sopenharmony_ci            Api::CxxType(ety) | Api::RustType(ety) => &ety.cfg,
11833d722a9Sopenharmony_ci            Api::CxxFunction(efn) | Api::RustFunction(efn) => &efn.cfg,
11933d722a9Sopenharmony_ci            Api::TypeAlias(alias) => &alias.cfg,
12033d722a9Sopenharmony_ci            Api::Impl(imp) => &imp.cfg,
12133d722a9Sopenharmony_ci        }
12233d722a9Sopenharmony_ci    }
12333d722a9Sopenharmony_ci}
12433d722a9Sopenharmony_ci
12533d722a9Sopenharmony_ciimpl From<bool> for CfgResult {
12633d722a9Sopenharmony_ci    fn from(value: bool) -> Self {
12733d722a9Sopenharmony_ci        if value {
12833d722a9Sopenharmony_ci            CfgResult::True
12933d722a9Sopenharmony_ci        } else {
13033d722a9Sopenharmony_ci            CfgResult::False
13133d722a9Sopenharmony_ci        }
13233d722a9Sopenharmony_ci    }
13333d722a9Sopenharmony_ci}
134