aboutsummaryrefslogtreecommitdiff
path: root/gen/src/cfg.rs
diff options
context:
space:
mode:
Diffstat (limited to 'gen/src/cfg.rs')
-rw-r--r--gen/src/cfg.rs133
1 files changed, 133 insertions, 0 deletions
diff --git a/gen/src/cfg.rs b/gen/src/cfg.rs
new file mode 100644
index 00000000..da589085
--- /dev/null
+++ b/gen/src/cfg.rs
@@ -0,0 +1,133 @@
+use crate::gen::{CfgEvaluator, CfgResult};
+use crate::syntax::cfg::CfgExpr;
+use crate::syntax::report::Errors;
+use crate::syntax::Api;
+use quote::quote;
+use std::collections::BTreeSet as Set;
+use syn::Error;
+
+pub(super) struct UnsupportedCfgEvaluator;
+
+impl CfgEvaluator for UnsupportedCfgEvaluator {
+ fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
+ let _ = name;
+ let _ = value;
+ let msg = "cfg attribute is not supported".to_owned();
+ CfgResult::Undetermined { msg }
+ }
+}
+
+pub(super) fn strip(
+ cx: &mut Errors,
+ cfg_errors: &mut Set<String>,
+ cfg_evaluator: &dyn CfgEvaluator,
+ apis: &mut Vec<Api>,
+) {
+ apis.retain(|api| eval(cx, cfg_errors, cfg_evaluator, api.cfg()));
+ for api in apis {
+ match api {
+ Api::Struct(strct) => strct
+ .fields
+ .retain(|field| eval(cx, cfg_errors, cfg_evaluator, &field.cfg)),
+ Api::Enum(enm) => enm
+ .variants
+ .retain(|variant| eval(cx, cfg_errors, cfg_evaluator, &variant.cfg)),
+ _ => {}
+ }
+ }
+}
+
+pub(super) fn eval(
+ cx: &mut Errors,
+ cfg_errors: &mut Set<String>,
+ cfg_evaluator: &dyn CfgEvaluator,
+ expr: &CfgExpr,
+) -> bool {
+ match try_eval(cfg_evaluator, expr) {
+ Ok(value) => value,
+ Err(errors) => {
+ for error in errors {
+ if cfg_errors.insert(error.to_string()) {
+ cx.push(error);
+ }
+ }
+ false
+ }
+ }
+}
+
+fn try_eval(cfg_evaluator: &dyn CfgEvaluator, expr: &CfgExpr) -> Result<bool, Vec<Error>> {
+ match expr {
+ CfgExpr::Unconditional => Ok(true),
+ CfgExpr::Eq(ident, string) => {
+ let key = ident.to_string();
+ let value = string.as_ref().map(|string| string.value());
+ match cfg_evaluator.eval(&key, value.as_deref()) {
+ CfgResult::True => Ok(true),
+ CfgResult::False => Ok(false),
+ CfgResult::Undetermined { msg } => {
+ let span = quote!(#ident #string);
+ Err(vec![Error::new_spanned(span, msg)])
+ }
+ }
+ }
+ CfgExpr::All(list) => {
+ let mut all_errors = Vec::new();
+ for subexpr in list {
+ match try_eval(cfg_evaluator, subexpr) {
+ Ok(true) => {}
+ Ok(false) => return Ok(false),
+ Err(errors) => all_errors.extend(errors),
+ }
+ }
+ if all_errors.is_empty() {
+ Ok(true)
+ } else {
+ Err(all_errors)
+ }
+ }
+ CfgExpr::Any(list) => {
+ let mut all_errors = Vec::new();
+ for subexpr in list {
+ match try_eval(cfg_evaluator, subexpr) {
+ Ok(true) => return Ok(true),
+ Ok(false) => {}
+ Err(errors) => all_errors.extend(errors),
+ }
+ }
+ if all_errors.is_empty() {
+ Ok(false)
+ } else {
+ Err(all_errors)
+ }
+ }
+ CfgExpr::Not(subexpr) => match try_eval(cfg_evaluator, subexpr) {
+ Ok(value) => Ok(!value),
+ Err(errors) => Err(errors),
+ },
+ }
+}
+
+impl Api {
+ fn cfg(&self) -> &CfgExpr {
+ match self {
+ Api::Include(include) => &include.cfg,
+ Api::Struct(strct) => &strct.cfg,
+ Api::Enum(enm) => &enm.cfg,
+ Api::CxxType(ety) | Api::RustType(ety) => &ety.cfg,
+ Api::CxxFunction(efn) | Api::RustFunction(efn) => &efn.cfg,
+ Api::TypeAlias(alias) => &alias.cfg,
+ Api::Impl(imp) => &imp.cfg,
+ }
+ }
+}
+
+impl From<bool> for CfgResult {
+ fn from(value: bool) -> Self {
+ if value {
+ CfgResult::True
+ } else {
+ CfgResult::False
+ }
+ }
+}