fixup! Only store tokens in Attribute.
diff --git a/src/attr.rs b/src/attr.rs
index 8b5ee18..e403882 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -6,13 +6,99 @@
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Attribute {
pub style: AttrStyle,
- pub value: MetaItem,
+ pub name: Ident,
+ pub tts: Vec<TokenTree>,
pub is_sugared_doc: bool,
}
impl Attribute {
- pub fn name(&self) -> &str {
- self.value.name()
+ pub fn meta_item(&self) -> Option<MetaItem> {
+ if self.tts.is_empty() {
+ return Some(MetaItem::Word);
+ }
+
+ if self.tts.len() == 1 {
+ if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, ref tts }) = self.tts[0] {
+ fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
+ assert!(!tts.is_empty());
+
+ match tts[0] {
+ TokenTree::Token(Token::Literal(ref lit)) => {
+ Some((NestedMetaItem::Literal(lit.clone()), &tts[1..]))
+ }
+
+ TokenTree::Token(Token::Ident(ref ident)) => {
+ if tts.len() >= 3 {
+ match (&tts[1], &tts[2]) {
+ (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
+ return Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::NameValue(lit.clone())), &tts[3..]));
+ }
+
+ _ => {}
+ }
+ }
+
+ if tts.len() >= 2 {
+ if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
+ return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
+ Some(nested_meta_items) => {
+ Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::List(nested_meta_items)), &tts[2..]))
+ }
+
+ None => None
+ };
+ }
+ }
+
+ Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::Word), &tts[1..]))
+ }
+
+ _ => None
+ }
+ }
+
+ fn list_of_nested_meta_items_from_tokens(mut result: Vec<NestedMetaItem>, tts: &[TokenTree]) -> Option<Vec<NestedMetaItem>> {
+ if tts.is_empty() {
+ return Some(result);
+ }
+
+ match nested_meta_item_from_tokens(tts) {
+ Some((nested_meta_item, rest)) => {
+ result.push(nested_meta_item);
+ if rest.is_empty() {
+ list_of_nested_meta_items_from_tokens(result, rest)
+ }
+ else {
+ if let TokenTree::Token(Token::Comma) = rest[0] {
+ list_of_nested_meta_items_from_tokens(result, &rest[1..])
+ }
+ else {
+ None
+ }
+ }
+ }
+
+ None => None
+ }
+ }
+
+ if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
+ return Some(MetaItem::List(nested_meta_items));
+ }
+ }
+ }
+
+ if self.tts.len() == 2 {
+ match (&self.tts[0], &self.tts[1]) {
+ (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
+ return Some(MetaItem::NameValue(lit.clone()));
+ }
+
+ _ => {}
+ }
+ }
+
+ None
}
}
@@ -36,37 +122,17 @@
/// Word meta item.
///
/// E.g. `test` as in `#[test]`
- Word(Ident),
+ Word,
/// List meta item.
///
/// E.g. `derive(..)` as in `#[derive(..)]`
- List(Ident, Vec<NestedMetaItem>),
+ List(Vec<NestedMetaItem>),
/// Name-value meta item.
///
/// E.g. `feature = "foo"` as in `#[feature = "foo"]`
- NameValue(Ident, Lit),
-
- /// Tokens meta item.
- ///
- /// E.g. `test foo bar` as in `#[test foo bar]`
- Tokens(Ident, Vec<TokenTree>),
-}
-
-impl MetaItem {
- /// Name of the item.
- ///
- /// E.g. `test` as in `#[test]`, `derive` as in `#[derive(..)]`, and
- /// `feature` as in `#[feature = "foo"]`.
- pub fn name(&self) -> &str {
- match *self {
- MetaItem::Word(ref name) |
- MetaItem::List(ref name, _) |
- MetaItem::NameValue(ref name, _) |
- MetaItem::Tokens(ref name, _) => name.as_ref(),
- }
- }
+ NameValue(Lit),
}
/// Possible values inside of compile-time attribute lists.
@@ -76,8 +142,8 @@
pub enum NestedMetaItem {
/// A full `MetaItem`.
///
- /// E.g. `Copy` in `#[derive(Copy)]` would be a `MetaItem::Word(Ident::from("Copy"))`.
- MetaItem(MetaItem),
+ /// E.g. `Copy` in `#[derive(Copy)]` would be a `(Ident::from("Copy"), MetaItem::Word)`.
+ MetaItem(Ident, MetaItem),
/// A Rust literal.
///
@@ -116,7 +182,6 @@
pub mod parsing {
use super::*;
use ident::parsing::ident;
- use lit::parsing::lit;
use mac::parsing::token_trees;
use synom::space::{block_comment, whitespace};
@@ -125,13 +190,20 @@
do_parse!(
punct!("#") >>
punct!("!") >>
- punct!("[") >>
- meta_item: meta_item >>
- punct!("]") >>
- (Attribute {
- style: AttrStyle::Inner,
- value: meta_item,
- is_sugared_doc: false,
+ name_and_tts: delimited!(
+ punct!("["),
+ tuple!(ident, token_trees),
+ punct!("]")
+ ) >>
+ ({
+ let (name, tts) = name_and_tts;
+
+ Attribute {
+ style: AttrStyle::Inner,
+ name: name,
+ tts: tts,
+ is_sugared_doc: false,
+ }
})
)
|
@@ -140,10 +212,11 @@
content: take_until!("\n") >>
(Attribute {
style: AttrStyle::Inner,
- value: MetaItem::NameValue(
- "doc".into(),
- format!("//!{}", content).into(),
- ),
+ name: "doc".into(),
+ tts: vec![
+ TokenTree::Token(Token::Eq),
+ TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
+ ],
is_sugared_doc: true,
})
)
@@ -154,10 +227,11 @@
com: block_comment >>
(Attribute {
style: AttrStyle::Inner,
- value: MetaItem::NameValue(
- "doc".into(),
- com.into(),
- ),
+ name: "doc".into(),
+ tts: vec![
+ TokenTree::Token(Token::Eq),
+ TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
+ ],
is_sugared_doc: true,
})
)
@@ -166,32 +240,20 @@
named!(pub outer_attr -> Attribute, alt!(
do_parse!(
punct!("#") >>
- punct!("[") >>
- meta_item: meta_item >>
- punct!("]") >>
- (Attribute {
- style: AttrStyle::Outer,
- value: meta_item,
- is_sugared_doc: false,
- })
- )
- |
- do_parse!(
- name_and_token_trees: preceded!(
- punct!("#"),
- delimited!(
- punct!("["),
- tuple!(ident, token_trees),
- punct!("]")
- )
+ name_and_tts: delimited!(
+ punct!("["),
+ tuple!(ident, token_trees),
+ punct!("]")
) >>
- (Attribute {
- style: AttrStyle::Outer,
- value: {
- let (name, token_trees) = name_and_token_trees;
- MetaItem::Tokens(name, token_trees)
- },
- is_sugared_doc: false,
+ ({
+ let (name, tts) = name_and_tts;
+
+ Attribute {
+ style: AttrStyle::Outer,
+ name: name,
+ tts: tts,
+ is_sugared_doc: false,
+ }
})
)
|
@@ -201,10 +263,11 @@
content: take_until!("\n") >>
(Attribute {
style: AttrStyle::Outer,
- value: MetaItem::NameValue(
- "doc".into(),
- format!("///{}", content).into(),
- ),
+ name: "doc".into(),
+ tts: vec![
+ TokenTree::Token(Token::Eq),
+ TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
+ ],
is_sugared_doc: true,
})
)
@@ -215,39 +278,15 @@
com: block_comment >>
(Attribute {
style: AttrStyle::Outer,
- value: MetaItem::NameValue(
- "doc".into(),
- com.into(),
- ),
+ name: "doc".into(),
+ tts: vec![
+ TokenTree::Token(Token::Eq),
+ TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
+ ],
is_sugared_doc: true,
})
)
));
-
- named!(meta_item -> MetaItem, alt!(
- do_parse!(
- id: ident >>
- punct!("(") >>
- inner: terminated_list!(punct!(","), nested_meta_item) >>
- punct!(")") >>
- (MetaItem::List(id, inner))
- )
- |
- do_parse!(
- name: ident >>
- punct!("=") >>
- value: lit >>
- (MetaItem::NameValue(name, value))
- )
- |
- map!(ident, MetaItem::Word)
- ));
-
- named!(nested_meta_item -> NestedMetaItem, alt!(
- meta_item => { NestedMetaItem::MetaItem }
- |
- lit => { NestedMetaItem::Literal }
- ));
}
#[cfg(feature = "printing")]
@@ -258,28 +297,32 @@
impl ToTokens for Attribute {
fn to_tokens(&self, tokens: &mut Tokens) {
- if let Attribute { style,
- value: MetaItem::NameValue(ref name,
- Lit::Str(ref value, StrStyle::Cooked)),
- is_sugared_doc: true } = *self {
- if name == "doc" {
- match style {
- AttrStyle::Inner if value.starts_with("//!") => {
- tokens.append(&format!("{}\n", value));
- return;
+ if let Attribute { style, ref name, ref tts, is_sugared_doc: true } = *self {
+ if name == "doc" && tts.len() == 2 {
+ match (&tts[0], &tts[1]) {
+ (&TokenTree::Token(Token::Eq),
+ &TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked)))) => {
+ match style {
+ AttrStyle::Inner if value.starts_with("//!") => {
+ tokens.append(&format!("{}\n", value));
+ return;
+ }
+ AttrStyle::Inner if value.starts_with("/*!") => {
+ tokens.append(value);
+ return;
+ }
+ AttrStyle::Outer if value.starts_with("///") => {
+ tokens.append(&format!("{}\n", value));
+ return;
+ }
+ AttrStyle::Outer if value.starts_with("/**") => {
+ tokens.append(value);
+ return;
+ }
+ _ => {}
+ }
}
- AttrStyle::Inner if value.starts_with("/*!") => {
- tokens.append(value);
- return;
- }
- AttrStyle::Outer if value.starts_with("///") => {
- tokens.append(&format!("{}\n", value));
- return;
- }
- AttrStyle::Outer if value.starts_with("/**") => {
- tokens.append(value);
- return;
- }
+
_ => {}
}
}
@@ -290,7 +333,8 @@
tokens.append("!");
}
tokens.append("[");
- self.value.to_tokens(tokens);
+ self.name.to_tokens(tokens);
+ tokens.append_all(&self.tts);
tokens.append("]");
}
}
@@ -298,24 +342,16 @@
impl ToTokens for MetaItem {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
- MetaItem::Word(ref ident) => {
- ident.to_tokens(tokens);
- }
- MetaItem::List(ref ident, ref inner) => {
- ident.to_tokens(tokens);
+ MetaItem::Word => {}
+ MetaItem::List(ref inner) => {
tokens.append("(");
tokens.append_separated(inner, ",");
tokens.append(")");
}
- MetaItem::NameValue(ref name, ref value) => {
- name.to_tokens(tokens);
+ MetaItem::NameValue(ref value) => {
tokens.append("=");
value.to_tokens(tokens);
}
- MetaItem::Tokens(ref name, ref token_trees) => {
- name.to_tokens(tokens);
- tokens.append_all(token_trees);
- }
}
}
}
@@ -323,7 +359,8 @@
impl ToTokens for NestedMetaItem {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
- NestedMetaItem::MetaItem(ref nested) => {
+ NestedMetaItem::MetaItem(ref ident, ref nested) => {
+ ident.to_tokens(tokens);
nested.to_tokens(tokens);
}
NestedMetaItem::Literal(ref lit) => {