parser/grammar/
attributes.rs

1use 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
39// test_err meta_recovery
40// #![]
41// #![p = ]
42// #![p::]
43// #![p:: =]
44// #![unsafe]
45// #![unsafe =]
46
47// test metas
48// #![simple_ident]
49// #![simple::path]
50// #![simple_ident_expr = ""]
51// #![simple::path::Expr = ""]
52// #![simple_ident_tt(a b c)]
53// #![simple_ident_tt[a b c]]
54// #![simple_ident_tt{a b c}]
55// #![simple::path::tt(a b c)]
56// #![simple::path::tt[a b c]]
57// #![simple::path::tt{a b c}]
58// #![unsafe(simple_ident)]
59// #![unsafe(simple::path)]
60// #![unsafe(simple_ident_expr = "")]
61// #![unsafe(simple::path::Expr = "")]
62// #![unsafe(simple_ident_tt(a b c))]
63// #![unsafe(simple_ident_tt[a b c])]
64// #![unsafe(simple_ident_tt{a b c})]
65// #![unsafe(simple::path::tt(a b c))]
66// #![unsafe(simple::path::tt[a b c])]
67// #![unsafe(simple::path::tt{a b c})]
68pub(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}