diff options
author | David Tolnay <dtolnay@gmail.com> | 2022-01-17 18:51:24 -0800 |
---|---|---|
committer | David Tolnay <dtolnay@gmail.com> | 2022-01-17 19:54:54 -0800 |
commit | 7bafde28f4c60174ee1d239f4b6b079318100b9c (patch) | |
tree | 1fb4df81481824d6b46ddc5daac6e4445560d4d5 | |
parent | a6c5fdb52582cff18bb1a1f49802947c3ae9b059 (diff) | |
download | cxx-7bafde28f4c60174ee1d239f4b6b079318100b9c.tar.gz |
Run cfg evaluator to strip syntax tree
-rw-r--r-- | gen/src/cfg.rs | 68 | ||||
-rw-r--r-- | gen/src/mod.rs | 12 | ||||
-rw-r--r-- | syntax/attrs.rs | 1 | ||||
-rw-r--r-- | syntax/cfg.rs | 4 |
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 { |