use super::*;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Ty {
Slice(Box<Ty>),
Array(Box<Ty>, ConstExpr),
Ptr(Box<MutTy>),
Rptr(Option<Lifetime>, Box<MutTy>),
BareFn(Box<BareFnTy>),
Never,
Tup(Vec<Ty>),
Path(Option<QSelf>, Path),
TraitObject(Vec<TyParamBound>),
ImplTrait(Vec<TyParamBound>),
Paren(Box<Ty>),
Infer,
Mac(Mac),
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct MutTy {
pub ty: Ty,
pub mutability: Mutability,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Mutability {
Mutable,
Immutable,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Path {
pub global: bool,
pub segments: Vec<PathSegment>,
}
impl<T> From<T> for Path
where T: Into<PathSegment>
{
fn from(segment: T) -> Self {
Path {
global: false,
segments: vec![segment.into()],
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PathSegment {
pub ident: Ident,
pub parameters: PathParameters,
}
impl<T> From<T> for PathSegment
where T: Into<Ident>
{
fn from(ident: T) -> Self {
PathSegment {
ident: ident.into(),
parameters: PathParameters::none(),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum PathParameters {
AngleBracketed(AngleBracketedParameterData),
Parenthesized(ParenthesizedParameterData),
}
impl PathParameters {
pub fn none() -> Self {
PathParameters::AngleBracketed(AngleBracketedParameterData::default())
}
pub fn is_empty(&self) -> bool {
match *self {
PathParameters::AngleBracketed(ref bracketed) => {
bracketed.lifetimes.is_empty() && bracketed.types.is_empty() &&
bracketed.bindings.is_empty()
}
PathParameters::Parenthesized(_) => false,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
pub struct AngleBracketedParameterData {
pub lifetimes: Vec<Lifetime>,
pub types: Vec<Ty>,
pub bindings: Vec<TypeBinding>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TypeBinding {
pub ident: Ident,
pub ty: Ty,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ParenthesizedParameterData {
pub inputs: Vec<Ty>,
pub output: Option<Ty>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PolyTraitRef {
pub bound_lifetimes: Vec<LifetimeDef>,
pub trait_ref: Path,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct QSelf {
pub ty: Box<Ty>,
pub position: usize,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct BareFnTy {
pub unsafety: Unsafety,
pub abi: Option<Abi>,
pub lifetimes: Vec<LifetimeDef>,
pub inputs: Vec<BareFnArg>,
pub output: FunctionRetTy,
pub variadic: bool,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Unsafety {
Unsafe,
Normal,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Abi {
Named(String),
Rust,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct BareFnArg {
pub name: Option<Ident>,
pub ty: Ty,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum FunctionRetTy {
Default,
Ty(Ty),
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use {TyParamBound, TraitBoundModifier};
#[cfg(feature = "full")]
use ConstExpr;
#[cfg(feature = "full")]
use constant::parsing::const_expr;
#[cfg(feature = "full")]
use expr::parsing::expr;
use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
use ident::parsing::ident;
use lit::parsing::quoted_string;
use mac::parsing::mac;
use std::str;
named!(pub ty -> Ty, alt!(
ty_paren
|
ty_mac
|
ty_path
|
ty_vec
|
ty_array
|
ty_ptr
|
ty_rptr
|
ty_bare_fn
|
ty_never
|
ty_tup
|
ty_poly_trait_ref
|
ty_impl_trait
));
named!(ty_mac -> Ty, map!(mac, Ty::Mac));
named!(ty_vec -> Ty, do_parse!(
punct!("[") >>
elem: ty >>
punct!("]") >>
(Ty::Slice(Box::new(elem)))
));
named!(ty_array -> Ty, do_parse!(
punct!("[") >>
elem: ty >>
punct!(";") >>
len: array_len >>
punct!("]") >>
(Ty::Array(Box::new(elem), len))
));
#[cfg(not(feature = "full"))]
use constant::parsing::const_expr as array_len;
#[cfg(feature = "full")]
named!(array_len -> ConstExpr, alt!(
terminated!(const_expr, after_array_len)
|
terminated!(expr, after_array_len) => { ConstExpr::Other }
));
#[cfg(feature = "full")]
named!(after_array_len -> &str, peek!(punct!("]")));
named!(ty_ptr -> Ty, do_parse!(
punct!("*") >>
mutability: alt!(
keyword!("const") => { |_| Mutability::Immutable }
|
keyword!("mut") => { |_| Mutability::Mutable }
) >>
target: ty >>
(Ty::Ptr(Box::new(MutTy {
ty: target,
mutability: mutability,
})))
));
named!(ty_rptr -> Ty, do_parse!(
punct!("&") >>
life: option!(lifetime) >>
mutability: mutability >>
target: ty >>
(Ty::Rptr(life, Box::new(MutTy {
ty: target,
mutability: mutability,
})))
));
named!(ty_bare_fn -> Ty, do_parse!(
lifetimes: opt_vec!(do_parse!(
keyword!("for") >>
punct!("<") >>
lifetimes: terminated_list!(punct!(","), lifetime_def) >>
punct!(">") >>
(lifetimes)
)) >>
unsafety: unsafety >>
abi: option!(abi) >>
keyword!("fn") >>
punct!("(") >>
inputs: separated_list!(punct!(","), fn_arg) >>
trailing_comma: option!(punct!(",")) >>
variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
punct!(")") >>
output: option!(preceded!(
punct!("->"),
ty
)) >>
(Ty::BareFn(Box::new(BareFnTy {
unsafety: unsafety,
abi: abi,
lifetimes: lifetimes,
inputs: inputs,
output: match output {
Some(ty) => FunctionRetTy::Ty(ty),
None => FunctionRetTy::Default,
},
variadic: variadic.is_some(),
})))
));
named!(ty_never -> Ty, map!(punct!("!"), |_| Ty::Never));
named!(ty_tup -> Ty, do_parse!(
punct!("(") >>
elems: terminated_list!(punct!(","), ty) >>
punct!(")") >>
(Ty::Tup(elems))
));
named!(ty_path -> Ty, do_parse!(
qpath: qpath >>
parenthesized: cond!(
qpath.1.segments.last().unwrap().parameters == PathParameters::none(),
option!(parenthesized_parameter_data)
) >>
bounds: many0!(preceded!(punct!("+"), ty_param_bound)) >>
({
let (qself, mut path) = qpath;
if let Some(Some(parenthesized)) = parenthesized {
path.segments.last_mut().unwrap().parameters = parenthesized;
}
if bounds.is_empty() {
Ty::Path(qself, path)
} else {
let path = TyParamBound::Trait(
PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: path,
},
TraitBoundModifier::None,
);
let bounds = Some(path).into_iter().chain(bounds).collect();
Ty::TraitObject(bounds)
}
})
));
named!(parenthesized_parameter_data -> PathParameters, do_parse!(
punct!("(") >>
inputs: terminated_list!(punct!(","), ty) >>
punct!(")") >>
output: option!(preceded!(
punct!("->"),
ty
)) >>
(PathParameters::Parenthesized(
ParenthesizedParameterData {
inputs: inputs,
output: output,
},
))
));
named!(pub qpath -> (Option<QSelf>, Path), alt!(
map!(path, |p| (None, p))
|
do_parse!(
punct!("<") >>
this: map!(ty, Box::new) >>
path: option!(preceded!(
keyword!("as"),
path
)) >>
punct!(">") >>
punct!("::") >>
rest: separated_nonempty_list!(punct!("::"), path_segment) >>
({
match path {
Some(mut path) => {
let pos = path.segments.len();
path.segments.extend(rest);
(Some(QSelf { ty: this, position: pos }), path)
}
None => {
(Some(QSelf { ty: this, position: 0 }), Path {
global: false,
segments: rest,
})
}
}
})
)
|
map!(keyword!("self"), |_| (None, "self".into()))
));
named!(ty_poly_trait_ref -> Ty, map!(
separated_nonempty_list!(punct!("+"), ty_param_bound),
Ty::TraitObject
));
named!(ty_impl_trait -> Ty, do_parse!(
keyword!("impl") >>
elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
(Ty::ImplTrait(elem))
));
named!(ty_paren -> Ty, do_parse!(
punct!("(") >>
elem: ty >>
punct!(")") >>
(Ty::Paren(Box::new(elem)))
));
named!(pub mutability -> Mutability, alt!(
keyword!("mut") => { |_| Mutability::Mutable }
|
epsilon!() => { |_| Mutability::Immutable }
));
named!(pub path -> Path, do_parse!(
global: option!(punct!("::")) >>
segments: separated_nonempty_list!(punct!("::"), path_segment) >>
(Path {
global: global.is_some(),
segments: segments,
})
));
named!(path_segment -> PathSegment, alt!(
do_parse!(
id: option!(ident) >>
punct!("<") >>
lifetimes: separated_list!(punct!(","), lifetime) >>
types: opt_vec!(preceded!(
cond!(!lifetimes.is_empty(), punct!(",")),
separated_nonempty_list!(
punct!(","),
terminated!(ty, not!(punct!("=")))
)
)) >>
bindings: opt_vec!(preceded!(
cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
separated_nonempty_list!(punct!(","), type_binding)
)) >>
cond!(!lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty(), option!(punct!(","))) >>
punct!(">") >>
(PathSegment {
ident: id.unwrap_or_else(|| "".into()),
parameters: PathParameters::AngleBracketed(
AngleBracketedParameterData {
lifetimes: lifetimes,
types: types,
bindings: bindings,
}
),
})
)
|
map!(ident, Into::into)
|
map!(alt!(
keyword!("super")
|
keyword!("self")
|
keyword!("Self")
), Into::into)
));
named!(type_binding -> TypeBinding, do_parse!(
id: ident >>
punct!("=") >>
ty: ty >>
(TypeBinding {
ident: id,
ty: ty,
})
));
named!(pub poly_trait_ref -> PolyTraitRef, do_parse!(
bound_lifetimes: bound_lifetimes >>
trait_ref: path >>
parenthesized: option!(cond_reduce!(
trait_ref.segments.last().unwrap().parameters == PathParameters::none(),
parenthesized_parameter_data
)) >>
({
let mut trait_ref = trait_ref;
if let Some(parenthesized) = parenthesized {
trait_ref.segments.last_mut().unwrap().parameters = parenthesized;
}
PolyTraitRef {
bound_lifetimes: bound_lifetimes,
trait_ref: trait_ref,
}
})
));
named!(pub fn_arg -> BareFnArg, do_parse!(
name: option!(do_parse!(
name: ident >>
punct!(":") >>
not!(tag!(":")) >>
(name)
)) >>
ty: ty >>
(BareFnArg {
name: name,
ty: ty,
})
));
named!(pub unsafety -> Unsafety, alt!(
keyword!("unsafe") => { |_| Unsafety::Unsafe }
|
epsilon!() => { |_| Unsafety::Normal }
));
named!(pub abi -> Abi, do_parse!(
keyword!("extern") >>
name: option!(quoted_string) >>
(match name {
Some(name) => Abi::Named(name),
None => Abi::Rust,
})
));
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use quote::{Tokens, ToTokens};
impl ToTokens for Ty {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
Ty::Slice(ref inner) => {
tokens.append("[");
inner.to_tokens(tokens);
tokens.append("]");
}
Ty::Array(ref inner, ref len) => {
tokens.append("[");
inner.to_tokens(tokens);
tokens.append(";");
len.to_tokens(tokens);
tokens.append("]");
}
Ty::Ptr(ref target) => {
tokens.append("*");
match target.mutability {
Mutability::Mutable => tokens.append("mut"),
Mutability::Immutable => tokens.append("const"),
}
target.ty.to_tokens(tokens);
}
Ty::Rptr(ref lifetime, ref target) => {
tokens.append("&");
lifetime.to_tokens(tokens);
target.mutability.to_tokens(tokens);
target.ty.to_tokens(tokens);
}
Ty::BareFn(ref func) => {
func.to_tokens(tokens);
}
Ty::Never => {
tokens.append("!");
}
Ty::Tup(ref elems) => {
tokens.append("(");
tokens.append_separated(elems, ",");
if elems.len() == 1 {
tokens.append(",");
}
tokens.append(")");
}
Ty::Path(None, ref path) => {
path.to_tokens(tokens);
}
Ty::Path(Some(ref qself), ref path) => {
tokens.append("<");
qself.ty.to_tokens(tokens);
if qself.position > 0 {
tokens.append("as");
for (i, segment) in path.segments
.iter()
.take(qself.position)
.enumerate() {
if i > 0 || path.global {
tokens.append("::");
}
segment.to_tokens(tokens);
}
}
tokens.append(">");
for segment in path.segments.iter().skip(qself.position) {
tokens.append("::");
segment.to_tokens(tokens);
}
}
Ty::TraitObject(ref bounds) => {
tokens.append_separated(bounds, "+");
}
Ty::ImplTrait(ref bounds) => {
tokens.append("impl");
tokens.append_separated(bounds, "+");
}
Ty::Paren(ref inner) => {
tokens.append("(");
inner.to_tokens(tokens);
tokens.append(")");
}
Ty::Infer => {
tokens.append("_");
}
Ty::Mac(ref mac) => mac.to_tokens(tokens),
}
}
}
impl ToTokens for Mutability {
fn to_tokens(&self, tokens: &mut Tokens) {
if let Mutability::Mutable = *self {
tokens.append("mut");
}
}
}
impl ToTokens for Path {
fn to_tokens(&self, tokens: &mut Tokens) {
for (i, segment) in self.segments.iter().enumerate() {
if i > 0 || self.global {
tokens.append("::");
}
segment.to_tokens(tokens);
}
}
}
impl ToTokens for PathSegment {
fn to_tokens(&self, tokens: &mut Tokens) {
self.ident.to_tokens(tokens);
if self.ident.as_ref().is_empty() && self.parameters.is_empty() {
tokens.append("<");
tokens.append(">");
} else {
self.parameters.to_tokens(tokens);
}
}
}
impl ToTokens for PathParameters {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
PathParameters::AngleBracketed(ref parameters) => {
parameters.to_tokens(tokens);
}
PathParameters::Parenthesized(ref parameters) => {
parameters.to_tokens(tokens);
}
}
}
}
impl ToTokens for AngleBracketedParameterData {
fn to_tokens(&self, tokens: &mut Tokens) {
let has_lifetimes = !self.lifetimes.is_empty();
let has_types = !self.types.is_empty();
let has_bindings = !self.bindings.is_empty();
if !has_lifetimes && !has_types && !has_bindings {
return;
}
tokens.append("<");
let mut first = true;
for lifetime in &self.lifetimes {
if !first {
tokens.append(",");
}
lifetime.to_tokens(tokens);
first = false;
}
for ty in &self.types {
if !first {
tokens.append(",");
}
ty.to_tokens(tokens);
first = false;
}
for binding in &self.bindings {
if !first {
tokens.append(",");
}
binding.to_tokens(tokens);
first = false;
}
tokens.append(">");
}
}
impl ToTokens for TypeBinding {
fn to_tokens(&self, tokens: &mut Tokens) {
self.ident.to_tokens(tokens);
tokens.append("=");
self.ty.to_tokens(tokens);
}
}
impl ToTokens for ParenthesizedParameterData {
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append("(");
tokens.append_separated(&self.inputs, ",");
tokens.append(")");
if let Some(ref output) = self.output {
tokens.append("->");
output.to_tokens(tokens);
}
}
}
impl ToTokens for PolyTraitRef {
fn to_tokens(&self, tokens: &mut Tokens) {
if !self.bound_lifetimes.is_empty() {
tokens.append("for");
tokens.append("<");
tokens.append_separated(&self.bound_lifetimes, ",");
tokens.append(">");
}
self.trait_ref.to_tokens(tokens);
}
}
impl ToTokens for BareFnTy {
fn to_tokens(&self, tokens: &mut Tokens) {
if !self.lifetimes.is_empty() {
tokens.append("for");
tokens.append("<");
tokens.append_separated(&self.lifetimes, ",");
tokens.append(">");
}
self.unsafety.to_tokens(tokens);
self.abi.to_tokens(tokens);
tokens.append("fn");
tokens.append("(");
tokens.append_separated(&self.inputs, ",");
if self.variadic {
if !self.inputs.is_empty() {
tokens.append(",");
}
tokens.append("...");
}
tokens.append(")");
if let FunctionRetTy::Ty(ref ty) = self.output {
tokens.append("->");
ty.to_tokens(tokens);
}
}
}
impl ToTokens for BareFnArg {
fn to_tokens(&self, tokens: &mut Tokens) {
if let Some(ref name) = self.name {
name.to_tokens(tokens);
tokens.append(":");
}
self.ty.to_tokens(tokens);
}
}
impl ToTokens for Unsafety {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
Unsafety::Unsafe => tokens.append("unsafe"),
Unsafety::Normal => {
}
}
}
}
impl ToTokens for Abi {
fn to_tokens(&self, tokens: &mut Tokens) {
tokens.append("extern");
match *self {
Abi::Named(ref named) => named.to_tokens(tokens),
Abi::Rust => {}
}
}
}
}