| 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); |
| } |