Cleanup and documentation of synom parsers
diff --git a/src/delimited.rs b/src/delimited.rs
index 98c5b43..ec753e8 100644
--- a/src/delimited.rs
+++ b/src/delimited.rs
@@ -90,7 +90,7 @@
}
pub fn push(&mut self, token: Element<T, D>) {
- assert!(self.is_empty() || self.trailing_delim());
+ assert!(self.empty_or_trailing());
match token {
Element::Delimited(t, d) => self.inner.push((t, Some(d))),
Element::End(t) => self.inner.push((t, None)),
@@ -117,7 +117,7 @@
where
D: Default,
{
- if self.is_empty() || self.trailing_delim() {
+ if self.empty_or_trailing() {
self.inner.push((token, None));
} else {
self.push_next(token, D::default());
@@ -140,8 +140,9 @@
}
/// Returns true if either this `Delimited` is empty, or it has a trailing
- /// delimiter. This is useful within `ToTokens` implementations for `syn`.
- #[doc(hidden)]
+ /// delimiter.
+ ///
+ /// Equivalent to `delimited.is_empty() || delimited.trailing_delim()`.
pub fn empty_or_trailing(&self) -> bool {
self.is_empty() || self.trailing_delim()
}
@@ -390,6 +391,13 @@
where
D: Synom,
{
+ pub fn parse_separated_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ Self::parse(input, parse, false)
+ }
+
pub fn parse_separated_nonempty_with(
input: Cursor,
parse: fn(Cursor) -> PResult<T>,
diff --git a/src/expr.rs b/src/expr.rs
index 1296594..41edfad 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1310,7 +1310,7 @@
syn!(ExprLit) => { Expr::Lit } // must be before expr_struct
|
// must be before expr_path
- cond_reduce!(allow_struct, map!(syn!(ExprStruct), Expr::Struct))
+ cond_reduce!(allow_struct, syn!(ExprStruct)) => { Expr::Struct }
|
syn!(ExprParen) => { Expr::Paren } // must be before expr_tup
|
@@ -1348,7 +1348,7 @@
|
call!(expr_closure, allow_struct)
|
- cond_reduce!(allow_block, map!(syn!(ExprBlock), Expr::Block))
+ cond_reduce!(allow_block, syn!(ExprBlock)) => { Expr::Block }
|
// NOTE: This is the prefix-form of range
call!(expr_range, allow_struct)
@@ -1665,13 +1665,16 @@
rocket: punct!(=>) >>
body: do_parse!(
expr: alt!(expr_nosemi | syn!(Expr)) >>
- comma1: cond!(arm_expr_requires_comma(&expr), alt!(
- map!(input_end!(), |_| None)
+ comma: switch!(value!(arm_expr_requires_comma(&expr)),
+ true => alt!(
+ input_end!() => { |_| None }
+ |
+ punct!(,) => { Some }
+ )
|
- map!(punct!(,), Some)
- )) >>
- comma2: cond!(!arm_expr_requires_comma(&expr), option!(punct!(,))) >>
- (expr, comma1.and_then(|x| x).or_else(|| comma2.and_then(|x| x)))
+ false => option!(punct!(,))
+ ) >>
+ (expr, comma)
) >>
(Arm {
rocket_token: rocket,
@@ -1834,15 +1837,11 @@
path: syn!(Path) >>
data: braces!(do_parse!(
fields: call!(Delimited::parse_terminated) >>
- base: option!(
- cond!(fields.is_empty() || fields.trailing_delim(),
- do_parse!(
- dots: punct!(..) >>
- base: syn!(Expr) >>
- (dots, base)
- )
- )
- ) >>
+ base: option!(cond!(fields.empty_or_trailing(), do_parse!(
+ dots: punct!(..) >>
+ base: syn!(Expr) >>
+ (dots, base)
+ ))) >>
(fields, base)
)) >>
({
@@ -1990,7 +1989,11 @@
impl Block {
named!(pub parse_within -> Vec<Stmt>, do_parse!(
many0!(punct!(;)) >>
- mut standalone: many0!(terminated!(syn!(Stmt), many0!(punct!(;)))) >>
+ mut standalone: many0!(do_parse!(
+ stmt: syn!(Stmt) >>
+ many0!(punct!(;)) >>
+ (stmt)
+ )) >>
last: option!(do_parse!(
attrs: many0!(Attribute::parse_outer) >>
mut e: syn!(Expr) >>
@@ -2188,10 +2191,7 @@
path: syn!(Path) >>
data: braces!(do_parse!(
fields: call!(Delimited::parse_terminated) >>
- base: option!(
- cond!(fields.is_empty() || fields.trailing_delim(),
- punct!(..))
- ) >>
+ base: option!(cond!(fields.empty_or_trailing(), punct!(..))) >>
(fields, base)
)) >>
(PatStruct {
@@ -2283,14 +2283,9 @@
named!(parse -> Self, do_parse!(
data: parens!(do_parse!(
front: call!(Delimited::parse_terminated) >>
- dotdot: map!(cond!(
- front.is_empty() || front.trailing_delim(),
- option!(do_parse!(
- dots: punct!(..) >>
- trailing: option!(punct!(,)) >>
- (dots, trailing)
- ))
- ), Option::unwrap_or_default) >>
+ dotdot: option!(cond_reduce!(front.empty_or_trailing(),
+ tuple!(punct!(..), option!(punct!(,)))
+ )) >>
back: cond!(match dotdot {
Some((_, Some(_))) => true,
_ => false,
@@ -2406,10 +2401,10 @@
}),
bracket_token: brackets,
middle: middle.and_then(|_| {
- if !before.is_empty() && !before.trailing_delim() {
- Some(Box::new(before.pop().unwrap().into_item()))
- } else {
+ if before.empty_or_trailing() {
None
+ } else {
+ Some(Box::new(before.pop().unwrap().into_item()))
}
}),
front: before,
diff --git a/src/item.rs b/src/item.rs
index 59694bb..90b70f0 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -905,8 +905,7 @@
generics: syn!(Generics) >>
inputs: parens!(do_parse!(
args: call!(Delimited::parse_terminated) >>
- variadic: cond!(args.is_empty() || args.trailing_delim(),
- option!(punct!(...))) >>
+ variadic: option!(cond_reduce!(args.empty_or_trailing(), punct!(...))) >>
(args, variadic)
)) >>
ret: syn!(ReturnType) >>
@@ -914,7 +913,6 @@
semi: punct!(;) >>
({
let ((inputs, variadic), parens) = inputs;
- let variadic = variadic.and_then(|v| v);
ForeignItemFn {
ident: ident,
attrs: attrs,
diff --git a/src/parsers.rs b/src/parsers.rs
index e93aefa..8072ab8 100644
--- a/src/parsers.rs
+++ b/src/parsers.rs
@@ -2,21 +2,58 @@
use parse_error;
use synom::PResult;
-/// Define a function from a parser combination.
+/// Define a parser function with the signature expected by syn parser
+/// combinators.
+///
+/// The function may be the `parse` function of the [`Synom`] trait, or it may
+/// be a free-standing function with an arbitrary name. When implementing the
+/// `Synom` trait, the function name is `parse` and the return type is `Self`.
+///
+/// [`Synom`]: synom/trait.Synom.html
///
/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
///
/// ```rust
-/// # #[macro_use]
-/// # extern crate syn;
-/// #
-/// # use syn::Type;
-/// # use syn::delimited::Delimited;
-/// #
-/// // One or more Rust types separated by commas.
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+/// use syn::delimited::Delimited;
+/// use syn::synom::Synom;
+///
+/// /// Parses one or more Rust types separated by commas.
+/// ///
+/// /// Example: `String, Vec<T>, [u8; LEN + 1]`
/// named!(pub comma_separated_types -> Delimited<Type, Token![,]>,
/// call!(Delimited::parse_separated_nonempty)
/// );
+///
+/// /// The same function as a `Synom` implementation.
+/// struct CommaSeparatedTypes {
+/// types: Delimited<Type, Token![,]>,
+/// }
+///
+/// impl Synom for CommaSeparatedTypes {
+/// /// As the default behavior, we want there to be at least 1 type.
+/// named!(parse -> Self, do_parse!(
+/// types: call!(Delimited::parse_separated_nonempty) >>
+/// (CommaSeparatedTypes {
+/// types: types,
+/// })
+/// ));
+/// }
+///
+/// impl CommaSeparatedTypes {
+/// /// A separate parser that the user can invoke explicitly which allows
+/// /// for parsing 0 or more types, rather than the default 1 or more.
+/// named!(pub parse0 -> Self, do_parse!(
+/// types: call!(Delimited::parse_separated) >>
+/// (CommaSeparatedTypes {
+/// types: types,
+/// })
+/// ));
+/// }
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -51,26 +88,52 @@
#[cfg(all(feature = "verbose-trace", not(feature = "all-features")))]
#[macro_export]
macro_rules! call {
- ($i:expr, $fun:expr $(, $args:expr)*) => {
- {
- let i = $i;
- eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
- let r = $fun(i $(, $args)*);
- match r {
- Ok((i, _)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
- Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
- }
- r
+ ($i:expr, $fun:expr $(, $args:expr)*) => {{
+ let i = $i;
+ eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
+ let r = $fun(i $(, $args)*);
+ match r {
+ Ok((i, _)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
+ Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
}
- };
+ r
+ }};
}
-/// Invoke the given parser function with the passed in arguments.
+/// Invoke the given parser function with zero or more arguments.
///
-/// - **Syntax:** `call!(FUNCTION, ARGS...)`
+/// - **Syntax:** `call!(FN, ARGS...)`
///
-/// where the signature of the function is `fn(&[U], ARGS...) -> IPResult<&[U], T>`
-/// - **Output:** `T`, the result of invoking the function `FUNCTION`
+/// where the signature of the function is `fn(Cursor, ARGS...) -> PResult<T>`
+///
+/// - **Output:** `T`, the result of invoking the function `FN`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+/// use syn::delimited::Delimited;
+/// use syn::synom::Synom;
+///
+/// /// Parses one or more Rust types separated by commas.
+/// ///
+/// /// Example: `String, Vec<T>, [u8; LEN + 1]`
+/// struct CommaSeparatedTypes {
+/// types: Delimited<Type, Token![,]>,
+/// }
+///
+/// impl Synom for CommaSeparatedTypes {
+/// named!(parse -> Self, do_parse!(
+/// types: call!(Delimited::parse_separated_nonempty) >>
+/// (CommaSeparatedTypes {
+/// types: types,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
#[cfg(any(not(feature = "verbose-trace"), feature = "all-features"))]
#[macro_export]
macro_rules! call {
@@ -90,16 +153,20 @@
///
/// use syn::{Expr, ExprIf};
///
+/// /// Extracts the branch condition of an `if`-expression.
/// fn get_cond(if_: ExprIf) -> Expr {
/// *if_.cond
/// }
///
-/// // Parses an `if` statement but returns the condition part only.
+/// /// Parses a full `if`-expression but returns the condition part only.
+/// ///
+/// /// Example: `if x > 0xFF { "big" } else { "small" }`
+/// /// The return would be the expression `x > 0xFF`.
/// named!(if_condition -> Expr,
/// map!(syn!(ExprIf), get_cond)
/// );
///
-/// // Or equivalently:
+/// /// Equivalent using a closure.
/// named!(if_condition2 -> Expr,
/// map!(syn!(ExprIf), |if_| *if_.cond)
/// );
@@ -130,11 +197,29 @@
f(t)
}
-/// Parses successfully if the given parser fails to parse. Does not consume any
-/// of the input.
+/// Invert the result of a parser by parsing successfully if the given parser
+/// fails to parse and vice versa.
+///
+/// Does not consume any of the input.
///
/// - **Syntax:** `not!(THING)`
/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Expr, Ident};
+///
+/// /// Parses any expression that does not begin with a `-` minus sign.
+/// named!(not_negative_expr -> Expr, do_parse!(
+/// not!(punct!(-)) >>
+/// e: syn!(Expr) >>
+/// (e)
+/// ));
+/// #
+/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! not {
($i:expr, $submac:ident!( $($args:tt)* )) => {
@@ -146,12 +231,70 @@
};
}
-/// Conditionally execute the given parser.
+/// Execute a parser only if a condition is met, otherwise return None.
///
/// If you are familiar with nom, this is nom's `cond_with_error` parser.
///
/// - **Syntax:** `cond!(CONDITION, THING)`
/// - **Output:** `Some(THING)` if the condition is true, else `None`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Ident;
+/// use syn::token::{Paren, Bracket, Brace};
+/// use syn::synom::Synom;
+///
+/// /// Parses a macro call with empty input. If the macro is written with
+/// /// parentheses or brackets, a trailing semicolon is required.
+/// ///
+/// /// Example: `my_macro!{}` or `my_macro!();` or `my_macro![];`
+/// struct EmptyMacroCall {
+/// name: Ident,
+/// bang_token: Token![!],
+/// delimiter: MacroDelimiter,
+/// semi_token: Option<Token![;]>,
+/// }
+///
+/// enum MacroDelimiter {
+/// Paren(Paren),
+/// Bracket(Bracket),
+/// Brace(Brace),
+/// }
+///
+/// impl MacroDelimiter {
+/// fn requires_semi(&self) -> bool {
+/// match *self {
+/// MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => true,
+/// MacroDelimiter::Brace(_) => false,
+/// }
+/// }
+/// }
+///
+/// impl Synom for EmptyMacroCall {
+/// named!(parse -> Self, do_parse!(
+/// name: syn!(Ident) >>
+/// bang: punct!(!) >>
+/// empty_body: alt!(
+/// parens!(epsilon!()) => { |d| MacroDelimiter::Paren(d.1) }
+/// |
+/// brackets!(epsilon!()) => { |d| MacroDelimiter::Bracket(d.1) }
+/// |
+/// braces!(epsilon!()) => { |d| MacroDelimiter::Brace(d.1) }
+/// ) >>
+/// semi: cond!(empty_body.requires_semi(), punct!(;)) >>
+/// (EmptyMacroCall {
+/// name: name,
+/// bang_token: bang,
+/// delimiter: empty_body,
+/// semi_token: semi,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! cond {
($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
@@ -171,12 +314,61 @@
};
}
-/// Fail to parse if condition is false, otherwise parse the given parser.
+/// Execute a parser only if a condition is met, otherwise fail to parse.
///
-/// This is typically used inside of `option!` or `alt!`.
+/// This is typically used inside of [`option!`] or [`alt!`].
+///
+/// [`option!`]: macro.option.html
+/// [`alt!`]: macro.alt.html
///
/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
/// - **Output:** `THING`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+/// use syn::token::Paren;
+/// use syn::delimited::Delimited;
+/// use syn::synom::Synom;
+///
+/// /// Parses a possibly variadic function signature.
+/// ///
+/// /// Example: `fn(A) or `fn(A, B, C, ...)` or `fn(...)`
+/// /// Rejected: `fn(A, B...)`
+/// struct VariadicFn {
+/// fn_token: Token![fn],
+/// paren_token: Paren,
+/// types: Delimited<Type, Token![,]>,
+/// variadic: Option<Token![...]>,
+/// }
+///
+/// // Example of using `cond_reduce!` inside of `option!`.
+/// impl Synom for VariadicFn {
+/// named!(parse -> Self, do_parse!(
+/// fn_token: keyword!(fn) >>
+/// params: parens!(do_parse!(
+/// types: call!(Delimited::parse_terminated) >>
+/// // Allow, but do not require, an ending `...` but only if the
+/// // preceding list of types is empty or ends with a trailing comma.
+/// variadic: option!(cond_reduce!(types.empty_or_trailing(), punct!(...))) >>
+/// (types, variadic)
+/// )) >>
+/// ({
+/// let ((types, variadic), paren_token) = params;
+/// VariadicFn {
+/// fn_token,
+/// paren_token,
+/// types,
+/// variadic,
+/// }
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! cond_reduce {
($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
@@ -192,48 +384,6 @@
};
}
-/// Parse two things, returning the value of the first.
-///
-/// - **Syntax:** `terminated!(THING, AFTER)`
-/// - **Output:** `THING`
-///
-/// ```rust
-/// #[macro_use]
-/// extern crate syn;
-///
-/// use syn::Expr;
-///
-/// // An expression terminated by ##.
-/// named!(expr_pound_pound -> Expr,
-/// terminated!(syn!(Expr), tuple!(punct!(#), punct!(#)))
-/// );
-///
-/// # fn main() {}
-/// ```
-#[macro_export]
-macro_rules! terminated {
- ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
- match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
- ::std::result::Result::Ok((i, (o, _))) =>
- ::std::result::Result::Ok((i, o)),
- ::std::result::Result::Err(err) =>
- ::std::result::Result::Err(err),
- }
- };
-
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
- terminated!($i, $submac!($($args)*), call!($g))
- };
-
- ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => {
- terminated!($i, call!($f), $submac!($($args)*))
- };
-
- ($i:expr, $f:expr, $g:expr) => {
- terminated!($i, call!($f), call!($g))
- };
-}
-
/// Parse zero or more values using the given parser.
///
/// - **Syntax:** `many0!(THING)`
@@ -244,16 +394,42 @@
/// - `call!(Delimited::parse_separated)` - zero or more values with separator
/// - `call!(Delimited::parse_separated_nonempty)` - one or more values
/// - `call!(Delimited::parse_terminated)` - zero or more, allows trailing separator
+/// - `call!(Delimited::parse_terminated_nonempty)` - one or more
///
/// ```rust
/// #[macro_use]
/// extern crate syn;
///
-/// use syn::Item;
+/// use syn::{Ident, Item};
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
///
-/// named!(items -> Vec<Item>, many0!(syn!(Item)));
+/// /// Parses a module containing zero or more Rust items.
+/// ///
+/// /// Example: `mod m { type Result<T> = ::std::result::Result<T, MyError>; }`
+/// struct SimpleMod {
+/// mod_token: Token![mod],
+/// name: Ident,
+/// brace_token: Brace,
+/// items: Vec<Item>,
+/// }
///
+/// impl Synom for SimpleMod {
+/// named!(parse -> Self, do_parse!(
+/// mod_token: keyword!(mod) >>
+/// name: syn!(Ident) >>
+/// body: braces!(many0!(syn!(Item))) >>
+/// (SimpleMod {
+/// mod_token: mod_token,
+/// name: name,
+/// brace_token: body.1,
+/// items: body.0,
+/// })
+/// ));
+/// }
+/// #
/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! many0 {
($i:expr, $submac:ident!( $($args:tt)* )) => {{
@@ -323,38 +499,6 @@
}
}
-/// Parse a value without consuming it from the input data.
-///
-/// - **Syntax:** `peek!(THING)`
-/// - **Output:** `THING`
-///
-/// ```rust
-/// #[macro_use]
-/// extern crate syn;
-///
-/// use syn::{Expr, Ident};
-///
-/// // Parse an expression that begins with an identifier.
-/// named!(ident_expr -> (Ident, Expr),
-/// tuple!(peek!(syn!(Ident)), syn!(Expr))
-/// );
-///
-/// # fn main() {}
-/// ```
-#[macro_export]
-macro_rules! peek {
- ($i:expr, $submac:ident!( $($args:tt)* )) => {
- match $submac!($i, $($args)*) {
- ::std::result::Result::Ok((_, o)) => ::std::result::Result::Ok(($i, o)),
- ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
- }
- };
-
- ($i:expr, $f:expr) => {
- peek!($i, call!($f))
- };
-}
-
/// Pattern-match the result of a parser to select which other parser to run.
///
/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
@@ -364,48 +508,66 @@
/// #[macro_use]
/// extern crate syn;
///
-/// use syn::{Ident, Type};
+/// use syn::Ident;
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
///
-/// #[derive(Debug)]
+/// /// Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
/// enum UnitType {
/// Struct {
+/// struct_token: Token![struct],
/// name: Ident,
+/// semi_token: Token![;],
/// },
/// Enum {
+/// enum_token: Token![enum],
/// name: Ident,
+/// brace_token: Brace,
/// variant: Ident,
/// },
/// }
///
-/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
-/// named!(unit_type -> UnitType, do_parse!(
-/// which: alt!(
-/// keyword!(struct) => { |_| 0 }
-/// |
-/// keyword!(enum) => { |_| 1 }
-/// ) >>
-/// id: syn!(Ident) >>
-/// item: switch!(value!(which),
-/// 0 => map!(
-/// punct!(;),
-/// move |_| UnitType::Struct {
-/// name: id,
-/// }
-/// )
-/// |
-/// 1 => map!(
-/// braces!(syn!(Ident)),
-/// move |(variant, _)| UnitType::Enum {
-/// name: id,
-/// variant: variant,
-/// }
-/// )
-/// |
-/// _ => reject!()
-/// ) >>
-/// (item)
-/// ));
+/// enum StructOrEnum {
+/// Struct(Token![struct]),
+/// Enum(Token![enum]),
+/// }
///
+/// impl Synom for StructOrEnum {
+/// named!(parse -> Self, alt!(
+/// keyword!(struct) => { StructOrEnum::Struct }
+/// |
+/// keyword!(enum) => { StructOrEnum::Enum }
+/// ));
+/// }
+///
+/// impl Synom for UnitType {
+/// named!(parse -> Self, do_parse!(
+/// which: syn!(StructOrEnum) >>
+/// name: syn!(Ident) >>
+/// item: switch!(value!(which),
+/// StructOrEnum::Struct(struct_token) => map!(
+/// punct!(;),
+/// |semi_token| UnitType::Struct {
+/// struct_token: struct_token,
+/// name: name,
+/// semi_token: semi_token,
+/// }
+/// )
+/// |
+/// StructOrEnum::Enum(enum_token) => map!(
+/// braces!(syn!(Ident)),
+/// |(variant, brace_token)| UnitType::Enum {
+/// enum_token: enum_token,
+/// name: name,
+/// brace_token: brace_token,
+/// variant: variant,
+/// }
+/// )
+/// ) >>
+/// (item)
+/// ));
+/// }
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -422,8 +584,14 @@
};
}
-/// Produce the given value without parsing anything. Useful as an argument to
-/// `switch!`.
+/// Produce the given value without parsing anything.
+///
+/// This can be needed where you have an existing parsed value but a parser
+/// macro's syntax expects you to provide a submacro, such as in the first
+/// argument of [`switch!`] or one of the branches of [`alt!`].
+///
+/// [`switch!`]: macro.switch.html
+/// [`alt!`]: macro.alt.html
///
/// - **Syntax:** `value!(VALUE)`
/// - **Output:** `VALUE`
@@ -433,45 +601,65 @@
/// extern crate syn;
///
/// use syn::Ident;
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
///
-/// #[derive(Debug)]
+/// /// Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
/// enum UnitType {
/// Struct {
+/// struct_token: Token![struct],
/// name: Ident,
+/// semi_token: Token![;],
/// },
/// Enum {
+/// enum_token: Token![enum],
/// name: Ident,
+/// brace_token: Brace,
/// variant: Ident,
/// },
/// }
///
-/// // Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
-/// named!(unit_type -> UnitType, do_parse!(
-/// is_struct: alt!(
-/// keyword!(struct) => { |_| true }
-/// |
-/// keyword!(enum) => { |_| false }
-/// ) >>
-/// id: syn!(Ident) >>
-/// item: switch!(value!(is_struct),
-/// true => map!(
-/// punct!(;),
-/// move |_| UnitType::Struct {
-/// name: id,
-/// }
-/// )
-/// |
-/// false => map!(
-/// braces!(syn!(Ident)),
-/// move |(variant, _)| UnitType::Enum {
-/// name: id,
-/// variant: variant,
-/// }
-/// )
-/// ) >>
-/// (item)
-/// ));
+/// enum StructOrEnum {
+/// Struct(Token![struct]),
+/// Enum(Token![enum]),
+/// }
///
+/// impl Synom for StructOrEnum {
+/// named!(parse -> Self, alt!(
+/// keyword!(struct) => { StructOrEnum::Struct }
+/// |
+/// keyword!(enum) => { StructOrEnum::Enum }
+/// ));
+/// }
+///
+/// impl Synom for UnitType {
+/// named!(parse -> Self, do_parse!(
+/// which: syn!(StructOrEnum) >>
+/// name: syn!(Ident) >>
+/// item: switch!(value!(which),
+/// StructOrEnum::Struct(struct_token) => map!(
+/// punct!(;),
+/// |semi_token| UnitType::Struct {
+/// struct_token: struct_token,
+/// name: name,
+/// semi_token: semi_token,
+/// }
+/// )
+/// |
+/// StructOrEnum::Enum(enum_token) => map!(
+/// braces!(syn!(Ident)),
+/// |(variant, brace_token)| UnitType::Enum {
+/// enum_token: enum_token,
+/// name: name,
+/// brace_token: brace_token,
+/// variant: variant,
+/// }
+/// )
+/// ) >>
+/// (item)
+/// ));
+/// }
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -481,8 +669,9 @@
};
}
-/// Unconditionally fail to parse anything. This may be useful in ignoring some
-/// arms of a `switch!` parser.
+/// Unconditionally fail to parse anything.
+///
+/// This may be useful in rejecting some arms of a `switch!` parser.
///
/// - **Syntax:** `reject!()`
/// - **Output:** never succeeds
@@ -501,7 +690,7 @@
/// ok => value!(ok)
/// )
/// );
-///
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -524,7 +713,7 @@
/// use syn::Type;
///
/// named!(two_types -> (Type, Type), tuple!(syn!(Type), syn!(Type)));
-///
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -534,7 +723,7 @@
};
}
-/// Internal parser, do not use directly.
+// Internal parser, do not use directly.
#[doc(hidden)]
#[macro_export]
macro_rules! tuple_parser {
@@ -603,7 +792,7 @@
/// punct!(!) => { |_| "BANG".into() }
/// )
/// );
-///
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -653,8 +842,8 @@
};
}
-/// Run a series of parsers, one after another, optionally assigning the results
-/// a name. Fail if any of the parsers fails.
+/// Run a series of parsers, optionally naming each intermediate result,
+/// followed by a step to combine the intermediate results.
///
/// Produces the result of evaluating the final expression in parentheses with
/// all of the previously named results bound.
@@ -669,16 +858,33 @@
///
/// use syn::Ident;
/// use syn::token::Paren;
+/// use syn::synom::Synom;
/// use proc_macro2::TokenStream;
///
-/// // Parse a macro invocation like `stringify!($args)`.
-/// named!(simple_mac -> (Ident, (TokenStream, Paren)), do_parse!(
-/// name: syn!(Ident) >>
-/// punct!(!) >>
-/// body: parens!(syn!(TokenStream)) >>
-/// (name, body)
-/// ));
+/// /// Parse a macro invocation that uses `(` `)` parentheses.
+/// ///
+/// /// Example: `stringify!($args)`.
+/// struct Macro {
+/// name: Ident,
+/// bang_token: Token![!],
+/// paren_token: Paren,
+/// tts: TokenStream,
+/// }
///
+/// impl Synom for Macro {
+/// named!(parse -> Self, do_parse!(
+/// name: syn!(Ident) >>
+/// bang: punct!(!) >>
+/// body: parens!(syn!(TokenStream)) >>
+/// (Macro {
+/// name: name,
+/// bang_token: bang,
+/// paren_token: body.1,
+/// tts: body.0,
+/// })
+/// ));
+/// }
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -731,6 +937,57 @@
};
}
+/// Parse nothing and succeed only if the end of the enclosing block has been
+/// reached.
+///
+/// The enclosing block may be the full input if we are parsing at the top
+/// level, or the surrounding parenthesis/bracket/brace if we are parsing within
+/// those.
+///
+/// - **Syntax:** `input_end!()`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::synom::Synom;
+///
+/// /// Parses any Rust expression followed either by a semicolon or by the end
+/// /// of the input.
+/// ///
+/// /// For example `many0!(syn!(TerminatedExpr))` would successfully parse the
+/// /// following input into three expressions.
+/// ///
+/// /// 1 + 1; second.two(); third!()
+/// ///
+/// /// Similarly within a block, `braced!(many0!(syn!(TerminatedExpr)))` would
+/// /// successfully parse three expressions.
+/// ///
+/// /// { 1 + 1; second.two(); third!() }
+/// struct TerminatedExpr {
+/// expr: Expr,
+/// semi_token: Option<Token![;]>,
+/// }
+///
+/// impl Synom for TerminatedExpr {
+/// named!(parse -> Self, do_parse!(
+/// expr: syn!(Expr) >>
+/// semi: alt!(
+/// input_end!() => { |_| None }
+/// |
+/// punct!(;) => { Some }
+/// ) >>
+/// (TerminatedExpr {
+/// expr: expr,
+/// semi_token: semi,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! input_end {
($i:expr,) => {
@@ -750,6 +1007,8 @@
/// Turn a failed parse into `None` and a successful parse into `Some`.
///
+/// A failed parse consumes none of the input.
+///
/// - **Syntax:** `option!(THING)`
/// - **Output:** `Option<THING>`
///
@@ -757,10 +1016,34 @@
/// #[macro_use]
/// extern crate syn;
///
-/// use syn::token::Bang;
+/// use syn::{Label, Block};
+/// use syn::synom::Synom;
///
-/// named!(maybe_bang -> Option<Bang>, option!(punct!(!)));
+/// /// Parses a Rust loop. Equivalent to syn::ExprLoop.
+/// ///
+/// /// Examples:
+/// /// loop { println!("y"); }
+/// /// 'x: loop { break 'x; }
+/// struct ExprLoop {
+/// label: Option<Label>,
+/// loop_token: Token![loop],
+/// body: Block,
+/// }
///
+/// impl Synom for ExprLoop {
+/// named!(parse -> Self, do_parse!(
+/// // Loop may or may not have a label.
+/// label: option!(syn!(Label)) >>
+/// loop_: keyword!(loop) >>
+/// block: syn!(Block) >>
+/// (ExprLoop {
+/// label: label,
+/// loop_token: loop_,
+/// body: block,
+/// })
+/// ));
+/// }
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -779,51 +1062,16 @@
};
}
-/// Turn a failed parse into an empty vector. The argument parser must itself
-/// return a vector.
-///
-/// This is often more convenient than `option!(...)` when the argument produces
-/// a vector.
-///
-/// - **Syntax:** `opt_vec!(THING)`
-/// - **Output:** `THING`, which must be `Vec<T>`
-///
-/// ```rust
-/// #[macro_use]
-/// extern crate syn;
-///
-/// use syn::{Lifetime, Type};
-/// use syn::delimited::Delimited;
-/// use syn::token::*;
-///
-/// named!(bound_lifetimes -> (Vec<Lifetime>, Type), tuple!(
-/// opt_vec!(do_parse!(
-/// keyword!(for) >>
-/// punct!(<) >>
-/// lifetimes: call!(Delimited::<Lifetime, Comma>::parse_terminated) >>
-/// punct!(>) >>
-/// (lifetimes.into_vec())
-/// )),
-/// syn!(Type)
-/// ));
-///
-/// # fn main() {}
-/// ```
-#[macro_export]
-macro_rules! opt_vec {
- ($i:expr, $submac:ident!( $($args:tt)* )) => {
- match $submac!($i, $($args)*) {
- ::std::result::Result::Ok((i, o)) =>
- ::std::result::Result::Ok((i, o)),
- ::std::result::Result::Err(_) =>
- ::std::result::Result::Ok(($i, Vec::new()))
- }
- };
-}
-
/// Parses nothing and always succeeds.
///
-/// This can be useful as a fallthrough case in `alt!`.
+/// This can be useful as a fallthrough case in [`alt!`], as shown below. Also
+/// useful for parsing empty delimiters using [`parens!`] or [`brackets!`] or
+/// [`braces!`] by parsing for example `braces!(epsilon!())` for an empty `{}`.
+///
+/// [`alt!`]: macro.alt.html
+/// [`parens!`]: macro.parens.html
+/// [`brackets!`]: macro.brackets.html
+/// [`braces!`]: macro.braces.html
///
/// - **Syntax:** `epsilon!()`
/// - **Output:** `()`
@@ -832,18 +1080,23 @@
/// #[macro_use]
/// extern crate syn;
///
+/// use syn::synom::Synom;
+///
/// enum Mutability {
/// Mutable(Token![mut]),
/// Immutable,
/// }
///
-/// named!(mutability -> Mutability, alt!(
-/// keyword!(mut) => { Mutability::Mutable }
-/// |
-/// epsilon!() => { |_| Mutability::Immutable }
-/// ));
-///
+/// impl Synom for Mutability {
+/// named!(parse -> Self, alt!(
+/// keyword!(mut) => { Mutability::Mutable }
+/// |
+/// epsilon!() => { |_| Mutability::Immutable }
+/// ));
+/// }
+/// #
/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! epsilon {
($i:expr,) => {
@@ -858,29 +1111,6 @@
///
/// - **Syntax:** `tap!(NAME : THING => EXPR)`
/// - **Output:** `()`
-///
-/// ```rust
-/// #[macro_use]
-/// extern crate syn;
-///
-/// use syn::{Expr, ExprCall};
-/// use syn::token::RArrow;
-///
-/// named!(expr_with_arrow_call -> Expr, do_parse!(
-/// mut e: syn!(Expr) >>
-/// many0!(tap!(arg: tuple!(punct!(->), syn!(Expr)) => {
-/// e = Expr::Call(ExprCall {
-/// attrs: Vec::new(),
-/// func: Box::new(e),
-/// args: vec![arg.1].into(),
-/// paren_token: Default::default(),
-/// });
-/// })) >>
-/// (e)
-/// ));
-///
-/// # fn main() {}
-/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! tap {
@@ -901,12 +1131,13 @@
};
}
-/// Parse a type through the `Synom` trait.
+/// Parse any type that implements the `Synom` trait.
///
-/// This is a convenience macro used to invoke the `Synom::parse` method for a
-/// type, you'll find this in quite a few parsers. This is also the primary way
-/// to parse punctuation.
+/// Any type implementing [`Synom`] can be used with this parser, whether the
+/// implementation is provided by Syn or is one that you write.
///
+/// [`Synom`]: synom/trait.Synom.html
+///
/// - **Syntax:** `syn!(TYPE)`
/// - **Output:** `TYPE`
///
@@ -914,29 +1145,51 @@
/// #[macro_use]
/// extern crate syn;
///
-/// use syn::Expr;
+/// use syn::{Ident, Item};
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
///
-/// named!(expression -> Expr, syn!(Expr));
+/// /// Parses a module containing zero or more Rust items.
+/// ///
+/// /// Example: `mod m { type Result<T> = ::std::result::Result<T, MyError>; }`
+/// struct SimpleMod {
+/// mod_token: Token![mod],
+/// name: Ident,
+/// brace_token: Brace,
+/// items: Vec<Item>,
+/// }
///
-/// named!(expression_dot -> (Expr, Token![.]), tuple!(syn!(Expr), punct!(.)));
-///
+/// impl Synom for SimpleMod {
+/// named!(parse -> Self, do_parse!(
+/// mod_token: keyword!(mod) >>
+/// name: syn!(Ident) >>
+/// body: braces!(many0!(syn!(Item))) >>
+/// (SimpleMod {
+/// mod_token: mod_token,
+/// name: name,
+/// brace_token: body.1,
+/// items: body.0,
+/// })
+/// ));
+/// }
+/// #
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! syn {
($i:expr, $t:ty) => {
- call!($i, <$t as $crate::synom::Synom>::parse)
+ <$t as $crate::synom::Synom>::parse($i)
};
}
-/// Parse a parenthesized-surrounded subtree.
+/// Parse inside of `(` `)` parentheses.
///
-/// This macro will invoke a sub-parser inside of all tokens contained in
-/// parenthesis. The sub-parser is required to consume all tokens within the
-/// parens or else this parser will return an error.
+/// This macro parses a set of balanced parentheses and invokes a sub-parser on
+/// the content inside. The sub-parser is required to consume all tokens within
+/// the parentheses in order for this parser to return successfully.
///
/// - **Syntax:** `parens!(SUBPARSER)`
-/// - **Output:** `(SUBPARSER_RET, Paren)`
+/// - **Output:** `(SUBPARSER, token::Paren)`
///
/// ```rust
/// #[macro_use]
@@ -945,8 +1198,11 @@
/// use syn::Expr;
/// use syn::token::Paren;
///
+/// /// Parses an expression inside of parentheses.
+/// ///
+/// /// Example: `(1 + 1)`
/// named!(expr_paren -> (Expr, Paren), parens!(syn!(Expr)));
-///
+/// #
/// # fn main() {}
/// ```
#[macro_export]
@@ -960,7 +1216,29 @@
};
}
-/// Same as the `parens` macro, but for brackets.
+/// Parse inside of `[` `]` square brackets.
+///
+/// This macro parses a set of balanced brackets and invokes a sub-parser on the
+/// content inside. The sub-parser is required to consume all tokens within the
+/// brackets in order for this parser to return successfully.
+///
+/// - **Syntax:** `brackets!(SUBPARSER)`
+/// - **Output:** `(SUBPARSER, token::Bracket)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::token::Bracket;
+///
+/// /// Parses an expression inside of brackets.
+/// ///
+/// /// Example: `[1 + 1]`
+/// named!(expr_paren -> (Expr, Bracket), brackets!(syn!(Expr)));
+/// #
+/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! brackets {
($i:expr, $submac:ident!( $($args:tt)* )) => {
@@ -972,7 +1250,29 @@
};
}
-/// Same as the `parens` macro, but for braces.
+/// Parse inside of `{` `}` curly braces.
+///
+/// This macro parses a set of balanced braces and invokes a sub-parser on the
+/// content inside. The sub-parser is required to consume all tokens within the
+/// braces in order for this parser to return successfully.
+///
+/// - **Syntax:** `braces!(SUBPARSER)`
+/// - **Output:** `(SUBPARSER, token::Brace)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::token::Brace;
+///
+/// /// Parses an expression inside of braces.
+/// ///
+/// /// Example: `{1 + 1}`
+/// named!(expr_paren -> (Expr, Brace), braces!(syn!(Expr)));
+/// #
+/// # fn main() {}
+/// ```
#[macro_export]
macro_rules! braces {
($i:expr, $submac:ident!( $($args:tt)* )) => {
@@ -984,7 +1284,8 @@
};
}
-/// Same as the `parens` macro, but for none-delimited sequences (groups).
+// Not public API.
+#[doc(hidden)]
#[macro_export]
macro_rules! grouped {
($i:expr, $submac:ident!( $($args:tt)* )) => {
diff --git a/src/ty.rs b/src/ty.rs
index ad75b36..2aefaaa 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -466,8 +466,7 @@
fn_: keyword!(fn) >>
parens: parens!(do_parse!(
inputs: call!(Delimited::parse_terminated) >>
- variadic: option!(cond_reduce!(inputs.is_empty() || inputs.trailing_delim(),
- punct!(...))) >>
+ variadic: option!(cond_reduce!(inputs.empty_or_trailing(), punct!(...))) >>
(inputs, variadic)
)) >>
output: syn!(ReturnType) >>
@@ -523,7 +522,7 @@
qpath.1.segments.last().unwrap().item().arguments.is_empty(),
option!(syn!(ParenthesizedGenericArguments))
) >>
- cond!(allow_plus, not!(peek!(punct!(+)))) >>
+ cond!(allow_plus, not!(punct!(+))) >>
({
let (qself, mut path) = qpath;
if let Some(Some(parenthesized)) = parenthesized {
@@ -549,7 +548,7 @@
let (pos, as_, path) = match path {
Some((as_, mut path)) => {
let pos = path.segments.len();
- if !path.segments.is_empty() && !path.segments.trailing_delim() {
+ if !path.segments.empty_or_trailing() {
path.segments.push_trailing(colon2);
}
for item in rest {
@@ -653,7 +652,7 @@
impl TypeParen {
named!(parse(allow_plus: bool) -> Self, do_parse!(
data: parens!(syn!(Type)) >>
- cond!(allow_plus, not!(peek!(punct!(+)))) >>
+ cond!(allow_plus, not!(punct!(+))) >>
(TypeParen {
paren_token: data.1,
elem: Box::new(data.0),
@@ -733,7 +732,11 @@
));
}
- named!(pub ty_no_eq_after -> Type, terminated!(syn!(Type), not!(punct!(=))));
+ named!(pub ty_no_eq_after -> Type, do_parse!(
+ ty: syn!(Type) >>
+ not!(punct!(=)) >>
+ (ty)
+ ));
impl Path {
named!(pub parse_mod_style -> Self, do_parse!(