parser/grammar/attributes.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
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.eat(T!['[']) {
meta(p);
if !p.eat(T![']']) {
p.error("expected `]`");
}
} else {
p.error("expected `[`");
}
attr.complete(p, ATTR);
}
// test_err meta_recovery
// #![]
// #![p = ]
// #![p::]
// #![p:: =]
// #![unsafe]
// #![unsafe =]
// 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 meta = p.start();
let is_unsafe = p.eat(T![unsafe]);
if is_unsafe {
p.expect(T!['(']);
}
paths::attr_path(p);
match p.current() {
T![=] => {
p.bump(T![=]);
if expressions::expr(p).is_none() {
p.error("expected expression");
}
}
T!['('] | T!['['] | T!['{'] => items::token_tree(p),
_ => {}
}
if is_unsafe {
p.expect(T![')']);
}
meta.complete(p, META);
}