use super::*;
pub(super) const ATTRIBUTE_FIRST: TokenSet = TokenSet::new(&[T![#]]);
pub(super) fn inner_attrs(p: &mut Parser<'_>) {
while p.at(T![#]) && p.nth(1) == T![!] {
attr(p, true);
}
}
pub(super) fn outer_attrs(p: &mut Parser<'_>) {
while p.at(T![#]) {
attr(p, false);
}
}
fn attr(p: &mut Parser<'_>, inner: bool) {
assert!(p.at(T![#]));
let attr = p.start();
p.bump(T![#]);
if inner {
p.bump(T![!]);
}
if p.expect(T!['[']) {
meta(p);
p.expect(T![']']);
}
attr.complete(p, ATTR);
}
// test_err meta_recovery
// #![]
// #![p = ]
// #![p::]
// #![p:: =]
// #![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]
// #![simple_ident_expr = ""]
// #![simple::path::Expr = ""]
// #![simple_ident_tt(a b c)]
// #![simple_ident_tt[a b c]]
// #![simple_ident_tt{a b c}]
// #![simple::path::tt(a b c)]
// #![simple::path::tt[a b c]]
// #![simple::path::tt{a b c}]
// #![unsafe(simple_ident)]
// #![unsafe(simple::path)]
// #![unsafe(simple_ident_expr = "")]
// #![unsafe(simple::path::Expr = "")]
// #![unsafe(simple_ident_tt(a b c))]
// #![unsafe(simple_ident_tt[a b c])]
// #![unsafe(simple_ident_tt{a b c})]
// #![unsafe(simple::path::tt(a b c))]
// #![unsafe(simple::path::tt[a b c])]
// #![unsafe(simple::path::tt{a b c})]
pub(super) fn meta(p: &mut Parser<'_>) {
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() {
T![=] if !p.at(T![=>]) && !p.at(T![==]) => {
p.bump(T![=]);
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);
}
}
}