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.rs | 61 |
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; |