diff options
author | Jonas Schievink <[email protected]> | 2020-10-21 12:57:12 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-10-21 12:57:12 +0100 |
commit | 2bc4c1ff31b6ef0ca1848a7ce12f981b93dcded0 (patch) | |
tree | e4a775098e38cf46b48a6daad58566e652d97536 | |
parent | 20d369a826e8f333cba1988325480a49a730f00e (diff) |
Simplify cfg representation
-rw-r--r-- | crates/cfg/src/cfg_expr.rs | 44 | ||||
-rw-r--r-- | crates/cfg/src/lib.rs | 22 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 6 |
3 files changed, 41 insertions, 31 deletions
diff --git a/crates/cfg/src/cfg_expr.rs b/crates/cfg/src/cfg_expr.rs index 336fe25bc..db3655b74 100644 --- a/crates/cfg/src/cfg_expr.rs +++ b/crates/cfg/src/cfg_expr.rs | |||
@@ -6,26 +6,42 @@ use std::slice::Iter as SliceIter; | |||
6 | 6 | ||
7 | use tt::SmolStr; | 7 | use tt::SmolStr; |
8 | 8 | ||
9 | /// A simple configuration value passed in from the outside. | ||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
11 | pub enum CfgAtom { | ||
12 | /// eg. `#[cfg(test)]` | ||
13 | Flag(SmolStr), | ||
14 | /// eg. `#[cfg(target_os = "linux")]` | ||
15 | /// | ||
16 | /// Note that a key can have multiple values that are all considered "active" at the same time. | ||
17 | /// For example, `#[cfg(target_feature = "sse")]` and `#[cfg(target_feature = "sse2")]`. | ||
18 | KeyValue { key: SmolStr, value: SmolStr }, | ||
19 | } | ||
20 | |||
9 | #[derive(Debug, Clone, PartialEq, Eq)] | 21 | #[derive(Debug, Clone, PartialEq, Eq)] |
10 | pub enum CfgExpr { | 22 | pub enum CfgExpr { |
11 | Invalid, | 23 | Invalid, |
12 | Atom(SmolStr), | 24 | Atom(CfgAtom), |
13 | KeyValue { key: SmolStr, value: SmolStr }, | ||
14 | All(Vec<CfgExpr>), | 25 | All(Vec<CfgExpr>), |
15 | Any(Vec<CfgExpr>), | 26 | Any(Vec<CfgExpr>), |
16 | Not(Box<CfgExpr>), | 27 | Not(Box<CfgExpr>), |
17 | } | 28 | } |
18 | 29 | ||
30 | impl From<CfgAtom> for CfgExpr { | ||
31 | fn from(atom: CfgAtom) -> Self { | ||
32 | CfgExpr::Atom(atom) | ||
33 | } | ||
34 | } | ||
35 | |||
19 | impl CfgExpr { | 36 | impl CfgExpr { |
20 | pub fn parse(tt: &tt::Subtree) -> CfgExpr { | 37 | pub fn parse(tt: &tt::Subtree) -> CfgExpr { |
21 | next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) | 38 | next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) |
22 | } | 39 | } |
23 | /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. | 40 | /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. |
24 | pub fn fold(&self, query: &dyn Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> { | 41 | pub fn fold(&self, query: &dyn Fn(&CfgAtom) -> bool) -> Option<bool> { |
25 | match self { | 42 | match self { |
26 | CfgExpr::Invalid => None, | 43 | CfgExpr::Invalid => None, |
27 | CfgExpr::Atom(name) => Some(query(name, None)), | 44 | CfgExpr::Atom(atom) => Some(query(atom)), |
28 | CfgExpr::KeyValue { key, value } => Some(query(key, Some(value))), | ||
29 | CfgExpr::All(preds) => { | 45 | CfgExpr::All(preds) => { |
30 | preds.iter().try_fold(true, |s, pred| Some(s && pred.fold(query)?)) | 46 | preds.iter().try_fold(true, |s, pred| Some(s && pred.fold(query)?)) |
31 | } | 47 | } |
@@ -54,7 +70,7 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | |||
54 | // FIXME: escape? raw string? | 70 | // FIXME: escape? raw string? |
55 | let value = | 71 | let value = |
56 | SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); | 72 | SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); |
57 | CfgExpr::KeyValue { key: name, value } | 73 | CfgAtom::KeyValue { key: name, value }.into() |
58 | } | 74 | } |
59 | _ => return Some(CfgExpr::Invalid), | 75 | _ => return Some(CfgExpr::Invalid), |
60 | } | 76 | } |
@@ -70,7 +86,7 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | |||
70 | _ => CfgExpr::Invalid, | 86 | _ => CfgExpr::Invalid, |
71 | } | 87 | } |
72 | } | 88 | } |
73 | _ => CfgExpr::Atom(name), | 89 | _ => CfgAtom::Flag(name).into(), |
74 | }; | 90 | }; |
75 | 91 | ||
76 | // Eat comma separator | 92 | // Eat comma separator |
@@ -101,22 +117,22 @@ mod tests { | |||
101 | 117 | ||
102 | #[test] | 118 | #[test] |
103 | fn test_cfg_expr_parser() { | 119 | fn test_cfg_expr_parser() { |
104 | assert_parse_result("#![cfg(foo)]", CfgExpr::Atom("foo".into())); | 120 | assert_parse_result("#![cfg(foo)]", CfgAtom::Flag("foo".into()).into()); |
105 | assert_parse_result("#![cfg(foo,)]", CfgExpr::Atom("foo".into())); | 121 | assert_parse_result("#![cfg(foo,)]", CfgAtom::Flag("foo".into()).into()); |
106 | assert_parse_result( | 122 | assert_parse_result( |
107 | "#![cfg(not(foo))]", | 123 | "#![cfg(not(foo))]", |
108 | CfgExpr::Not(Box::new(CfgExpr::Atom("foo".into()))), | 124 | CfgExpr::Not(Box::new(CfgAtom::Flag("foo".into()).into())), |
109 | ); | 125 | ); |
110 | assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); | 126 | assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); |
111 | 127 | ||
112 | // Only take the first | 128 | // Only take the first |
113 | assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgExpr::Atom("foo".into())); | 129 | assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgAtom::Flag("foo".into()).into()); |
114 | 130 | ||
115 | assert_parse_result( | 131 | assert_parse_result( |
116 | r#"#![cfg(all(foo, bar = "baz"))]"#, | 132 | r#"#![cfg(all(foo, bar = "baz"))]"#, |
117 | CfgExpr::All(vec![ | 133 | CfgExpr::All(vec![ |
118 | CfgExpr::Atom("foo".into()), | 134 | CfgAtom::Flag("foo".into()).into(), |
119 | CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() }, | 135 | CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), |
120 | ]), | 136 | ]), |
121 | ); | 137 | ); |
122 | 138 | ||
@@ -126,7 +142,7 @@ mod tests { | |||
126 | CfgExpr::Not(Box::new(CfgExpr::Invalid)), | 142 | CfgExpr::Not(Box::new(CfgExpr::Invalid)), |
127 | CfgExpr::All(vec![]), | 143 | CfgExpr::All(vec![]), |
128 | CfgExpr::Invalid, | 144 | CfgExpr::Invalid, |
129 | CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() }, | 145 | CfgAtom::KeyValue { key: "bar".into(), value: "baz".into() }.into(), |
130 | ]), | 146 | ]), |
131 | ); | 147 | ); |
132 | } | 148 | } |
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index a9d50e698..35f540ac3 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs | |||
@@ -5,7 +5,7 @@ mod cfg_expr; | |||
5 | use rustc_hash::FxHashSet; | 5 | use rustc_hash::FxHashSet; |
6 | use tt::SmolStr; | 6 | use tt::SmolStr; |
7 | 7 | ||
8 | pub use cfg_expr::CfgExpr; | 8 | pub use cfg_expr::{CfgAtom, CfgExpr}; |
9 | 9 | ||
10 | /// Configuration options used for conditional compilition on items with `cfg` attributes. | 10 | /// Configuration options used for conditional compilition on items with `cfg` attributes. |
11 | /// We have two kind of options in different namespaces: atomic options like `unix`, and | 11 | /// We have two kind of options in different namespaces: atomic options like `unix`, and |
@@ -19,33 +19,25 @@ pub use cfg_expr::CfgExpr; | |||
19 | /// See: https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options | 19 | /// See: https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options |
20 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 20 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
21 | pub struct CfgOptions { | 21 | pub struct CfgOptions { |
22 | atoms: FxHashSet<SmolStr>, | 22 | enabled: FxHashSet<CfgAtom>, |
23 | key_values: FxHashSet<(SmolStr, SmolStr)>, | ||
24 | } | 23 | } |
25 | 24 | ||
26 | impl CfgOptions { | 25 | impl CfgOptions { |
27 | pub fn check(&self, cfg: &CfgExpr) -> Option<bool> { | 26 | pub fn check(&self, cfg: &CfgExpr) -> Option<bool> { |
28 | cfg.fold(&|key, value| match value { | 27 | cfg.fold(&|atom| self.enabled.contains(atom)) |
29 | None => self.atoms.contains(key), | ||
30 | Some(value) => self.key_values.contains(&(key.clone(), value.clone())), | ||
31 | }) | ||
32 | } | 28 | } |
33 | 29 | ||
34 | pub fn insert_atom(&mut self, key: SmolStr) { | 30 | pub fn insert_atom(&mut self, key: SmolStr) { |
35 | self.atoms.insert(key); | 31 | self.enabled.insert(CfgAtom::Flag(key)); |
36 | } | 32 | } |
37 | 33 | ||
38 | pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { | 34 | pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { |
39 | self.key_values.insert((key, value)); | 35 | self.enabled.insert(CfgAtom::KeyValue { key, value }); |
40 | } | 36 | } |
41 | 37 | ||
42 | pub fn append(&mut self, other: &CfgOptions) { | 38 | pub fn append(&mut self, other: &CfgOptions) { |
43 | for atom in &other.atoms { | 39 | for atom in &other.enabled { |
44 | self.atoms.insert(atom.clone()); | 40 | self.enabled.insert(atom.clone()); |
45 | } | ||
46 | |||
47 | for (key, value) in &other.key_values { | ||
48 | self.key_values.insert((key.clone(), value.clone())); | ||
49 | } | 41 | } |
50 | } | 42 | } |
51 | } | 43 | } |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index ddc028148..7da935464 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! See `CargoTargetSpec` | 1 | //! See `CargoTargetSpec` |
2 | 2 | ||
3 | use cfg::CfgExpr; | 3 | use cfg::{CfgAtom, CfgExpr}; |
4 | use ide::{FileId, RunnableKind, TestId}; | 4 | use ide::{FileId, RunnableKind, TestId}; |
5 | use project_model::{self, TargetKind}; | 5 | use project_model::{self, TargetKind}; |
6 | use vfs::AbsPathBuf; | 6 | use vfs::AbsPathBuf; |
@@ -160,7 +160,9 @@ impl CargoTargetSpec { | |||
160 | /// Fill minimal features needed | 160 | /// Fill minimal features needed |
161 | fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) { | 161 | fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) { |
162 | match cfg_expr { | 162 | match cfg_expr { |
163 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.to_string()), | 163 | CfgExpr::Atom(CfgAtom::KeyValue { key, value }) if key == "feature" => { |
164 | features.push(value.to_string()) | ||
165 | } | ||
164 | CfgExpr::All(preds) => { | 166 | CfgExpr::All(preds) => { |
165 | preds.iter().for_each(|cfg| required_features(cfg, features)); | 167 | preds.iter().for_each(|cfg| required_features(cfg, features)); |
166 | } | 168 | } |