Handle extended key value attr in mbe

This commit is contained in:
Edwin Cheng 2021-04-17 14:31:52 +08:00
parent df5b6f7d45
commit c4173bb468
3 changed files with 35 additions and 48 deletions

View File

@ -940,6 +940,24 @@ fn test_meta_doc_comments() {
);
}
#[test]
fn test_meta_extended_key_value_attributes() {
parse_macro(
r#"
macro_rules! foo {
(#[$i:meta]) => (
#[$ i]
fn bar() {}
)
}
"#,
)
.assert_expand_items(
r#"foo! { #[doc = concat!("The `", "bla", "` lang item.")] }"#,
r#"# [doc = concat ! ("The `" , "bla" , "` lang item.")] fn bar () {}"#,
);
}
#[test]
fn test_meta_doc_comments_non_latin() {
parse_macro(

View File

@ -76,42 +76,7 @@ pub(crate) mod fragments {
// Parse a meta item , which excluded [], e.g : #[ MetaItem ]
pub(crate) fn meta_item(p: &mut Parser) {
fn is_delimiter(p: &mut Parser) -> bool {
matches!(p.current(), T!['{'] | T!['('] | T!['['])
}
if is_delimiter(p) {
items::token_tree(p);
return;
}
let m = p.start();
while !p.at(EOF) {
if is_delimiter(p) {
items::token_tree(p);
break;
} else {
// https://doc.rust-lang.org/reference/attributes.html
// https://doc.rust-lang.org/reference/paths.html#simple-paths
// The start of an meta must be a simple path
match p.current() {
IDENT | T![super] | T![self] | T![crate] => p.bump_any(),
T![=] => {
p.bump_any();
match p.current() {
c if c.is_literal() => p.bump_any(),
T![true] | T![false] => p.bump_any(),
_ => {}
}
break;
}
_ if p.at(T![::]) => p.bump(T![::]),
_ => break,
}
}
}
m.complete(p, TOKEN_TREE);
attributes::meta(p);
}
pub(crate) fn item(p: &mut Parser) {

View File

@ -14,6 +14,21 @@ pub(super) fn outer_attrs(p: &mut Parser) {
}
}
pub(super) fn meta(p: &mut Parser) {
paths::use_path(p);
match p.current() {
T![=] => {
p.bump(T![=]);
if expressions::expr(p).0.is_none() {
p.error("expected expression");
}
}
T!['('] | T!['['] | T!['{'] => items::token_tree(p),
_ => {}
}
}
fn attr(p: &mut Parser, inner: bool) {
let attr = p.start();
assert!(p.at(T![#]));
@ -25,18 +40,7 @@ fn attr(p: &mut Parser, inner: bool) {
}
if p.eat(T!['[']) {
paths::use_path(p);
match p.current() {
T![=] => {
p.bump(T![=]);
if expressions::expr(p).0.is_none() {
p.error("expected expression");
}
}
T!['('] | T!['['] | T!['{'] => items::token_tree(p),
_ => {}
}
meta(p);
if !p.eat(T![']']) {
p.error("expected `]`");