Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/parser/src/grammar/attributes.rs')
| -rw-r--r-- | crates/parser/src/grammar/attributes.rs | 113 |
1 files changed, 103 insertions, 10 deletions
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs index c0cf43a87b..2eeaa25257 100644 --- a/crates/parser/src/grammar/attributes.rs +++ b/crates/parser/src/grammar/attributes.rs @@ -40,6 +40,86 @@ fn attr(p: &mut Parser<'_>, inner: bool) { // #![unsafe] // #![unsafe =] +fn cfg_attr_meta(p: &mut Parser<'_>, m: Marker) { + // test cfg_attr + // #![cfg_attr(not(foo), unsafe(bar()), cfg_attr(all(true, foo = "bar"), baz = "baz"))] + p.eat_contextual_kw(T![cfg_attr]); + p.bump(T!['(']); + cfg_predicate(p); + p.expect(T![,]); + while !p.at(T![')']) && !p.at(EOF) { + meta(p); + if !p.eat(T![,]) { + break; + } + } + p.expect(T![')']); + m.complete(p, CFG_ATTR_META); +} + +const CFG_PREDICATE_FIRST_SET: TokenSet = TokenSet::new(&[T![true], T![false], T![ident]]); + +fn cfg_predicate(p: &mut Parser<'_>) { + let m = p.start(); + if p.eat(T![true]) || p.eat(T![false]) { + // test cfg_true_false_pred + // #![cfg(true)] + // #![cfg(false)] + m.complete(p, CFG_ATOM); + return; + } + p.expect(T![ident]); + if p.eat(T![=]) { + if p.at(T![ident]) { + // This is required for completion, that inserts an identifier, to work in cases like + // `#[cfg(key = $0)]`, and also makes sense on itself. + + // test_err key_ident_cfg_predicate + // #![cfg(key = value)] + p.err_and_bump("expected a string literal"); + } else { + // test cfg_key_value_pred + // #![cfg(key = "value")] + p.expect(T![string]); + } + m.complete(p, CFG_ATOM); + } else if p.at(T!['(']) { + // test cfg_composite_pred + // #![cfg(any(a, all(b = "c", d)))] + delimited( + p, + T!['('], + T![')'], + T![,], + || "expected a cfg predicate".to_owned(), + CFG_PREDICATE_FIRST_SET, + |p| { + if p.at_ts(CFG_PREDICATE_FIRST_SET) { + cfg_predicate(p); + true + } else { + false + } + }, + ); + m.complete(p, CFG_COMPOSITE); + } else { + m.complete(p, CFG_ATOM); + } +} + +fn cfg_meta(p: &mut Parser<'_>, m: Marker) { + // test cfg_meta + // #![cfg(foo)] + // #![cfg(foo = "bar",)] + p.eat_contextual_kw(T![cfg]); + p.bump(T!['(']); + cfg_predicate(p); + p.eat(T![,]); + p.expect(T![')']); + m.complete(p, CFG_META); +} + // test metas // #![simple_ident] // #![simple::path] @@ -62,11 +142,23 @@ fn attr(p: &mut Parser<'_>, inner: bool) { // #![unsafe(simple::path::tt[a b c])] // #![unsafe(simple::path::tt{a b c})] pub(super) fn meta(p: &mut Parser<'_>) { - let meta = p.start(); - let is_unsafe = p.eat(T![unsafe]); - if is_unsafe { + let m = p.start(); + if p.eat(T![unsafe]) { p.expect(T!['(']); + meta(p); + p.expect(T![')']); + m.complete(p, UNSAFE_META); + return; + } + + if p.nth_at(1, T!['(']) { + if p.at_contextual_kw(T![cfg_attr]) { + return cfg_attr_meta(p, m); + } else if p.at_contextual_kw(T![cfg]) { + return cfg_meta(p, m); + } } + paths::attr_path(p); match p.current() { @@ -75,13 +167,14 @@ pub(super) fn meta(p: &mut Parser<'_>) { if expressions::expr(p).is_none() { p.error("expected expression"); } + m.complete(p, KEY_VALUE_META); + } + T!['('] | T!['['] | T!['{'] => { + items::token_tree(p); + m.complete(p, TOKEN_TREE_META); + } + _ => { + m.complete(p, PATH_META); } - T!['('] | T!['['] | T!['{'] => items::token_tree(p), - _ => {} - } - if is_unsafe { - p.expect(T![')']); } - - meta.complete(p, META); } |