Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/cfg/src/cfg_expr.rs')
-rw-r--r--crates/cfg/src/cfg_expr.rs61
1 files changed, 60 insertions, 1 deletions
diff --git a/crates/cfg/src/cfg_expr.rs b/crates/cfg/src/cfg_expr.rs
index f83c21eb8d..76e0aba859 100644
--- a/crates/cfg/src/cfg_expr.rs
+++ b/crates/cfg/src/cfg_expr.rs
@@ -47,7 +47,7 @@ impl fmt::Display for CfgAtom {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-#[cfg_attr(test, derive(derive_arbitrary::Arbitrary))]
+#[cfg_attr(test, derive(arbitrary::Arbitrary))]
pub enum CfgExpr {
Invalid,
Atom(CfgAtom),
@@ -63,6 +63,8 @@ impl From<CfgAtom> for CfgExpr {
}
impl CfgExpr {
+ // FIXME: Parsing from `tt` is only used in a handful of places, reconsider
+ // if we should switch them to AST.
#[cfg(feature = "tt")]
pub fn parse<S: Copy>(tt: &tt::TopSubtree<S>) -> CfgExpr {
next_cfg_expr(&mut tt.iter()).unwrap_or(CfgExpr::Invalid)
@@ -73,6 +75,13 @@ impl CfgExpr {
next_cfg_expr(tt).unwrap_or(CfgExpr::Invalid)
}
+ #[cfg(feature = "syntax")]
+ pub fn parse_from_ast(
+ ast: &mut std::iter::Peekable<syntax::ast::TokenTreeChildren>,
+ ) -> CfgExpr {
+ next_cfg_expr_from_ast(ast).unwrap_or(CfgExpr::Invalid)
+ }
+
/// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
pub fn fold(&self, query: &dyn Fn(&CfgAtom) -> bool) -> Option<bool> {
match self {
@@ -89,6 +98,56 @@ impl CfgExpr {
}
}
+#[cfg(feature = "syntax")]
+fn next_cfg_expr_from_ast(
+ it: &mut std::iter::Peekable<syntax::ast::TokenTreeChildren>,
+) -> Option<CfgExpr> {
+ use intern::sym;
+ use syntax::{NodeOrToken, SyntaxKind, T, ast};
+
+ let name = match it.next() {
+ None => return None,
+ Some(NodeOrToken::Token(ident)) if ident.kind().is_any_identifier() => {
+ Symbol::intern(ident.text())
+ }
+ Some(_) => return Some(CfgExpr::Invalid),
+ };
+
+ let ret = match it.peek() {
+ Some(NodeOrToken::Token(eq)) if eq.kind() == T![=] => {
+ it.next();
+ if let Some(NodeOrToken::Token(literal)) = it.peek()
+ && matches!(literal.kind(), SyntaxKind::STRING)
+ {
+ let literal = tt::token_to_literal(literal.text(), ()).symbol;
+ it.next();
+ CfgAtom::KeyValue { key: name, value: literal.clone() }.into()
+ } else {
+ return Some(CfgExpr::Invalid);
+ }
+ }
+ Some(NodeOrToken::Node(subtree)) => {
+ let mut subtree_iter = ast::TokenTreeChildren::new(subtree).peekable();
+ it.next();
+ let mut subs = std::iter::from_fn(|| next_cfg_expr_from_ast(&mut subtree_iter));
+ match name {
+ s if s == sym::all => CfgExpr::All(subs.collect()),
+ s if s == sym::any => CfgExpr::Any(subs.collect()),
+ s if s == sym::not => {
+ CfgExpr::Not(Box::new(subs.next().unwrap_or(CfgExpr::Invalid)))
+ }
+ _ => CfgExpr::Invalid,
+ }
+ }
+ _ => CfgAtom::Flag(name).into(),
+ };
+
+ // Eat comma separator
+ while it.next().is_some_and(|it| it.as_token().is_none_or(|it| it.kind() != T![,])) {}
+
+ Some(ret)
+}
+
#[cfg(feature = "tt")]
fn next_cfg_expr<S: Copy>(it: &mut tt::iter::TtIter<'_, S>) -> Option<CfgExpr> {
use intern::sym;