Parse types
diff --git a/src/attr.rs b/src/attr.rs
index 73af023..7b1cfa9 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -427,7 +427,7 @@
pound: punct!(#) >>
bang: punct!(!) >>
path_and_tts: brackets!(tuple!(
- call!(Path::parse_mod_style),
+ call!(Path::old_parse_mod_style),
syn!(TokenStream),
)) >>
({
@@ -465,7 +465,7 @@
do_parse!(
pound: punct!(#) >>
path_and_tts: brackets!(tuple!(
- call!(Path::parse_mod_style),
+ call!(Path::old_parse_mod_style),
syn!(TokenStream),
)) >>
({
diff --git a/src/data.rs b/src/data.rs
index 36ba136..c8e9e06 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -241,7 +241,7 @@
vis: input.parse()?,
ident: Some(input.parse()?),
colon_token: Some(input.parse()?),
- ty: input.parse_synom(Type::parse)?,
+ ty: input.parse()?,
})
}
@@ -251,7 +251,7 @@
vis: input.parse()?,
ident: None,
colon_token: None,
- ty: input.parse_synom(Type::parse)?,
+ ty: input.parse()?,
})
}
}
@@ -292,7 +292,7 @@
pub_token: pub_token,
paren_token: parenthesized!(content in input),
in_token: Some(content.parse()?),
- path: Box::new(content.parse_synom(Path::parse_mod_style)?),
+ path: Box::new(content.parse_synom(Path::old_parse_mod_style)?),
}));
}
}
diff --git a/src/expr.rs b/src/expr.rs
index 540c994..bb8b469 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1029,7 +1029,7 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use path::parsing::mod_style_path_segment;
+ use path::parsing::old_mod_style_path_segment;
#[cfg(feature = "full")]
use path::parsing::ty_no_eq_after;
@@ -1347,7 +1347,7 @@
as_: keyword!(as) >>
// We can't accept `A + B` in cast expressions, as it's
// ambiguous with the + expression.
- ty: call!(Type::without_plus) >>
+ ty: shim!(Type::without_plus) >>
({
e = ExprCast {
attrs: Vec::new(),
@@ -1362,7 +1362,7 @@
colon: punct!(:) >>
// We can't accept `A + B` in cast expressions, as it's
// ambiguous with the + expression.
- ty: call!(Type::without_plus) >>
+ ty: shim!(Type::without_plus) >>
({
e = ExprType {
attrs: Vec::new(),
@@ -1384,7 +1384,7 @@
as_: keyword!(as) >>
// We can't accept `A + B` in cast expressions, as it's
// ambiguous with the + expression.
- ty: call!(Type::without_plus) >>
+ ty: shim!(Type::without_plus) >>
({
e = ExprCast {
attrs: Vec::new(),
@@ -1721,7 +1721,7 @@
#[cfg(feature = "full")]
impl Synom for ExprGroup {
named!(parse -> Self, do_parse!(
- e: grouped!(syn!(Expr)) >>
+ e: old_grouped!(syn!(Expr)) >>
(ExprGroup {
attrs: Vec::new(),
expr: Box::new(e.1),
@@ -2542,7 +2542,7 @@
})
)
|
- mod_style_path_segment
+ old_mod_style_path_segment
));
named!(qpath -> (Option<QSelf>, Path), alt!(
@@ -2651,7 +2651,7 @@
#[cfg(feature = "full")]
named!(stmt_mac -> Stmt, do_parse!(
attrs: many0!(Attribute::old_parse_outer) >>
- what: call!(Path::parse_mod_style) >>
+ what: call!(Path::old_parse_mod_style) >>
bang: punct!(!) >>
// Only parse braces here; paren and bracket will get parsed as
// expression statements
diff --git a/src/generics.rs b/src/generics.rs
index bfcc5a5..7d96e78 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -670,7 +670,7 @@
},
default: {
if has_default {
- Some(input.parse_synom(Type::parse)?)
+ Some(input.parse()?)
} else {
None
}
@@ -737,7 +737,7 @@
const_token: input.parse()?,
ident: input.parse()?,
colon_token: input.parse()?,
- ty: input.parse_synom(Type::parse)?,
+ ty: input.parse()?,
eq_token: {
if input.peek(Token![=]) {
let eq_token = input.parse()?;
@@ -822,7 +822,7 @@
} else {
Ok(WherePredicate::Type(PredicateType {
lifetimes: input.parse()?,
- bounded_ty: input.parse_synom(Type::parse)?,
+ bounded_ty: input.parse()?,
colon_token: input.parse()?,
bounds: {
let mut bounds = Punctuated::new();
diff --git a/src/group.rs b/src/group.rs
index 28f3333..1f46f2b 100644
--- a/src/group.rs
+++ b/src/group.rs
@@ -19,8 +19,13 @@
pub content: ParseBuffer<'a>,
}
+pub struct Group<'a> {
+ pub token: token::Group,
+ pub content: ParseBuffer<'a>,
+}
+
impl<'a> ParseBuffer<'a> {
- fn parse_group(&self, delimiter: Delimiter) -> Result<(Span, ParseBuffer<'a>)> {
+ fn parse_delimited(&self, delimiter: Delimiter) -> Result<(Span, ParseBuffer<'a>)> {
self.step_cursor(|cursor| {
if let Some((content, span, rest)) = cursor.group(delimiter) {
let content =
@@ -31,7 +36,7 @@
Delimiter::Parenthesis => "expected parentheses",
Delimiter::Brace => "expected curly braces",
Delimiter::Bracket => "expected square brackets",
- Delimiter::None => unreachable!(),
+ Delimiter::None => "expected invisible group",
};
Err(cursor.error(message))
}
@@ -41,7 +46,7 @@
// Not public API.
#[doc(hidden)]
pub fn parse_parens(&self) -> Result<Parens<'a>> {
- self.parse_group(Delimiter::Parenthesis)
+ self.parse_delimited(Delimiter::Parenthesis)
.map(|(span, content)| Parens {
token: token::Paren(span),
content: content,
@@ -51,7 +56,7 @@
// Not public API.
#[doc(hidden)]
pub fn parse_braces(&self) -> Result<Braces<'a>> {
- self.parse_group(Delimiter::Brace)
+ self.parse_delimited(Delimiter::Brace)
.map(|(span, content)| Braces {
token: token::Brace(span),
content: content,
@@ -61,12 +66,22 @@
// Not public API.
#[doc(hidden)]
pub fn parse_brackets(&self) -> Result<Brackets<'a>> {
- self.parse_group(Delimiter::Bracket)
+ self.parse_delimited(Delimiter::Bracket)
.map(|(span, content)| Brackets {
token: token::Bracket(span),
content: content,
})
}
+
+ // Not public API.
+ #[doc(hidden)]
+ pub fn parse_group(&self) -> Result<Group<'a>> {
+ self.parse_delimited(Delimiter::None)
+ .map(|(span, content)| Group {
+ token: token::Group(span),
+ content: content,
+ })
+ }
}
/// Parse a set of parentheses and expose their content to subsequent parsers.
@@ -152,3 +167,19 @@
}
};
}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! grouped {
+ ($content:ident in $cursor:expr) => {
+ match $crate::parse::ParseBuffer::parse_group(&$cursor) {
+ $crate::export::Ok(group) => {
+ $content = group.content;
+ group.token
+ }
+ $crate::export::Err(error) => {
+ return $crate::export::Err(error);
+ }
+ }
+ };
+}
diff --git a/src/item.rs b/src/item.rs
index 569c1c8..9e28808 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -806,7 +806,7 @@
impl_synom!(ItemMacro "macro item" do_parse!(
attrs: many0!(Attribute::old_parse_outer) >>
- what: call!(Path::parse_mod_style) >>
+ what: call!(Path::old_parse_mod_style) >>
bang: punct!(!) >>
ident: option!(syn!(Ident)) >>
body: call!(tt::delimited) >>
diff --git a/src/lit.rs b/src/lit.rs
index a25d2a3..908ff89 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -425,7 +425,6 @@
use super::*;
use parse::{Parse, ParseStream, Result};
use parse_error;
- use synom::Synom;
impl Parse for Lit {
fn parse(input: ParseStream) -> Result<Self> {
@@ -460,54 +459,75 @@
}
}
- impl_synom!(LitStr "string literal" switch!(
- syn!(Lit),
- Lit::Str(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitStr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Str(lit) => Ok(lit),
+ _ => Err(head.error("expected string literal")),
+ }
+ }
+ }
- impl_synom!(LitByteStr "byte string literal" switch!(
- syn!(Lit),
- Lit::ByteStr(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitByteStr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::ByteStr(lit) => Ok(lit),
+ _ => Err(head.error("expected byte string literal")),
+ }
+ }
+ }
- impl_synom!(LitByte "byte literal" switch!(
- syn!(Lit),
- Lit::Byte(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitByte {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Byte(lit) => Ok(lit),
+ _ => Err(head.error("expected byte literal")),
+ }
+ }
+ }
- impl_synom!(LitChar "character literal" switch!(
- syn!(Lit),
- Lit::Char(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitChar {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Char(lit) => Ok(lit),
+ _ => Err(head.error("expected character literal")),
+ }
+ }
+ }
- impl_synom!(LitInt "integer literal" switch!(
- syn!(Lit),
- Lit::Int(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitInt {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Int(lit) => Ok(lit),
+ _ => Err(head.error("expected integer literal")),
+ }
+ }
+ }
- impl_synom!(LitFloat "floating point literal" switch!(
- syn!(Lit),
- Lit::Float(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitFloat {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Float(lit) => Ok(lit),
+ _ => Err(head.error("expected floating point literal")),
+ }
+ }
+ }
- impl_synom!(LitBool "boolean literal" switch!(
- syn!(Lit),
- Lit::Bool(lit) => value!(lit)
- |
- _ => reject!()
- ));
+ impl Parse for LitBool {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Bool(lit) => Ok(lit),
+ _ => Err(head.error("expected boolean literal")),
+ }
+ }
+ }
}
#[cfg(feature = "printing")]
diff --git a/src/mac.rs b/src/mac.rs
index a9219fe..b08c8a1 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -8,8 +8,12 @@
use super::*;
use proc_macro2::TokenStream;
+#[cfg(feature = "parsing")]
+use proc_macro2::{Delimiter, TokenTree};
use token::{Brace, Bracket, Paren};
+#[cfg(feature = "parsing")]
+use parse::{ParseStream, Result};
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};
#[cfg(feature = "extra-traits")]
@@ -67,26 +71,44 @@
}
#[cfg(feature = "parsing")]
+pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
+ input.step_cursor(|cursor| {
+ if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
+ let span = g.span();
+ let delimiter = match g.delimiter() {
+ Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
+ Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
+ Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
+ Delimiter::None => {
+ return Err(cursor.error("expected delimiter"));
+ }
+ };
+ Ok(((delimiter, g.stream().clone()), rest))
+ } else {
+ Err(cursor.error("expected delimiter"))
+ }
+ })
+}
+
+#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use synom::Synom;
+ use parse::{Parse, ParseStream, Result};
- impl Synom for Macro {
- named!(parse -> Self, do_parse!(
- what: call!(Path::parse_mod_style) >>
- bang: punct!(!) >>
- body: call!(tt::delimited) >>
- (Macro {
- path: what,
- bang_token: bang,
- delimiter: body.0,
- tts: body.1,
+ impl Parse for Macro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let tts;
+ Ok(Macro {
+ path: input.call(Path::parse_mod_style)?,
+ bang_token: input.parse()?,
+ delimiter: {
+ let (delimiter, content) = parse_delimiter(input)?;
+ tts = content;
+ delimiter
+ },
+ tts: tts,
})
- ));
-
- fn description() -> Option<&'static str> {
- Some("macro invocation")
}
}
}
diff --git a/src/macros.rs b/src/macros.rs
index f4e7d0a..5966e38 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -179,10 +179,7 @@
($($rest:tt)*) => (ast_struct! { $($rest)* });
}
-#[cfg(all(
- feature = "parsing",
- any(feature = "full", feature = "derive")
-))]
+#[cfg(all(feature = "parsing", feature = "full"))]
macro_rules! impl_synom {
($t:ident $description:tt $($parser:tt)+) => {
impl Synom for $t {
diff --git a/src/parse.rs b/src/parse.rs
index c87ad9f..64f972d 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -115,7 +115,9 @@
return false;
}
let ahead = self.fork();
- ahead.step_cursor(|cursor| Ok(cursor.token_tree().unwrap())).unwrap();
+ ahead
+ .step_cursor(|cursor| Ok(cursor.token_tree().unwrap()))
+ .unwrap();
ahead.peek(token)
}
@@ -124,8 +126,12 @@
return false;
}
let ahead = self.fork();
- ahead.step_cursor(|cursor| Ok(cursor.token_tree().unwrap())).unwrap();
- ahead.step_cursor(|cursor| Ok(cursor.token_tree().unwrap())).unwrap();
+ ahead
+ .step_cursor(|cursor| Ok(cursor.token_tree().unwrap()))
+ .unwrap();
+ ahead
+ .step_cursor(|cursor| Ok(cursor.token_tree().unwrap()))
+ .unwrap();
ahead.peek(token)
}
@@ -216,6 +222,12 @@
}
}
+impl<T: Parse> Parse for Box<T> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.parse().map(Box::new)
+ }
+}
+
impl<T: Parse + Token> Parse for Option<T> {
fn parse(input: ParseStream) -> Result<Self> {
if T::peek(&input.lookahead1()) {
diff --git a/src/parsers.rs b/src/parsers.rs
index 400c0ca..c3c638b 100644
--- a/src/parsers.rs
+++ b/src/parsers.rs
@@ -1417,7 +1417,7 @@
// Not public API.
#[doc(hidden)]
#[macro_export]
-macro_rules! grouped {
+macro_rules! old_grouped {
($i:expr, $submac:ident!( $($args:tt)* )) => {
$crate::token::Group::parse($i, |i| $submac!(i, $($args)*))
};
@@ -1426,3 +1426,19 @@
grouped!($i, call!($f));
};
}
+
+macro_rules! shim {
+ ($i:expr, $parser:expr $(, $args:expr)*) => {{
+ let unexpected = ::std::rc::Rc::new(::std::cell::Cell::new(None));
+ let state = ::parse::ParseBuffer::new(::proc_macro2::Span::call_site(), $i, unexpected);
+ match $parser(&state $(, $args)*) {
+ Ok(node) => {
+ match state.check_unexpected() {
+ Ok(()) => Ok((node, state.cursor())),
+ Err(err) => Err(err),
+ }
+ }
+ Err(err) => Err(err),
+ }
+ }};
+}
diff --git a/src/path.rs b/src/path.rs
index 12c7549..c2ad34a 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -229,7 +229,6 @@
use super::*;
use parse::{Parse, ParseStream, Result};
use synom::ext::IdentExt;
- use synom::Synom;
impl Parse for Path {
fn parse(input: ParseStream) -> Result<Self> {
@@ -303,7 +302,7 @@
Ok(ParenthesizedGenericArguments {
paren_token: parenthesized!(content in input),
inputs: content.parse_synom(Punctuated::parse_terminated)?,
- output: input.parse_synom(ReturnType::without_plus)?,
+ output: input.call(ReturnType::without_plus)?,
})
}
}
@@ -321,7 +320,7 @@
}
let ident = input.parse()?;
- if input.peek(Token![<]) && !input.peek2(Token![=])
+ if input.peek(Token![<]) && !input.peek(Token![<=])
|| input.peek(Token![::]) && input.peek3(Token![<])
{
Ok(PathSegment {
@@ -339,16 +338,49 @@
Ok(Binding {
ident: input.parse()?,
eq_token: input.parse()?,
- ty: input.parse_synom(Type::parse)?,
+ ty: input.parse()?,
})
}
}
impl Path {
- named!(pub parse_mod_style -> Self, do_parse!(
+ pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
+ Ok(Path {
+ leading_colon: input.parse()?,
+ segments: {
+ let mut segments = Punctuated::new();
+ loop {
+ if !input.peek(Ident)
+ && !input.peek(Token![super])
+ && !input.peek(Token![self])
+ && !input.peek(Token![Self])
+ && !input.peek(Token![crate])
+ && !input.peek(Token![extern])
+ {
+ break;
+ }
+ let ident = Ident::parse_any2(input)?;
+ segments.push_value(PathSegment::from(ident));
+ if !input.peek(Token![::]) {
+ break;
+ }
+ let punct = input.parse()?;
+ segments.push_punct(punct);
+ }
+ if segments.is_empty() {
+ return Err(input.error("expected path"));
+ } else if segments.trailing_punct() {
+ return Err(input.error("expected path segment"));
+ }
+ segments
+ },
+ })
+ }
+
+ named!(pub old_parse_mod_style -> Self, do_parse!(
colon: option!(punct!(::)) >>
segments: call!(Punctuated::parse_separated_nonempty_with,
- mod_style_path_segment) >>
+ old_mod_style_path_segment) >>
(Path {
leading_colon: colon,
segments: segments,
@@ -356,7 +388,30 @@
));
}
- named!(pub mod_style_path_segment -> PathSegment, alt!(
+ // FIXME
+ /*
+ pub fn mod_style_path_segment(input: ParseStream) -> Result<PathSegment> {
+ let lookahead = input.lookahead1();
+ let ident = if lookahead.peek(Ident) {
+ input.parse()?
+ } else if lookahead.peek(Token![super]) {
+ Ident::from(input.parse::<Token![super]>()?)
+ } else if lookahead.peek(Token![self]) {
+ Ident::from(input.parse::<Token![self]>()?)
+ } else if lookahead.peek(Token![Self]) {
+ Ident::from(input.parse::<Token![Self]>()?)
+ } else if lookahead.peek(Token![crate]) {
+ Ident::from(input.parse::<Token![crate]>()?)
+ } else if lookahead.peek(Token![extern]) {
+ Ident::from(input.parse::<Token![extern]>()?)
+ } else {
+ return Err(lookahead.error());
+ };
+ Ok(PathSegment::from(ident))
+ }
+ */
+
+ named!(pub old_mod_style_path_segment -> PathSegment, alt!(
syn!(Ident) => { Into::into }
|
keyword!(super) => { Into::into }
@@ -370,44 +425,6 @@
keyword!(extern) => { Into::into }
));
- named!(pub qpath -> (Option<QSelf>, Path), alt!(
- map!(syn!(Path), |p| (None, p))
- |
- do_parse!(
- lt: punct!(<) >>
- this: syn!(Type) >>
- path: option!(tuple!(keyword!(as), syn!(Path))) >>
- gt: punct!(>) >>
- colon2: punct!(::) >>
- rest: call!(Punctuated::parse_separated_nonempty) >>
- ({
- let (pos, as_, path) = match path {
- Some((as_, mut path)) => {
- let pos = path.segments.len();
- path.segments.push_punct(colon2);
- path.segments.extend(rest.into_pairs());
- (pos, Some(as_), path)
- }
- None => {
- (0, None, Path {
- leading_colon: Some(colon2),
- segments: rest,
- })
- }
- };
- (Some(QSelf {
- lt_token: lt,
- ty: Box::new(this),
- position: pos,
- as_token: as_,
- gt_token: gt,
- }), path)
- })
- )
- |
- map!(keyword!(self), |s| (None, s.into()))
- ));
-
named!(pub ty_no_eq_after -> Type, do_parse!(
ty: syn!(Type) >>
not!(punct!(=)) >>
diff --git a/src/synom.rs b/src/synom.rs
index ed1c1b2..035b770 100644
--- a/src/synom.rs
+++ b/src/synom.rs
@@ -231,7 +231,7 @@
fn parse(input: ParseStream) -> Result<Self> {
input.step_cursor(|cursor| match cursor.token_tree() {
Some((tt, rest)) => Ok((tt, rest)),
- None => Err(cursor.error("expected token tree"))
+ None => Err(cursor.error("expected token tree")),
})
}
}
diff --git a/src/token.rs b/src/token.rs
index 3ffe827..9f9b904 100644
--- a/src/token.rs
+++ b/src/token.rs
@@ -124,7 +124,7 @@
#[cfg(feature = "parsing")]
use lifetime::Lifetime;
#[cfg(feature = "parsing")]
-use lit::Lit;
+use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
#[cfg(feature = "parsing")]
use lookahead;
#[cfg(feature = "parsing")]
@@ -177,6 +177,13 @@
impl_token!(Ident "identifier");
impl_token!(Lifetime "lifetime");
impl_token!(Lit "literal");
+impl_token!(LitStr "string literal");
+impl_token!(LitByteStr "byte string literal");
+impl_token!(LitByte "byte literal");
+impl_token!(LitChar "character literal");
+impl_token!(LitInt "integer literal");
+impl_token!(LitFloat "floating point literal");
+impl_token!(LitBool "boolean literal");
macro_rules! define_keywords {
($($token:tt pub struct $name:ident #[$doc:meta])*) => {
@@ -493,6 +500,17 @@
}
}
+#[cfg(feature = "parsing")]
+impl Token for Group {
+ fn peek(lookahead: &Lookahead1) -> bool {
+ lookahead::is_delimiter(lookahead, Delimiter::None)
+ }
+
+ fn display() -> String {
+ "invisible group".to_owned()
+ }
+}
+
define_keywords! {
"as" pub struct As /// `as`
"async" pub struct Async /// `async`
diff --git a/src/tt.rs b/src/tt.rs
index bde82dc..3fe12f8 100644
--- a/src/tt.rs
+++ b/src/tt.rs
@@ -6,22 +6,25 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[cfg(feature = "parsing")]
+#[cfg(all(feature = "full", feature = "parsing"))]
use buffer::Cursor;
-#[cfg(feature = "parsing")]
+#[cfg(all(feature = "full", feature = "parsing"))]
use synom::PResult;
-#[cfg(feature = "parsing")]
+#[cfg(all(feature = "full", feature = "parsing"))]
use token::{Brace, Bracket, Paren};
-#[cfg(feature = "parsing")]
+#[cfg(all(feature = "full", feature = "parsing"))]
use {parse_error, MacroDelimiter};
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};
-#[cfg(any(feature = "parsing", feature = "extra-traits"))]
+#[cfg(any(
+ all(feature = "full", feature = "parsing"),
+ feature = "extra-traits"
+))]
use proc_macro2::{Delimiter, TokenStream, TokenTree};
-#[cfg(feature = "parsing")]
+#[cfg(all(feature = "full", feature = "parsing"))]
pub fn delimited(input: Cursor) -> PResult<(MacroDelimiter, TokenStream)> {
if let Some((TokenTree::Group(g), rest)) = input.token_tree() {
let span = g.span();
diff --git a/src/ty.rs b/src/ty.rs
index 81e4df5..fa1083f 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -73,10 +73,10 @@
/// *This type is available if Syn is built with the `"derive"` or
/// `"full"` feature.*
pub BareFn(TypeBareFn {
+ pub lifetimes: Option<BoundLifetimes>,
pub unsafety: Option<Token![unsafe]>,
pub abi: Option<Abi>,
pub fn_token: Token![fn],
- pub lifetimes: Option<BoundLifetimes>,
pub paren_token: token::Paren,
pub inputs: Punctuated<BareFnArg, Token![,]>,
pub variadic: Option<Token![...]>,
@@ -249,14 +249,12 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use path::parsing::qpath;
+ use parse::{Parse, ParseStream, Result};
use synom::Synom;
- impl Synom for Type {
- named!(parse -> Self, call!(ambig_ty, true));
-
- fn description() -> Option<&'static str> {
- Some("type")
+ impl Parse for Type {
+ fn parse(input: ParseStream) -> Result<Self> {
+ ambig_ty(input, true)
}
}
@@ -266,250 +264,389 @@
/// contain a `+` character.
///
/// This parser does not allow a `+`, while the default parser does.
- named!(pub without_plus -> Self, call!(ambig_ty, false));
- }
-
- named!(ambig_ty(allow_plus: bool) -> Type, alt!(
- syn!(TypeGroup) => { Type::Group }
- |
- // must be before TypeTuple
- call!(TypeParen::parse, allow_plus) => { Type::Paren }
- |
- // must be before TypePath
- syn!(TypeMacro) => { Type::Macro }
- |
- // must be before TypePath
- syn!(TypeBareFn) => { Type::BareFn }
- |
- // must be before TypeTraitObject
- call!(TypePath::parse, allow_plus) => { Type::Path }
- |
- // Don't try parsing more than one trait bound if we aren't allowing it.
- // must be before TypeTuple
- call!(TypeTraitObject::parse, allow_plus) => { Type::TraitObject }
- |
- syn!(TypeSlice) => { Type::Slice }
- |
- syn!(TypeArray) => { Type::Array }
- |
- syn!(TypePtr) => { Type::Ptr }
- |
- syn!(TypeReference) => { Type::Reference }
- |
- syn!(TypeNever) => { Type::Never }
- |
- syn!(TypeTuple) => { Type::Tuple }
- |
- syn!(TypeImplTrait) => { Type::ImplTrait }
- |
- syn!(TypeInfer) => { Type::Infer }
- ));
-
- impl Synom for TypeSlice {
- named!(parse -> Self, map!(
- brackets!(syn!(Type)),
- |(b, ty)| TypeSlice {
- elem: Box::new(ty),
- bracket_token: b,
- }
- ));
-
- fn description() -> Option<&'static str> {
- Some("slice type")
+ pub fn without_plus(input: ParseStream) -> Result<Self> {
+ ambig_ty(input, false)
}
}
- impl Synom for TypeArray {
- named!(parse -> Self, map!(
- brackets!(do_parse!(
- elem: syn!(Type) >>
- semi: punct!(;) >>
- len: syn!(Expr) >>
- (elem, semi, len)
- )),
- |(brackets, (elem, semi, len))| {
- TypeArray {
+ fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result<Type> {
+ if input.peek(token::Group) {
+ return input.parse().map(Type::Group);
+ }
+
+ let mut lifetimes = None::<BoundLifetimes>;
+ let mut lookahead = input.lookahead1();
+ if lookahead.peek(Token![for]) {
+ lifetimes = input.parse()?;
+ lookahead = input.lookahead1();
+ if !lookahead.peek(Ident)
+ && !lookahead.peek(Token![fn])
+ && !lookahead.peek(Token![unsafe])
+ && !lookahead.peek(Token![extern])
+ && !lookahead.peek(Token![super])
+ && !lookahead.peek(Token![self])
+ && !lookahead.peek(Token![Self])
+ && !lookahead.peek(Token![crate])
+ {
+ return Err(lookahead.error());
+ }
+ }
+
+ if lookahead.peek(token::Paren) {
+ let content;
+ let paren_token = parenthesized!(content in input);
+ if content.is_empty() {
+ return Ok(Type::Tuple(TypeTuple {
+ paren_token: paren_token,
+ elems: Punctuated::new(),
+ }));
+ }
+ if content.peek(Lifetime) {
+ return Ok(Type::Paren(TypeParen {
+ paren_token: paren_token,
+ elem: Box::new(Type::TraitObject(content.parse()?)),
+ }));
+ }
+ let first: Type = content.parse()?;
+ if content.peek(Token![,]) {
+ Ok(Type::Tuple(TypeTuple {
+ paren_token: paren_token,
+ elems: {
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ elems.push_punct(content.parse()?);
+ let rest: Punctuated<Type, Token![,]> =
+ content.parse_terminated(Parse::parse)?;
+ elems.extend(rest);
+ elems
+ },
+ }))
+ } else {
+ Ok(Type::Paren(TypeParen {
+ paren_token: paren_token,
+ elem: Box::new(first),
+ }))
+ }
+ } else if lookahead.peek(Token![fn])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern]) && !input.peek2(Token![::])
+ {
+ let mut bare_fn: TypeBareFn = input.parse()?;
+ bare_fn.lifetimes = lifetimes;
+ Ok(Type::BareFn(bare_fn))
+ } else if lookahead.peek(Ident)
+ || input.peek(Token![super])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![crate])
+ || input.peek(Token![extern])
+ || lookahead.peek(Token![::])
+ || lookahead.peek(Token![<])
+ {
+ if input.peek(Token![dyn]) {
+ let mut trait_object: TypeTraitObject = input.parse()?;
+ if lifetimes.is_some() {
+ match *trait_object.bounds.iter_mut().next().unwrap() {
+ TypeParamBound::Trait(ref mut trait_bound) => {
+ trait_bound.lifetimes = lifetimes;
+ }
+ TypeParamBound::Lifetime(_) => unreachable!(),
+ }
+ }
+ return Ok(Type::TraitObject(trait_object));
+ }
+
+ let ty: TypePath = input.parse()?;
+ if ty.qself.is_some() {
+ return Ok(Type::Path(ty));
+ }
+
+ if input.peek(Token![!]) && !input.peek(Token![!=]) {
+ let mut contains_arguments = false;
+ for segment in &ty.path.segments {
+ match segment.arguments {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+ contains_arguments = true;
+ }
+ }
+ }
+
+ if !contains_arguments {
+ let bang_token: Token![!] = input.parse()?;
+ let (delimiter, tts) = mac::parse_delimiter(input)?;
+ return Ok(Type::Macro(TypeMacro {
+ mac: Macro {
+ path: ty.path,
+ bang_token: bang_token,
+ delimiter: delimiter,
+ tts: tts,
+ },
+ }));
+ }
+ }
+
+ if lifetimes.is_some() || allow_plus && input.peek(Token![+]) {
+ let mut bounds = Punctuated::new();
+ bounds.push_value(TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes: lifetimes,
+ path: ty.path,
+ }));
+ if allow_plus && input.peek(Token![+]) {
+ bounds.push_punct(input.parse()?);
+ let rest: Punctuated<TypeParamBound, Token![+]> =
+ input.parse_synom(Punctuated::parse_terminated_nonempty)?;
+ bounds.extend(rest);
+ }
+ return Ok(Type::TraitObject(TypeTraitObject {
+ dyn_token: None,
+ bounds: bounds,
+ }));
+ }
+
+ Ok(Type::Path(ty))
+ } else if lookahead.peek(token::Bracket) {
+ let content;
+ let bracket_token = bracketed!(content in input);
+ let elem: Type = content.parse()?;
+ if content.peek(Token![;]) {
+ Ok(Type::Array(TypeArray {
+ bracket_token: bracket_token,
elem: Box::new(elem),
- len: len,
- bracket_token: brackets,
- semi_token: semi,
- }
+ semi_token: content.parse()?,
+ len: content.parse_synom(Expr::parse)?,
+ }))
+ } else {
+ Ok(Type::Slice(TypeSlice {
+ bracket_token: bracket_token,
+ elem: Box::new(elem),
+ }))
}
- ));
-
- fn description() -> Option<&'static str> {
- Some("array type")
+ } else if lookahead.peek(Token![*]) {
+ input.parse().map(Type::Ptr)
+ } else if lookahead.peek(Token![&]) {
+ input.parse().map(Type::Reference)
+ } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) {
+ input.parse().map(Type::Never)
+ } else if lookahead.peek(Token![impl ]) {
+ input.parse().map(Type::ImplTrait)
+ } else if lookahead.peek(Token![_]) {
+ input.parse().map(Type::Infer)
+ } else if lookahead.peek(Lifetime) {
+ input.parse().map(Type::TraitObject)
+ } else {
+ Err(lookahead.error())
}
}
- impl Synom for TypePtr {
- named!(parse -> Self, do_parse!(
- star: punct!(*) >>
- mutability: alt!(
- keyword!(const) => { |c| (None, Some(c)) }
- |
- keyword!(mut) => { |m| (Some(m), None) }
- ) >>
- target: call!(Type::without_plus) >>
- (TypePtr {
- const_token: mutability.1,
- star_token: star,
- mutability: mutability.0,
- elem: Box::new(target),
+ impl Parse for TypeSlice {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(TypeSlice {
+ bracket_token: bracketed!(content in input),
+ elem: content.parse()?,
})
- ));
-
- fn description() -> Option<&'static str> {
- Some("raw pointer type")
}
}
- impl Synom for TypeReference {
- named!(parse -> Self, do_parse!(
- amp: punct!(&) >>
- life: option!(syn!(Lifetime)) >>
- mutability: option!(keyword!(mut)) >>
- // & binds tighter than +, so we don't allow + here.
- target: call!(Type::without_plus) >>
- (TypeReference {
- lifetime: life,
+ impl Parse for TypeArray {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(TypeArray {
+ bracket_token: bracketed!(content in input),
+ elem: content.parse()?,
+ semi_token: content.parse()?,
+ len: content.parse_synom(Expr::parse)?,
+ })
+ }
+ }
+
+ impl Parse for TypePtr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let star_token: Token![*] = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let (const_token, mutability) = if lookahead.peek(Token![const]) {
+ (Some(input.parse()?), None)
+ } else if lookahead.peek(Token![mut]) {
+ (None, Some(input.parse()?))
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok(TypePtr {
+ star_token: star_token,
+ const_token: const_token,
mutability: mutability,
- elem: Box::new(target),
- and_token: amp,
+ elem: Box::new(input.call(Type::without_plus)?),
})
- ));
-
- fn description() -> Option<&'static str> {
- Some("reference type")
}
}
- impl Synom for TypeBareFn {
- named!(parse -> Self, do_parse!(
- lifetimes: option!(syn!(BoundLifetimes)) >>
- unsafety: option!(keyword!(unsafe)) >>
- abi: option!(syn!(Abi)) >>
- fn_: keyword!(fn) >>
- parens: parens!(do_parse!(
- inputs: call!(Punctuated::parse_terminated) >>
- variadic: option!(cond_reduce!(inputs.empty_or_trailing(), punct!(...))) >>
- (inputs, variadic)
- )) >>
- output: call!(ReturnType::without_plus) >>
- (TypeBareFn {
- unsafety: unsafety,
- abi: abi,
- lifetimes: lifetimes,
- output: output,
- variadic: (parens.1).1,
- fn_token: fn_,
- paren_token: parens.0,
- inputs: (parens.1).0,
+ impl Parse for TypeReference {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeReference {
+ and_token: input.parse()?,
+ lifetime: input.parse()?,
+ mutability: input.parse()?,
+ // & binds tighter than +, so we don't allow + here.
+ elem: Box::new(input.call(Type::without_plus)?),
})
- ));
-
- fn description() -> Option<&'static str> {
- Some("`fn` type")
}
}
- impl Synom for TypeNever {
- named!(parse -> Self, map!(
- punct!(!),
- |b| TypeNever { bang_token: b }
- ));
-
- fn description() -> Option<&'static str> {
- Some("never type: `!`")
- }
- }
-
- impl Synom for TypeInfer {
- named!(parse -> Self, map!(
- punct!(_),
- |u| TypeInfer { underscore_token: u }
- ));
-
- fn description() -> Option<&'static str> {
- Some("inferred type: `_`")
- }
- }
-
- impl Synom for TypeTuple {
- named!(parse -> Self, do_parse!(
- data: parens!(Punctuated::parse_terminated) >>
- (TypeTuple {
- paren_token: data.0,
- elems: data.1,
+ impl Parse for TypeBareFn {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let args;
+ let allow_variadic;
+ Ok(TypeBareFn {
+ lifetimes: input.parse()?,
+ unsafety: input.parse()?,
+ abi: input.parse()?,
+ fn_token: input.parse()?,
+ paren_token: parenthesized!(args in input),
+ inputs: {
+ let inputs = args.parse_synom(Punctuated::parse_terminated)?;
+ allow_variadic = inputs.empty_or_trailing();
+ inputs
+ },
+ variadic: {
+ if allow_variadic && args.peek(Token![...]) {
+ Some(args.parse()?)
+ } else {
+ None
+ }
+ },
+ output: input.call(ReturnType::without_plus)?,
})
- ));
-
- fn description() -> Option<&'static str> {
- Some("tuple type")
}
}
- impl Synom for TypeMacro {
- named!(parse -> Self, map!(syn!(Macro), |mac| TypeMacro { mac: mac }));
-
- fn description() -> Option<&'static str> {
- Some("macro invocation")
- }
- }
-
- impl Synom for TypePath {
- named!(parse -> Self, call!(Self::parse, false));
-
- fn description() -> Option<&'static str> {
- Some("type path")
- }
- }
-
- impl TypePath {
- named!(parse(allow_plus: bool) -> Self, do_parse!(
- qpath: qpath >>
- parenthesized: option!(cond_reduce!(
- qpath.1.segments.last().unwrap().value().arguments.is_empty(),
- syn!(ParenthesizedGenericArguments)
- )) >>
- cond!(allow_plus, not!(punct!(+))) >>
- ({
- let (qself, mut path) = qpath;
- if let Some(parenthesized) = parenthesized {
- let parenthesized = PathArguments::Parenthesized(parenthesized);
- path.segments.last_mut().unwrap().value_mut().arguments = parenthesized;
- }
- TypePath { qself: qself, path: path }
+ impl Parse for TypeNever {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeNever {
+ bang_token: input.parse()?,
})
- ));
+ }
+ }
+
+ impl Parse for TypeInfer {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeInfer {
+ underscore_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypeTuple {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(TypeTuple {
+ paren_token: parenthesized!(content in input),
+ elems: content.parse_terminated(<Type as Parse>::parse)?,
+ })
+ }
+ }
+
+ impl Parse for TypeMacro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeMacro {
+ mac: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypePath {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let (qself, mut path) = if input.peek(Token![<]) {
+ let lt_token: Token![<] = input.parse()?;
+ let this: Type = input.parse()?;
+ let path = if input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let path: Path = input.parse()?;
+ Some((as_token, path))
+ } else {
+ None
+ };
+ let gt_token: Token![>] = input.parse()?;
+ let colon2_token: Token![::] = input.parse()?;
+ let rest = input.parse_synom(Punctuated::parse_separated_nonempty)?;
+ let (position, as_token, path) = match path {
+ Some((as_token, mut path)) => {
+ let pos = path.segments.len();
+ path.segments.push_punct(colon2_token);
+ path.segments.extend(rest.into_pairs());
+ (pos, Some(as_token), path)
+ }
+ None => {
+ let path = Path {
+ leading_colon: Some(colon2_token),
+ segments: rest,
+ };
+ (0, None, path)
+ }
+ };
+ let qself = QSelf {
+ lt_token: lt_token,
+ ty: Box::new(this),
+ position: position,
+ as_token: as_token,
+ gt_token: gt_token,
+ };
+ (Some(qself), path)
+ } else {
+ let path: Path = input.parse()?;
+ (None, path)
+ };
+
+ let parenthesized = if path.segments.last().unwrap().value().arguments.is_empty()
+ && input.peek(token::Paren)
+ {
+ let args: ParenthesizedGenericArguments = input.parse()?;
+ Some(args)
+ } else {
+ None
+ };
+
+ if let Some(parenthesized) = parenthesized {
+ let parenthesized = PathArguments::Parenthesized(parenthesized);
+ path.segments.last_mut().unwrap().value_mut().arguments = parenthesized;
+ }
+
+ Ok(TypePath {
+ qself: qself,
+ path: path,
+ })
+ }
}
impl ReturnType {
- named!(pub without_plus -> Self, call!(Self::parse, false));
- named!(parse(allow_plus: bool) -> Self, alt!(
- do_parse!(
- arrow: punct!(->) >>
- ty: call!(ambig_ty, allow_plus) >>
- (ReturnType::Type(arrow, Box::new(ty)))
- )
- |
- epsilon!() => { |_| ReturnType::Default }
- ));
- }
+ pub fn without_plus(input: ParseStream) -> Result<Self> {
+ Self::parse(input, false)
+ }
- impl Synom for ReturnType {
- named!(parse -> Self, call!(Self::parse, true));
-
- fn description() -> Option<&'static str> {
- Some("return type")
+ pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
+ if input.peek(Token![->]) {
+ let arrow = input.parse()?;
+ let ty = ambig_ty(input, allow_plus)?;
+ Ok(ReturnType::Type(arrow, Box::new(ty)))
+ } else {
+ Ok(ReturnType::Default)
+ }
}
}
- impl Synom for TypeTraitObject {
- named!(parse -> Self, call!(Self::parse, true));
+ impl Parse for ReturnType {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse(input, true)
+ }
+ }
- fn description() -> Option<&'static str> {
- Some("trait object type")
+ impl Parse for TypeTraitObject {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse(input, true)
}
}
@@ -523,123 +660,118 @@
}
impl TypeTraitObject {
- named!(pub without_plus -> Self, call!(Self::parse, false));
+ pub fn without_plus(input: ParseStream) -> Result<Self> {
+ Self::parse(input, false)
+ }
// Only allow multiple trait references if allow_plus is true.
- named!(parse(allow_plus: bool) -> Self, do_parse!(
- dyn_token: option!(keyword!(dyn)) >>
- bounds: alt!(
- cond_reduce!(allow_plus, Punctuated::parse_terminated_nonempty)
- |
- syn!(TypeParamBound) => {|x| {
- let mut bounds = Punctuated::new();
- bounds.push_value(x);
+ pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
+ Ok(TypeTraitObject {
+ dyn_token: input.parse()?,
+ bounds: {
+ let bounds = if allow_plus {
+ input.parse_synom(Punctuated::parse_terminated_nonempty)?
+ } else {
+ let mut bounds = Punctuated::new();
+ bounds.push_value(input.parse()?);
+ bounds
+ };
+ // Just lifetimes like `'a + 'b` is not a TraitObject.
+ if !at_least_one_type(&bounds) {
+ return Err(input.error("expected at least one type"));
+ }
bounds
- }}
- ) >>
- // Just lifetimes like `'a + 'b` is not a TraitObject.
- cond_reduce!(at_least_one_type(&bounds)) >>
- (TypeTraitObject {
- dyn_token: dyn_token,
- bounds: bounds,
+ },
})
- ));
- }
-
- impl Synom for TypeImplTrait {
- named!(parse -> Self, do_parse!(
- impl_: keyword!(impl) >>
- // NOTE: rust-lang/rust#34511 includes discussion about whether or
- // not + should be allowed in ImplTrait directly without ().
- elem: call!(Punctuated::parse_terminated_nonempty) >>
- (TypeImplTrait {
- impl_token: impl_,
- bounds: elem,
- })
- ));
-
- fn description() -> Option<&'static str> {
- Some("`impl Trait` type")
}
}
- impl Synom for TypeGroup {
- named!(parse -> Self, do_parse!(
- data: grouped!(syn!(Type)) >>
- (TypeGroup {
- group_token: data.0,
- elem: Box::new(data.1),
+ impl Parse for TypeImplTrait {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeImplTrait {
+ impl_token: input.parse()?,
+ // NOTE: rust-lang/rust#34511 includes discussion about whether
+ // or not + should be allowed in ImplTrait directly without ().
+ bounds: input.parse_synom(Punctuated::parse_terminated_nonempty)?,
})
- ));
-
- fn description() -> Option<&'static str> {
- Some("type surrounded by invisible delimiters")
}
}
- impl Synom for TypeParen {
- named!(parse -> Self, call!(Self::parse, false));
+ impl Parse for TypeGroup {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(TypeGroup {
+ group_token: grouped!(content in input),
+ elem: content.parse()?,
+ })
+ }
+ }
- fn description() -> Option<&'static str> {
- Some("parenthesized type")
+ impl Parse for TypeParen {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse(input, false)
}
}
impl TypeParen {
- named!(parse(allow_plus: bool) -> Self, do_parse!(
- data: parens!(syn!(Type)) >>
- cond!(allow_plus, not!(punct!(+))) >>
- (TypeParen {
- paren_token: data.0,
- elem: Box::new(data.1),
+ fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
+ let content;
+ Ok(TypeParen {
+ paren_token: parenthesized!(content in input),
+ elem: Box::new(ambig_ty(&content, allow_plus)?),
})
- ));
- }
-
- impl Synom for BareFnArg {
- named!(parse -> Self, do_parse!(
- name: option!(do_parse!(
- name: syn!(BareFnArgName) >>
- not!(punct!(::)) >>
- colon: punct!(:) >>
- (name, colon)
- )) >>
- ty: syn!(Type) >>
- (BareFnArg {
- name: name,
- ty: ty,
- })
- ));
-
- fn description() -> Option<&'static str> {
- Some("function type argument")
}
}
- impl Synom for BareFnArgName {
- named!(parse -> Self, alt!(
- map!(syn!(Ident), BareFnArgName::Named)
- |
- map!(punct!(_), BareFnArgName::Wild)
- ));
-
- fn description() -> Option<&'static str> {
- Some("function argument name")
+ impl Parse for BareFnArg {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(BareFnArg {
+ name: {
+ if (input.peek(Ident) || input.peek(Token![_]))
+ && !input.peek2(Token![::])
+ && input.peek2(Token![:])
+ {
+ let name: BareFnArgName = input.parse()?;
+ let colon: Token![:] = input.parse()?;
+ Some((name, colon))
+ } else {
+ None
+ }
+ },
+ ty: input.parse()?,
+ })
}
}
- impl Synom for Abi {
- named!(parse -> Self, do_parse!(
- extern_: keyword!(extern) >>
- name: option!(syn!(LitStr)) >>
- (Abi {
- extern_token: extern_,
- name: name,
- })
- ));
+ impl Parse for BareFnArgName {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Ident) {
+ input.parse().map(BareFnArgName::Named)
+ } else if lookahead.peek(Token![_]) {
+ input.parse().map(BareFnArgName::Wild)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
- fn description() -> Option<&'static str> {
- Some("`extern` ABI qualifier")
+ impl Parse for Abi {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Abi {
+ extern_token: input.parse()?,
+ name: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for Option<Abi> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![extern]) {
+ input.parse().map(Some)
+ } else {
+ Ok(None)
+ }
}
}
}