// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::*;
use punctuated::Punctuated;
ast_struct! {
/// An enum variant.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
pub struct Variant {
/// Attributes tagged on the variant.
pub attrs: Vec<Attribute>,
/// Name of the variant.
pub ident: Ident,
/// Content stored in the variant.
pub fields: Fields,
/// Explicit discriminant: `Variant = 1`
pub discriminant: Option<(Token![=], Expr)>,
}
}
ast_enum_of_structs! {
/// Data stored within an enum variant or struct.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Fields {
/// Named fields of a struct or struct variant such as `Point { x: f64,
/// y: f64 }`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub Named(FieldsNamed {
pub brace_token: token::Brace,
pub named: Punctuated<Field, Token![,]>,
}),
/// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub Unnamed(FieldsUnnamed {
pub paren_token: token::Paren,
pub unnamed: Punctuated<Field, Token![,]>,
}),
/// Unit struct or unit variant such as `None`.
pub Unit,
}
}
impl Fields {
/// Get an iterator over the [`Field`] items in this object. This iterator
/// can be used to iterate over a named or unnamed struct or variant's
/// fields uniformly.
///
/// [`Field`]: struct.Field.html
pub fn iter(&self) -> punctuated::Iter<Field, Token![,]> {
match *self {
Fields::Unit => punctuated::Iter::private_empty(),
Fields::Named(ref f) => f.named.iter(),
Fields::Unnamed(ref f) => f.unnamed.iter(),
}
}
}
impl<'a> IntoIterator for &'a Fields {
type Item = &'a Field;
type IntoIter = punctuated::Iter<'a, Field, Token![,]>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
ast_struct! {
/// A field of a struct or enum variant.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
pub struct Field {
/// Attributes tagged on the field.
pub attrs: Vec<Attribute>,
/// Visibility of the field.
pub vis: Visibility,
/// Name of the field, if any.
///
/// Fields of tuple structs have no names.
pub ident: Option<Ident>,
pub colon_token: Option<Token![:]>,
/// Type of the field.
pub ty: Type,
}
}
ast_enum_of_structs! {
/// The visibility level of an item: inherited or `pub` or
/// `pub(restricted)`.
///
/// *This type is available if Syn is built with the `"derive"` or `"full"`
/// feature.*
///
/// # Syntax tree enum
///
/// This type is a [syntax tree enum].
///
/// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
pub enum Visibility {
/// A public visibility level: `pub`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub Public(VisPublic {
pub pub_token: Token![pub],
}),
/// A crate-level visibility: `pub(crate)`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub Crate(VisCrate {
pub pub_token: Token![pub],
pub paren_token: token::Paren,
pub crate_token: Token![crate],
}),
/// A visibility level restricted to some path: `pub(self)` or
/// `pub(super)` or `pub(in some::module)`.
///
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub Restricted(VisRestricted {
pub pub_token: Token![pub],
pub paren_token: token::Paren,
pub in_token: Option<Token![in]>,
pub path: Box<Path>,
}),
/// An inherited visibility, which usually means private.
pub Inherited,
}
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use synom::Synom;
impl Synom for Variant {
named!(parse -> Self, do_parse!(
attrs: many0!(Attribute::parse_outer) >>
id: syn!(Ident) >>
fields: alt!(
syn!(FieldsNamed) => { Fields::Named }
|
syn!(FieldsUnnamed) => { Fields::Unnamed }
|
epsilon!() => { |_| Fields::Unit }
) >>
disr: option!(tuple!(punct!(=), syn!(Expr))) >>
(Variant {
ident: id,
attrs: attrs,
fields: fields,
discriminant: disr,
})
));
fn description() -> Option<&'static str> {
Some("enum variant")
}
}
impl Synom for FieldsNamed {
named!(parse -> Self, map!(
braces!(call!(Punctuated::parse_terminated_with, Field::parse_named)),
|(brace, fields)| FieldsNamed {
brace_token: brace,
named: fields,
}
));
fn description() -> Option<&'static str> {
Some("named fields in a struct or struct variant")
}
}
impl Synom for FieldsUnnamed {
named!(parse -> Self, map!(
parens!(call!(Punctuated::parse_terminated_with, Field::parse_unnamed)),
|(paren, fields)| FieldsUnnamed {
paren_token: paren,
unnamed: fields,
}
));
fn description() -> Option<&'static str> {
Some("unnamed fields in a tuple struct or tuple variant")
}
}
impl Field {
named!(pub parse_named -> Self, do_parse!(
attrs: many0!(Attribute::parse_outer) >>
vis: syn!(Visibility) >>
id: syn!(Ident) >>
colon: punct!(:) >>
ty: syn!(Type) >>
(Field {
ident: Some(id),
vis: vis,
attrs: attrs,
ty: ty,
colon_token: Some(colon),
})
));
named!(pub parse_unnamed -> Self, do_parse!(
attrs: many0!(Attribute::parse_outer) >>
vis: syn!(Visibility) >>
ty: syn!(Type) >>
(Field {
ident: None,
colon_token: None,
vis: vis,
attrs: attrs,
ty: ty,
})
));
}
impl Synom for Visibility {
named!(parse -> Self, alt!(
do_parse!(
pub_token: keyword!(pub) >>
other: parens!(keyword!(crate)) >>
(Visibility::Crate(VisCrate {
pub_token: pub_token,
paren_token: other.0,
crate_token: other.1,
}))
)
|
keyword!(crate) => { |tok| {
Visibility::Crate(VisCrate {
pub_token: <Token![pub]>::default(),
paren_token: token::Paren::default(),
crate_token: tok,
})
} }
|
do_parse!(
pub_token: keyword!(pub) >>
other: parens!(keyword!(self)) >>
(Visibility::Restricted(VisRestricted {
pub_token: pub_token,
paren_token: other.0,
in_token: None,
path: Box::new(other.1.into()),
}))
)
|
do_parse!(
pub_token: keyword!(pub) >>
other: parens!(keyword!(super)) >>
(Visibility::Restricted(VisRestricted {
pub_token: pub_token,
paren_token: other.0,
in_token: None,
path: Box::new(other.1.into()),
}))
)
|
do_parse!(
pub_token: keyword!(pub) >>
other: parens!(do_parse!(
in_tok: keyword!(in) >>
restricted: call!(Path::parse_mod_style) >>
(in_tok, restricted)
)) >>
(Visibility::Restricted(VisRestricted {
pub_token: pub_token,
paren_token: other.0,
in_token: Some((other.1).0),
path: Box::new((other.1).1),
}))
)
|
keyword!(pub) => { |tok| {
Visibility::Public(VisPublic {
pub_token: tok,
})
} }
|
epsilon!() => { |_| Visibility::Inherited }
));
fn description() -> Option<&'static str> {
Some("visibility qualifier such as `pub`")
}
}
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use quote::{ToTokens, Tokens};
impl ToTokens for Variant {
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append_all(&self.attrs);
self.ident.to_tokens(tokens);
self.fields.to_tokens(tokens);
if let Some((ref eq_token, ref disc)) = self.discriminant {
eq_token.to_tokens(tokens);
disc.to_tokens(tokens);
}
}
}
impl ToTokens for FieldsNamed {
fn to_tokens(&self, tokens: &mut Tokens) {
self.brace_token.surround(tokens, |tokens| {
self.named.to_tokens(tokens);
});
}
}
impl ToTokens for FieldsUnnamed {
fn to_tokens(&self, tokens: &mut Tokens) {
self.paren_token.surround(tokens, |tokens| {
self.unnamed.to_tokens(tokens);
});
}
}
impl ToTokens for Field {
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append_all(&self.attrs);
self.vis.to_tokens(tokens);
if let Some(ref ident) = self.ident {
ident.to_tokens(tokens);
TokensOrDefault(&self.colon_token).to_tokens(tokens);
}
self.ty.to_tokens(tokens);
}
}
impl ToTokens for VisPublic {
fn to_tokens(&self, tokens: &mut Tokens) {
self.pub_token.to_tokens(tokens)
}
}
impl ToTokens for VisCrate {
fn to_tokens(&self, tokens: &mut Tokens) {
self.pub_token.to_tokens(tokens);
self.paren_token.surround(tokens, |tokens| {
self.crate_token.to_tokens(tokens);
})
}
}
impl ToTokens for VisRestricted {
fn to_tokens(&self, tokens: &mut Tokens) {
self.pub_token.to_tokens(tokens);
self.paren_token.surround(tokens, |tokens| {
// XXX: If we have a path which is not "self" or "super",
// automatically add the "in" token.
self.in_token.to_tokens(tokens);
self.path.to_tokens(tokens);
});
}
}
}