aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2022-01-17 18:51:24 -0800
committerDavid Tolnay <dtolnay@gmail.com>2022-01-17 19:54:54 -0800
commit7bafde28f4c60174ee1d239f4b6b079318100b9c (patch)
tree1fb4df81481824d6b46ddc5daac6e4445560d4d5
parenta6c5fdb52582cff18bb1a1f49802947c3ae9b059 (diff)
downloadcxx-7bafde28f4c60174ee1d239f4b6b079318100b9c.tar.gz
Run cfg evaluator to strip syntax tree
-rw-r--r--gen/src/cfg.rs68
-rw-r--r--gen/src/mod.rs12
-rw-r--r--syntax/attrs.rs1
-rw-r--r--syntax/cfg.rs4
4 files changed, 79 insertions, 6 deletions
diff --git a/gen/src/cfg.rs b/gen/src/cfg.rs
index 2595e310..bd62a930 100644
--- a/gen/src/cfg.rs
+++ b/gen/src/cfg.rs
@@ -1,4 +1,9 @@
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;
pub(super) struct UnsupportedCfgEvaluator;
@@ -10,3 +15,66 @@ impl CfgEvaluator for UnsupportedCfgEvaluator {
CfgResult::Undetermined { msg }
}
}
+
+pub(super) fn strip(cx: &mut Errors, cfg_evaluator: &dyn CfgEvaluator, apis: &mut Vec<Api>) {
+ let mut already_errors = Set::new();
+ apis.retain(|api| eval(cx, &mut already_errors, cfg_evaluator, api.cfg()));
+ for api in apis {
+ match api {
+ Api::Struct(strct) => strct
+ .fields
+ .retain(|field| eval(cx, &mut already_errors, cfg_evaluator, &field.cfg)),
+ Api::Enum(enm) => enm
+ .variants
+ .retain(|variant| eval(cx, &mut already_errors, cfg_evaluator, &variant.cfg)),
+ _ => {}
+ }
+ }
+}
+
+fn eval(
+ cx: &mut Errors,
+ already_errors: &mut Set<String>,
+ cfg_evaluator: &dyn CfgEvaluator,
+ expr: &CfgExpr,
+) -> bool {
+ match expr {
+ CfgExpr::Unconditional => 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 => true,
+ CfgResult::False => false,
+ CfgResult::Undetermined { msg } => {
+ if already_errors.insert(msg.clone()) {
+ let span = quote!(#ident #string);
+ cx.error(span, msg);
+ }
+ false
+ }
+ }
+ }
+ CfgExpr::All(list) => list
+ .iter()
+ .all(|expr| eval(cx, already_errors, cfg_evaluator, expr)),
+ CfgExpr::Any(list) => list
+ .iter()
+ .any(|expr| eval(cx, already_errors, cfg_evaluator, expr)),
+ CfgExpr::Not(expr) => !eval(cx, already_errors, cfg_evaluator, expr),
+ }
+}
+
+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,
+ }
+ }
+}
diff --git a/gen/src/mod.rs b/gen/src/mod.rs
index 881cdd5f..90bfddd5 100644
--- a/gen/src/mod.rs
+++ b/gen/src/mod.rs
@@ -56,7 +56,6 @@ pub struct Opt {
pub(super) gen_header: bool,
pub(super) gen_implementation: bool,
pub(super) allow_dot_includes: bool,
- #[allow(dead_code)]
pub(super) cfg_evaluator: Box<dyn CfgEvaluator>,
}
@@ -64,11 +63,14 @@ pub(super) trait CfgEvaluator {
fn eval(&self, name: &str, value: Option<&str>) -> CfgResult;
}
-#[allow(dead_code)]
pub(super) enum CfgResult {
+ #[allow(dead_code)]
True,
+ #[allow(dead_code)]
False,
- Undetermined { msg: String },
+ Undetermined {
+ msg: String,
+ },
}
/// Results of code generation.
@@ -145,9 +147,13 @@ pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
));
}
+ cfg::strip(errors, opt.cfg_evaluator.as_ref(), apis);
+ errors.propagate()?;
+
let ref types = Types::collect(errors, apis);
check::precheck(errors, apis, opt);
errors.propagate()?;
+
let generator = check::Generator::Build;
check::typecheck(errors, apis, types, generator);
errors.propagate()?;
diff --git a/syntax/attrs.rs b/syntax/attrs.rs
index 61a7e8f4..552f4d00 100644
--- a/syntax/attrs.rs
+++ b/syntax/attrs.rs
@@ -132,7 +132,6 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
Ok(cfg_expr) => {
if let Some(cfg) = &mut parser.cfg {
cfg.merge(cfg_expr);
- cx.error(&attr, "support for cfg attribute is not implemented yet");
passthrough_attrs.push(attr);
continue;
}
diff --git a/syntax/cfg.rs b/syntax/cfg.rs
index 760f70fd..d486b995 100644
--- a/syntax/cfg.rs
+++ b/syntax/cfg.rs
@@ -6,7 +6,7 @@ use syn::{parenthesized, token, LitStr, Token};
#[derive(Clone)]
pub enum CfgExpr {
Unconditional,
- Eq(Ident, Option<String>),
+ Eq(Ident, Option<LitStr>),
All(Vec<CfgExpr>),
Any(Vec<CfgExpr>),
Not(Box<CfgExpr>),
@@ -55,7 +55,7 @@ fn parse_single(input: ParseStream) -> Result<CfgExpr> {
} else if lookahead.peek(Token![=]) {
input.parse::<Token![=]>()?;
let string: LitStr = input.parse()?;
- Ok(CfgExpr::Eq(ident, Some(string.value())))
+ Ok(CfgExpr::Eq(ident, Some(string)))
} else if lookahead.peek(Token![,]) || input.is_empty() {
Ok(CfgExpr::Eq(ident, None))
} else {