Use TokenTree straight from proc_macro2
diff --git a/src/attr.rs b/src/attr.rs
index 6069302..4171553 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -3,11 +3,16 @@
use std::iter;
-use proc_macro2::{self, Delimiter, TokenNode, Spacing};
+use proc_macro2::{Delimiter, TokenNode, TokenTree, Spacing};
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "extra-traits")]
+use mac::SliceTokenTreeHelper;
ast_struct! {
/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
- pub struct Attribute {
+ pub struct Attribute #manual_extra_traits {
pub style: AttrStyle,
pub pound_token: Token![#],
pub bracket_token: token::Bracket,
@@ -28,6 +33,35 @@
}
}
+#[cfg(feature = "extra-traits")]
+impl Eq for Attribute {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Attribute {
+ fn eq(&self, other: &Self) -> bool {
+ self.style == other.style
+ && self.pound_token == other.pound_token
+ && self.bracket_token == other.bracket_token
+ && self.path == other.path
+ && SliceTokenTreeHelper(&self.tts) == SliceTokenTreeHelper(&other.tts)
+ && self.is_sugared_doc == other.is_sugared_doc
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Attribute {
+ fn hash<H>(&self, state: &mut H)
+ where H: Hasher
+ {
+ self.style.hash(state);
+ self.pound_token.hash(state);
+ self.bracket_token.hash(state);
+ self.path.hash(state);
+ SliceTokenTreeHelper(&self.tts).hash(state);
+ self.is_sugared_doc.hash(state);
+ }
+}
+
impl Attribute {
/// Parses the tokens after the path as a [`MetaItem`](enum.MetaItem.html) if possible.
pub fn meta_item(&self) -> Option<MetaItem> {
@@ -42,11 +76,11 @@
}
if self.tts.len() == 1 {
- if let TokenNode::Group(Delimiter::Parenthesis, ref ts) = self.tts[0].0.kind {
+ if let TokenNode::Group(Delimiter::Parenthesis, ref ts) = self.tts[0].kind {
let tokens = ts.clone().into_iter().collect::<Vec<_>>();
if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(&tokens) {
return Some(MetaItem::List(MetaItemList {
- paren_token: token::Paren(self.tts[0].0.span),
+ paren_token: token::Paren(self.tts[0].span),
ident: *name,
nested: nested_meta_items,
}));
@@ -55,14 +89,14 @@
}
if self.tts.len() == 2 {
- if let TokenNode::Op('=', Spacing::Alone) = self.tts[0].0.kind {
- if let TokenNode::Literal(ref lit) = self.tts[1].0.kind {
+ if let TokenNode::Op('=', Spacing::Alone) = self.tts[0].kind {
+ if let TokenNode::Literal(ref lit) = self.tts[1].kind {
return Some(MetaItem::NameValue(MetaNameValue {
ident: *name,
- eq_token: Token,
+ eq_token: Token,
lit: Lit {
value: LitKind::Other(lit.clone()),
- span: self.tts[1].0.span,
+ span: self.tts[1].span,
},
}));
}
@@ -73,8 +107,8 @@
}
}
-fn nested_meta_item_from_tokens(tts: &[proc_macro2::TokenTree])
- -> Option<(NestedMetaItem, &[proc_macro2::TokenTree])>
+fn nested_meta_item_from_tokens(tts: &[TokenTree])
+ -> Option<(NestedMetaItem, &[TokenTree])>
{
assert!(!tts.is_empty());
@@ -130,7 +164,7 @@
}
}
-fn list_of_nested_meta_items_from_tokens(mut tts: &[proc_macro2::TokenTree])
+fn list_of_nested_meta_items_from_tokens(mut tts: &[TokenTree])
-> Option<Delimited<NestedMetaItem, Token![,]>>
{
let mut delimited = Delimited::new();
@@ -311,7 +345,7 @@
bang: punct!(!) >>
path_and_tts: brackets!(tuple!(
call!(::Path::parse_mod_style),
- call!(::TokenTree::parse_list)
+ call!(mac::parsing::parse_tt_list)
)) >>
({
let ((path, tts), bracket) = path_and_tts;
@@ -333,8 +367,8 @@
style: AttrStyle::Inner(<Token![!]>::default()),
path: "doc".into(),
tts: vec![
- ::TokenTree(eq()),
- ::TokenTree(lit),
+ eq(),
+ lit,
],
is_sugared_doc: true,
pound_token: <Token![#]>::default(),
@@ -348,7 +382,7 @@
pound: punct!(#) >>
path_and_tts: brackets!(tuple!(
call!(::Path::parse_mod_style),
- call!(::TokenTree::parse_list)
+ call!(mac::parsing::parse_tt_list)
)) >>
({
let ((path, tts), bracket) = path_and_tts;
@@ -370,8 +404,8 @@
style: AttrStyle::Outer,
path: "doc".into(),
tts: vec![
- ::TokenTree(eq()),
- ::TokenTree(lit),
+ eq(),
+ lit,
],
is_sugared_doc: true,
pound_token: <Token![#]>::default(),
diff --git a/src/expr.rs b/src/expr.rs
index 21ed9fa..ba1fc02 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1847,10 +1847,10 @@
Macro {
path: what,
bang_token: bang,
- tokens: vec![TokenTree(proc_macro2::TokenTree {
+ tokens: vec![proc_macro2::TokenTree {
span: (data.1).0,
kind: TokenNode::Group(Delimiter::Brace, data.0),
- })],
+ }],
},
match semi {
Some(semi) => MacStmtStyle::Semicolon(semi),
diff --git a/src/item.rs b/src/item.rs
index 5467f26..9549823 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1,5 +1,11 @@
use super::*;
use delimited::Delimited;
+use proc_macro2::TokenTree;
+
+#[cfg(feature = "extra-traits")]
+use mac::TokenTreeHelper;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
ast_enum_of_structs! {
/// Things that can appear directly inside of a module.
@@ -192,7 +198,7 @@
pub mac: Macro,
}),
/// FIXME will need to revisit what this looks like in the AST.
- pub Macro2(ItemMacro2 {
+ pub Macro2(ItemMacro2 #manual_extra_traits {
pub attrs: Vec<Attribute>,
pub vis: Visibility,
pub macro_token: Token![macro],
@@ -203,6 +209,35 @@
}
}
+#[cfg(feature = "extra-traits")]
+impl Eq for ItemMacro2 {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ItemMacro2 {
+ fn eq(&self, other: &Self) -> bool {
+ self.attrs == other.attrs
+ && self.vis == other.vis
+ && self.macro_token == other.macro_token
+ && self.ident == other.ident
+ && TokenTreeHelper(&self.args) == TokenTreeHelper(&other.args)
+ && TokenTreeHelper(&self.body) == TokenTreeHelper(&other.body)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ItemMacro2 {
+ fn hash<H>(&self, state: &mut H)
+ where H: Hasher
+ {
+ self.attrs.hash(state);
+ self.vis.hash(state);
+ self.macro_token.hash(state);
+ self.ident.hash(state);
+ TokenTreeHelper(&self.args).hash(state);
+ TokenTreeHelper(&self.body).hash(state);
+ }
+}
+
impl From<DeriveInput> for Item {
fn from(input: DeriveInput) -> Item {
match input.body {
@@ -484,8 +519,8 @@
what: syn!(Path) >>
bang: punct!(!) >>
ident: option!(syn!(Ident)) >>
- body: call!(TokenTree::parse_delimited) >>
- cond!(!body.is_braced(), punct!(;)) >>
+ body: call!(mac::parsing::parse_tt_delimited) >>
+ cond!(!mac::is_braced(&body), punct!(;)) >>
(ItemMacro {
attrs: attrs,
ident: ident,
@@ -503,8 +538,8 @@
vis: syn!(Visibility) >>
macro_: keyword!(macro) >>
ident: syn!(Ident) >>
- args: call!(TokenTree::parse_delimited) >>
- body: call!(TokenTree::parse_delimited) >>
+ args: call!(mac::parsing::parse_tt_delimited) >>
+ body: call!(mac::parsing::parse_tt_delimited) >>
(ItemMacro2 {
attrs: attrs,
vis: vis,
diff --git a/src/lib.rs b/src/lib.rs
index 474a0c0..e133f75 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -90,7 +90,7 @@
pub use lit::{Lit, LitKind};
mod mac;
-pub use mac::{Macro, TokenTree};
+pub use mac::Macro;
mod derive;
pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};
diff --git a/src/lit.rs b/src/lit.rs
index f55e398..9480563 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -1,9 +1,7 @@
use std::fmt;
use std::hash::{Hash, Hasher};
-use proc_macro2::{self, Span, Literal, TokenNode, Term};
-
-use TokenTree;
+use proc_macro2::{self, Span, Literal, TokenNode, TokenTree, Term};
#[derive(Clone)]
pub struct Lit {
@@ -24,10 +22,10 @@
LitKind::Bool(false) => TokenNode::Term(Term::intern("false")),
LitKind::Other(l) => TokenNode::Literal(l),
};
- TokenTree(proc_macro2::TokenTree {
+ proc_macro2::TokenTree {
span: self.span,
kind: kind,
- })
+ }
}
}
diff --git a/src/mac.rs b/src/mac.rs
index e370acd..b2a6a19 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -1,45 +1,66 @@
-#[cfg(feature = "extra-traits")]
-use std::fmt;
-
use super::*;
-use proc_macro2::{TokenNode, Delimiter};
+use proc_macro2::{TokenNode, TokenTree, Delimiter};
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
ast_struct! {
/// Represents a macro invocation. The Path indicates which macro
/// is being invoked, and the vector of token-trees contains the source
/// of the macro invocation.
- pub struct Macro {
+ pub struct Macro #manual_extra_traits {
pub path: Path,
pub bang_token: Token![!],
pub tokens: Vec<TokenTree>,
}
}
-#[cfg_attr(feature = "clone-impls", derive(Clone))]
-pub struct TokenTree(pub proc_macro2::TokenTree);
+#[cfg(feature = "extra-traits")]
+impl Eq for Macro {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Macro {
+ fn eq(&self, other: &Self) -> bool {
+ self.path == other.path
+ && self.bang_token == other.bang_token
+ && SliceTokenTreeHelper(&self.tokens) == SliceTokenTreeHelper(&other.tokens)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Macro {
+ fn hash<H>(&self, state: &mut H)
+ where H: Hasher
+ {
+ self.path.hash(state);
+ self.bang_token.hash(state);
+ SliceTokenTreeHelper(&self.tokens).hash(state);
+ }
+}
impl Macro {
pub fn is_braced(&self) -> bool {
match self.tokens.last() {
- Some(t) => t.is_braced(),
+ Some(t) => is_braced(t),
None => false,
}
}
}
-impl TokenTree {
- pub fn is_braced(&self) -> bool {
- match self.0.kind {
- TokenNode::Group(Delimiter::Brace, _) => true,
- _ => false,
- }
+pub fn is_braced(tt: &TokenTree) -> bool {
+ match tt.kind {
+ TokenNode::Group(Delimiter::Brace, _) => true,
+ _ => false,
}
}
#[cfg(feature = "extra-traits")]
-impl PartialEq for TokenTree {
- fn eq(&self, other: &TokenTree) -> bool {
+pub struct TokenTreeHelper<'a>(pub &'a TokenTree);
+
+#[cfg(feature = "extra-traits")]
+impl<'a> PartialEq for TokenTreeHelper<'a> {
+ fn eq(&self, other: &Self) -> bool {
use proc_macro2::Spacing;
match (&self.0.kind, &other.0.kind) {
@@ -60,7 +81,7 @@
Some(item) => item,
None => return false,
};
- if TokenTree(item1) != TokenTree(item2) {
+ if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
return false
}
}
@@ -85,11 +106,8 @@
}
#[cfg(feature = "extra-traits")]
-impl Eq for TokenTree {}
-
-#[cfg(feature = "extra-traits")]
-impl ::std::hash::Hash for TokenTree {
- fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
+impl<'a> Hash for TokenTreeHelper<'a> {
+ fn hash<H: Hasher>(&self, h: &mut H) {
use proc_macro2::Spacing;
match self.0.kind {
@@ -103,7 +121,7 @@
}
for item in stream.clone() {
- TokenTree(item).hash(h);
+ TokenTreeHelper(&item).hash(h);
}
0xffu8.hash(h); // terminator w/ a variant we don't normally hash
}
@@ -122,9 +140,30 @@
}
#[cfg(feature = "extra-traits")]
-impl fmt::Debug for TokenTree {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.0.to_string().fmt(f)
+pub struct SliceTokenTreeHelper<'a>(pub &'a [TokenTree]);
+
+#[cfg(feature = "extra-traits")]
+impl<'a> PartialEq for SliceTokenTreeHelper<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ if self.0.len() != other.0.len() {
+ return false;
+ }
+ for (a, b) in self.0.iter().zip(other.0) {
+ if TokenTreeHelper(a) != TokenTreeHelper(b) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl<'a> Hash for SliceTokenTreeHelper<'a> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.0.len().hash(state);
+ for tt in self.0 {
+ TokenTreeHelper(tt).hash(state);
+ }
}
}
@@ -141,7 +180,7 @@
named!(parse -> Self, do_parse!(
what: syn!(Path) >>
bang: punct!(!) >>
- body: call!(::TokenTree::parse_delimited) >>
+ body: call!(parse_tt_delimited) >>
(Macro {
path: what,
bang_token: bang,
@@ -150,18 +189,16 @@
));
}
- impl ::TokenTree {
- pub fn parse_list(input: Cursor) -> PResult<Vec<Self>> {
- Ok((Cursor::empty(), input.token_stream().into_iter().map(::TokenTree).collect()))
- }
+ pub fn parse_tt_list(input: Cursor) -> PResult<Vec<TokenTree>> {
+ Ok((Cursor::empty(), input.token_stream().into_iter().collect()))
+ }
- pub fn parse_delimited(input: Cursor) -> PResult<Self> {
- match input.token_tree() {
- Some((rest, token @ TokenTree { kind: TokenNode::Group(..), .. })) => {
- Ok((rest, ::TokenTree(token)))
- }
- _ => parse_error(),
+ pub fn parse_tt_delimited(input: Cursor) -> PResult<TokenTree> {
+ match input.token_tree() {
+ Some((rest, token @ TokenTree { kind: TokenNode::Group(..), .. })) => {
+ Ok((rest, token))
}
+ _ => parse_error(),
}
}
}
@@ -178,10 +215,4 @@
tokens.append_all(&self.tokens);
}
}
-
- impl ToTokens for TokenTree {
- fn to_tokens(&self, tokens: &mut Tokens) {
- self.0.to_tokens(tokens);
- }
- }
}
diff --git a/src/macros.rs b/src/macros.rs
index cf49640..1710444 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -20,6 +20,16 @@
(
$(#[$attr:meta])*
+ pub struct $name:ident #manual_extra_traits $($rest:tt)*
+ ) => {
+ $(#[$attr])*
+ #[cfg_attr(feature = "extra-traits", derive(Debug))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ pub struct $name $($rest)*
+ };
+
+ (
+ $(#[$attr:meta])*
pub struct $name:ident $($rest:tt)*
) => {
$(#[$attr])*
diff --git a/src/parsers.rs b/src/parsers.rs
index 66561c1..ae17365 100644
--- a/src/parsers.rs
+++ b/src/parsers.rs
@@ -667,7 +667,7 @@
/// extern crate syn;
/// extern crate proc_macro2;
///
-/// use syn::{Ident, TokenTree};
+/// use syn::Ident;
/// use syn::token::Paren;
/// use proc_macro2::TokenStream;
///