Allow literals inside meta item lists
diff --git a/src/attr.rs b/src/attr.rs
index 64bcc4e..8f70319 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -37,7 +37,7 @@
/// List meta item.
///
/// E.g. `derive(..)` as in `#[derive(..)]`
- List(Ident, Vec<MetaItem>),
+ List(Ident, Vec<NestedMetaItem>),
/// Name value meta item.
///
/// E.g. `feature = "foo"` as in `#[feature = "foo"]`
@@ -54,6 +54,19 @@
}
}
+/// Possible values inside of compile-time attribute lists.
+///
+/// E.g. the '..' in `#[name(..)]`.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum NestedMetaItem {
+ /// A full MetaItem, for recursive meta items.
+ MetaItem(MetaItem),
+ /// A literal.
+ ///
+ /// E.g. "foo", 64, true
+ Literal(Lit),
+}
+
pub trait FilterAttrs<'a> {
type Ret: Iterator<Item = &'a Attribute>;
@@ -177,7 +190,7 @@
do_parse!(
id: ident >>
punct!("(") >>
- inner: terminated_list!(punct!(","), meta_item) >>
+ inner: terminated_list!(punct!(","), nested_meta_item) >>
punct!(")") >>
(MetaItem::List(id, inner))
)
@@ -191,6 +204,12 @@
|
map!(ident, MetaItem::Word)
));
+
+ named!(nested_meta_item -> NestedMetaItem, alt!(
+ meta_item => { NestedMetaItem::MetaItem }
+ |
+ lit => { NestedMetaItem::Literal }
+ ));
}
#[cfg(feature = "printing")]
@@ -258,4 +277,17 @@
}
}
}
+
+ impl ToTokens for NestedMetaItem {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ match *self {
+ NestedMetaItem::MetaItem(ref nested) => {
+ nested.to_tokens(tokens);
+ }
+ NestedMetaItem::Literal(ref lit) => {
+ lit.to_tokens(tokens);
+ }
+ }
+ }
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index a59e8b6..87bb38f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,7 +23,7 @@
mod escape;
mod attr;
-pub use attr::{Attribute, AttrStyle, MetaItem};
+pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem};
mod constant;
pub use constant::ConstExpr;
diff --git a/src/registry.rs b/src/registry.rs
index 0dcb6d6..2acd759 100644
--- a/src/registry.rs
+++ b/src/registry.rs
@@ -1,4 +1,5 @@
-use super::{Attribute, AttrStyle, Body, Crate, Ident, Item, ItemKind, MacroInput, MetaItem};
+use super::{Attribute, AttrStyle, Body, Crate, Ident, Item, ItemKind, MacroInput, MetaItem,
+ NestedMetaItem};
use quote::Tokens;
use std::collections::BTreeMap as Map;
@@ -110,7 +111,7 @@
fn expand_item(reg: &Registry,
mut item: Item,
- cfg: Vec<MetaItem>,
+ cfg: Vec<NestedMetaItem>,
out: &mut Vec<Item>)
-> Result<(), String> {
let (body, generics) = match item.node {
@@ -135,7 +136,7 @@
fn expand_macro_input(reg: &Registry,
mut input: MacroInput,
- inherited_cfg: Vec<MetaItem>,
+ inherited_cfg: Vec<NestedMetaItem>,
out: &mut Vec<Item>)
-> Result<(), String> {
let mut derives = Vec::new();
@@ -176,11 +177,11 @@
struct Derive {
name: Ident,
/// If the custom derive was behind a cfg_attr
- cfg: Option<MetaItem>,
+ cfg: Option<NestedMetaItem>,
}
/// Pull custom derives and cfgs out of the given Attribute.
-fn parse_attr(reg: &Registry, attr: Attribute) -> (Vec<Derive>, Vec<MetaItem>, Option<Attribute>) {
+fn parse_attr(reg: &Registry, attr: Attribute) -> (Vec<Derive>, Vec<NestedMetaItem>, Option<Attribute>) {
if attr.style != AttrStyle::Outer || attr.is_sugared_doc {
return (Vec::new(), Vec::new(), Some(attr));
}
@@ -222,20 +223,20 @@
/// Assuming the given nested meta-items came from a #[derive(...)] attribute,
/// pull out the ones that are custom derives.
-fn parse_derive_attr(reg: &Registry, nested: Vec<MetaItem>) -> (Vec<Ident>, Option<Attribute>) {
+fn parse_derive_attr(reg: &Registry, nested: Vec<NestedMetaItem>) -> (Vec<Ident>, Option<Attribute>) {
let mut derives = Vec::new();
let remaining: Vec<_> = nested.into_iter()
.flat_map(|meta| {
let word = match meta {
- MetaItem::Word(word) => word,
+ NestedMetaItem::MetaItem(MetaItem::Word(word)) => word,
_ => return Some(meta),
};
if reg.derives.contains_key(word.as_ref()) {
derives.push(word);
None
} else {
- Some(MetaItem::Word(word))
+ Some(NestedMetaItem::MetaItem(MetaItem::Word(word)))
}
})
.collect();
@@ -256,7 +257,7 @@
/// Assuming the given nested meta-items came from a #[cfg_attr(...)] attribute,
/// pull out any custom derives contained within.
-fn parse_cfg_attr(reg: &Registry, nested: Vec<MetaItem>) -> (Vec<Derive>, Option<Attribute>) {
+fn parse_cfg_attr(reg: &Registry, nested: Vec<NestedMetaItem>) -> (Vec<Derive>, Option<Attribute>) {
if nested.len() != 2 {
let attr = Attribute {
style: AttrStyle::Outer,
@@ -271,7 +272,7 @@
let arg = iter.next().unwrap();
let (name, nested) = match arg {
- MetaItem::List(name, nested) => (name, nested),
+ NestedMetaItem::MetaItem(MetaItem::List(name, nested)) => (name, nested),
_ => {
let attr = Attribute {
style: AttrStyle::Outer,
@@ -295,7 +296,7 @@
let attr = attr.map(|attr| {
Attribute {
style: AttrStyle::Outer,
- value: MetaItem::List("cfg_attr".into(), vec![cfg, attr.value]),
+ value: MetaItem::List("cfg_attr".into(), vec![cfg, NestedMetaItem::MetaItem(attr.value)]),
is_sugared_doc: false,
}
});
@@ -303,7 +304,7 @@
} else {
let attr = Attribute {
style: AttrStyle::Outer,
- value: MetaItem::List("cfg_attr".into(), vec![cfg, MetaItem::List(name, nested)]),
+ value: MetaItem::List("cfg_attr".into(), vec![cfg, NestedMetaItem::MetaItem(MetaItem::List(name, nested))]),
is_sugared_doc: false,
};
(Vec::new(), Some(attr))
@@ -312,18 +313,18 @@
/// Combine a list of cfg expressions into an attribute like `#[cfg(a)]` or
/// `#[cfg(all(a, b, c))]`, or nothing if there are no cfg expressions.
-fn combine_cfgs(cfg: Vec<MetaItem>) -> Option<Attribute> {
+fn combine_cfgs(cfg: Vec<NestedMetaItem>) -> Option<Attribute> {
// Flatten `all` cfgs so we don't nest `all` inside of `all`.
let cfg: Vec<_> = cfg.into_iter()
.flat_map(|cfg| {
let (name, nested) = match cfg {
- MetaItem::List(name, nested) => (name, nested),
+ NestedMetaItem::MetaItem(MetaItem::List(name, nested)) => (name, nested),
_ => return vec![cfg],
};
if name == "all" {
nested
} else {
- vec![MetaItem::List(name, nested)]
+ vec![NestedMetaItem::MetaItem(MetaItem::List(name, nested))]
}
})
.collect();
@@ -331,7 +332,7 @@
let value = match cfg.len() {
0 => return None,
1 => cfg,
- _ => vec![MetaItem::List("all".into(), cfg)],
+ _ => vec![NestedMetaItem::MetaItem(MetaItem::List("all".into(), cfg))],
};
Some(Attribute {
diff --git a/tests/test_macro_input.rs b/tests/test_macro_input.rs
index 8a0c395..2f4f2a3 100644
--- a/tests/test_macro_input.rs
+++ b/tests/test_macro_input.rs
@@ -33,8 +33,8 @@
Attribute {
style: AttrStyle::Outer,
value: MetaItem::List("derive".into(), vec![
- MetaItem::Word("Debug".into()),
- MetaItem::Word("Clone".into()),
+ NestedMetaItem::MetaItem(MetaItem::Word("Debug".into())),
+ NestedMetaItem::MetaItem(MetaItem::Word("Clone".into())),
]),
is_sugared_doc: false,
},