parser/grammar/
attributes.rs1use super::*;
2
3pub(super) const ATTRIBUTE_FIRST: TokenSet = TokenSet::new(&[T![#]]);
4
5pub(super) fn inner_attrs(p: &mut Parser<'_>) {
6 while p.at(T![#]) && p.nth(1) == T![!] {
7 attr(p, true);
8 }
9}
10
11pub(super) fn outer_attrs(p: &mut Parser<'_>) {
12 while p.at(T![#]) {
13 attr(p, false);
14 }
15}
16
17fn attr(p: &mut Parser<'_>, inner: bool) {
18 assert!(p.at(T![#]));
19
20 let attr = p.start();
21 p.bump(T![#]);
22
23 if inner {
24 p.bump(T![!]);
25 }
26
27 if p.eat(T!['[']) {
28 meta(p);
29
30 if !p.eat(T![']']) {
31 p.error("expected `]`");
32 }
33 } else {
34 p.error("expected `[`");
35 }
36 attr.complete(p, ATTR);
37}
38
39pub(super) fn meta(p: &mut Parser<'_>) {
69 let meta = p.start();
70 let is_unsafe = p.eat(T![unsafe]);
71 if is_unsafe {
72 p.expect(T!['(']);
73 }
74 paths::attr_path(p);
75
76 match p.current() {
77 T![=] => {
78 p.bump(T![=]);
79 if expressions::expr(p).is_none() {
80 p.error("expected expression");
81 }
82 }
83 T!['('] | T!['['] | T!['{'] => items::token_tree(p),
84 _ => {}
85 }
86 if is_unsafe {
87 p.expect(T![')']);
88 }
89
90 meta.complete(p, META);
91}