Combine Expr::Field and Expr::TupleField into one variant
diff --git a/src/expr.rs b/src/expr.rs
index e7b35b1..4e7efe4 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1,5 +1,9 @@
use super::*;
use delimited::Delimited;
+#[cfg(feature = "full")]
+use proc_macro2::Span;
+#[cfg(feature = "full")]
+use std::hash::{Hash, Hasher};
ast_struct! {
/// An expression.
@@ -229,20 +233,12 @@
pub right: Box<Expr>,
}),
- /// Access of a named struct field (`obj.foo`)
+ /// Access of a named struct field (`obj.foo`) or unnamed tuple struct
+ /// field (`obj.0`).
pub Field(ExprField #full {
- pub expr: Box<Expr>,
- pub field: Ident,
+ pub base: Box<Expr>,
pub dot_token: Token![.],
- }),
-
- /// Access of an unnamed field of a struct or tuple-struct
- ///
- /// For example, `foo.0`.
- pub TupleField(ExprTupleField #full {
- pub expr: Box<Expr>,
- pub field: Lit,
- pub dot_token: Token![.],
+ pub member: Member,
}),
/// An indexing operation (`foo[2]`)
@@ -363,11 +359,54 @@
}
#[cfg(feature = "full")]
+ast_enum! {
+ /// A struct or tuple struct field accessed in a struct literal or field
+ /// expression.
+ pub enum Member {
+ /// A named field like `self.x`.
+ Named(Ident),
+ /// An unnamed field like `self.0`.
+ Unnamed(Index),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// The index of an unnamed tuple struct field.
+ pub struct Index #manual_extra_traits {
+ pub index: u32,
+ pub span: Span,
+ }
+}
+
+#[cfg(feature = "full")]
+impl Eq for Index {}
+
+#[cfg(feature = "full")]
+impl PartialEq for Index {
+ fn eq(&self, other: &Self) -> bool {
+ self.index == other.index
+ }
+}
+
+#[cfg(feature = "full")]
+impl Hash for Index {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.index.hash(state);
+ }
+}
+
+#[cfg(feature = "full")]
ast_struct! {
/// A field-value pair in a struct literal.
pub struct FieldValue {
- /// Name of the field.
- pub ident: Ident,
+ /// Attributes tagged on the field.
+ pub attrs: Vec<Attribute>,
+
+ /// Name or index of the field.
+ pub member: Member,
+
+ pub colon_token: Option<Token![:]>,
/// Value of the field.
pub expr: Expr,
@@ -375,11 +414,6 @@
/// Whether this is a shorthand field, e.g. `Struct { x }`
/// instead of `Struct { x: x }`.
pub is_shorthand: bool,
-
- /// Attributes tagged on the field.
- pub attrs: Vec<Attribute>,
-
- pub colon_token: Option<Token![:]>,
}
}
@@ -606,7 +640,7 @@
/// except `is_shorthand` is true
pub struct FieldPat {
/// The identifier for the field
- pub ident: Ident,
+ pub member: Member,
/// The pattern the field is destructured to
pub pat: Box<Pat>,
pub is_shorthand: bool,
@@ -659,7 +693,7 @@
use ty::parsing::qpath;
#[cfg(feature = "full")]
- use proc_macro2::{Delimiter, Span, Term, TokenNode, TokenStream};
+ use proc_macro2::{Delimiter, Span, TokenNode, TokenStream};
use synom::Synom;
use cursor::Cursor;
#[cfg(feature = "full")]
@@ -1080,20 +1114,11 @@
})
|
tap!(field: and_field => {
- let (field, token) = field;
+ let (token, member) = field;
e = ExprField {
- expr: Box::new(e.into()),
- field: field,
+ base: Box::new(e.into()),
dot_token: token,
- }.into();
- })
- |
- tap!(field: and_tup_field => {
- let (field, token) = field;
- e = ExprTupleField {
- expr: Box::new(e.into()),
- field: field,
- dot_token: token,
+ member: member,
}.into();
})
|
@@ -1693,11 +1718,11 @@
impl Synom for FieldValue {
named!(parse -> Self, alt!(
do_parse!(
- ident: field_ident >>
+ member: syn!(Member) >>
colon: punct!(:) >>
value: syn!(Expr) >>
(FieldValue {
- ident: ident,
+ member: member,
expr: value,
is_shorthand: false,
attrs: Vec::new(),
@@ -1706,7 +1731,7 @@
)
|
map!(syn!(Ident), |name| FieldValue {
- ident: name,
+ member: Member::Named(name),
expr: ExprKind::Path(ExprPath { qself: None, path: name.into() }).into(),
is_shorthand: true,
attrs: Vec::new(),
@@ -1786,12 +1811,7 @@
}
#[cfg(feature = "full")]
- named!(and_field -> (Ident, Token![.]),
- map!(tuple!(punct!(.), syn!(Ident)), |(a, b)| (b, a)));
-
- #[cfg(feature = "full")]
- named!(and_tup_field -> (Lit, Token![.]),
- map!(tuple!(punct!(.), syn!(Lit)), |(a, b)| (b, a)));
+ named!(and_field -> (Token![.], Member), tuple!(punct!(.), syn!(Member)));
named!(and_index -> (Expr, token::Bracket), brackets!(syn!(Expr)));
@@ -2034,11 +2054,11 @@
impl Synom for FieldPat {
named!(parse -> Self, alt!(
do_parse!(
- ident: field_ident >>
+ member: syn!(Member) >>
colon: punct!(:) >>
pat: syn!(Pat) >>
(FieldPat {
- ident: ident,
+ member: member,
pat: Box::new(pat),
is_shorthand: false,
attrs: Vec::new(),
@@ -2069,7 +2089,7 @@
}.into();
}
FieldPat {
- ident: ident,
+ member: Member::Named(ident),
pat: Box::new(pat),
is_shorthand: true,
attrs: Vec::new(),
@@ -2081,21 +2101,27 @@
}
#[cfg(feature = "full")]
- named!(field_ident -> Ident, alt!(
- syn!(Ident)
- |
- do_parse!(
+ impl Synom for Member {
+ named!(parse -> Self, alt!(
+ syn!(Ident) => { Member::Named }
+ |
+ syn!(Index) => { Member::Unnamed }
+ ));
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for Index {
+ named!(parse -> Self, do_parse!(
lit: syn!(Lit) >>
({
- let s = lit.to_string();
- if s.parse::<usize>().is_ok() {
- Ident::new(Term::intern(&s), lit.span)
+ if let Ok(i) = lit.value.to_string().parse() {
+ Index { index: i, span: lit.span }
} else {
return parse_error();
}
})
- )
- ));
+ ));
+ }
#[cfg(feature = "full")]
impl Synom for PatPath {
@@ -2268,6 +2294,8 @@
#[cfg(feature = "full")]
use attr::FilterAttrs;
use quote::{ToTokens, Tokens};
+ #[cfg(feature = "full")]
+ use proc_macro2::{TokenTree, TokenNode, Literal};
// If the given expression is a bare `ExprStruct`, wraps it in parenthesis
// before appending it to `Tokens`.
@@ -2614,20 +2642,29 @@
#[cfg(feature = "full")]
impl ToTokens for ExprField {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.expr.to_tokens(tokens);
+ self.base.to_tokens(tokens);
self.dot_token.to_tokens(tokens);
- // XXX: I don't think we can do anything if someone shoves a
- // nonsense Lit in here.
- self.field.to_tokens(tokens);
+ self.member.to_tokens(tokens);
}
}
#[cfg(feature = "full")]
- impl ToTokens for ExprTupleField {
+ impl ToTokens for Member {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.expr.to_tokens(tokens);
- self.dot_token.to_tokens(tokens);
- self.field.to_tokens(tokens);
+ match *self {
+ Member::Named(ident) => ident.to_tokens(tokens),
+ Member::Unnamed(ref index) => index.to_tokens(tokens),
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Index {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append(TokenTree {
+ span: self.span,
+ kind: TokenNode::Literal(Literal::integer(self.index as i64)),
+ });
}
}
@@ -2744,7 +2781,7 @@
#[cfg(feature = "full")]
impl ToTokens for FieldValue {
fn to_tokens(&self, tokens: &mut Tokens) {
- self.ident.to_tokens(tokens);
+ self.member.to_tokens(tokens);
// XXX: Override self.is_shorthand if expr is not an IdentExpr with
// the ident self.ident?
if !self.is_shorthand {
@@ -2917,7 +2954,7 @@
fn to_tokens(&self, tokens: &mut Tokens) {
// XXX: Override is_shorthand if it was wrong?
if !self.is_shorthand {
- self.ident.to_tokens(tokens);
+ self.member.to_tokens(tokens);
TokensOrDefault(&self.colon_token).to_tokens(tokens);
}
self.pat.to_tokens(tokens);