Some more compelling synom examples
diff --git a/synom/src/helper.rs b/synom/src/helper.rs
index e4ada4b..fb04d53 100644
--- a/synom/src/helper.rs
+++ b/synom/src/helper.rs
@@ -1,7 +1,10 @@
use IResult;
use space::{skip_whitespace, word_break};
-/// Parse a piece of punctuation, skipping whitespace before it.
+/// Parse a piece of punctuation like "+" or "+=".
+///
+/// See also `keyword!` for parsing keywords, which are subtly different from
+/// punctuation.
///
/// - **Syntax:** `punct!("...")`
/// - **Output:** `&str`
@@ -10,11 +13,15 @@
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
-/// named!(bang -> &str, punct!("!"));
+/// // Parse zero or more bangs.
+/// named!(many_bangs -> Vec<&str>,
+/// many0!(punct!("!"))
+/// );
///
/// fn main() {
-/// let input = " !";
-/// bang(input).expect("bang");
+/// let input = "!! !";
+/// let parsed = many_bangs(input).expect("bangs");
+/// assert_eq!(parsed, ["!", "!", "!"]);
/// }
/// ```
#[macro_export]
@@ -35,7 +42,10 @@
}
}
-/// Parse a keyword. The word must make up a complete identifier.
+/// Parse a keyword like "fn" or "struct".
+///
+/// See also `punct!` for parsing punctuation, which are subtly different from
+/// keywords.
///
/// - **Syntax:** `keyword!("...")`
/// - **Output:** `&str`
@@ -44,13 +54,24 @@
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
-/// named!(apple -> &str, keyword!("apple"));
+/// use synom::IResult;
+///
+/// // Parse zero or more "bang" keywords.
+/// named!(many_bangs -> Vec<&str>,
+/// terminated!(
+/// many0!(keyword!("bang")),
+/// punct!(";")
+/// )
+/// );
///
/// fn main() {
-/// let input = " apple";
-/// apple(input).expect("apple");
-/// let input = "apples";
-/// assert_eq!(apple(input), synom::IResult::Error);
+/// let input = "bang bang bang;";
+/// let parsed = many_bangs(input).expect("bangs");
+/// assert_eq!(parsed, ["bang", "bang", "bang"]);
+///
+/// let input = "bangbang;";
+/// let err = many_bangs(input);
+/// assert_eq!(err, IResult::Error);
/// }
/// ```
#[macro_export]
@@ -74,11 +95,10 @@
}
}
-/// Try to run the parser and wrap it in an `Option`, if it fails, succeed but
-/// produce a `None`.
+/// Turn a failed parse into `None` and a successful parse into `Some`.
///
/// - **Syntax:** `option!(THING)`
-/// - **Output:** `THING`
+/// - **Output:** `Option<THING>`
///
/// ```rust
/// extern crate syn;
@@ -87,10 +107,13 @@
/// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
///
/// fn main() {
-/// let input = " !";
-/// assert_eq!(maybe_bang(input).expect("maybe bang"), Some("!"));
+/// let input = "!";
+/// let parsed = maybe_bang(input).expect("maybe bang");
+/// assert_eq!(parsed, Some("!"));
+///
/// let input = "";
-/// assert_eq!(maybe_bang(input).expect("maybe bang"), None);
+/// let parsed = maybe_bang(input).expect("maybe bang");
+/// assert_eq!(parsed, None);
/// }
/// ```
#[macro_export]
@@ -107,31 +130,43 @@
};
}
-/// Try to run the parser, if it fails, succeed and produce an empty Vec.
+/// Turn a failed parse into an empty vector. The argument parser must itself
+/// return a vector.
///
-/// The argument parser must be a Vec.
+/// This is often more convenient than `option!(...)` when the argument produces
+/// a vector.
///
/// - **Syntax:** `opt_vec!(THING)`
-/// - **Output:** `THING`
+/// - **Output:** `THING`, which must be `Vec<T>`
///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
///
-/// use syn::Expr;
-/// use syn::parse::expr;
+/// use syn::{Lifetime, Ty};
+/// use syn::parse::{lifetime, ty};
///
-/// named!(opt_expr_list -> Vec<Expr>, opt_vec!(
-/// separated_list!(punct!(","), expr)));
+/// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
+/// opt_vec!(do_parse!(
+/// keyword!("for") >>
+/// punct!("<") >>
+/// lifetimes: terminated_list!(punct!(","), lifetime) >>
+/// punct!(">") >>
+/// (lifetimes)
+/// )),
+/// ty
+/// ));
///
/// fn main() {
-/// let input = "a, 1 + 1, Object { construct: ion }";
-/// let result = opt_expr_list(input).expect("opt expr list");
-/// assert_eq!(result.len(), 3);
+/// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
+/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
+/// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
+/// println!("{:?}", parsed);
///
-/// let input = "";
-/// let result = opt_expr_list(input).expect("opt expr list");
-/// assert_eq!(result.len(), 0);
+/// let input = "From<String>";
+/// let parsed = bound_lifetimes(input).expect("bound lifetimes");
+/// assert!(parsed.0.is_empty());
+/// println!("{:?}", parsed);
/// }
/// ```
#[macro_export]
@@ -146,17 +181,31 @@
/// Parses nothing and always succeeds.
///
+/// This can be useful as a fallthrough case in `alt!`.
+///
/// - **Syntax:** `epsilon!()`
/// - **Output:** `()`
///
/// ```rust
+/// extern crate syn;
/// #[macro_use] extern crate synom;
///
-/// named!(epsi -> (), epsilon!());
+/// use syn::Mutability;
+///
+/// named!(mutability -> Mutability, alt!(
+/// keyword!("mut") => { |_| Mutability::Mutable }
+/// |
+/// epsilon!() => { |_| Mutability::Immutable }
+/// ));
///
/// fn main() {
+/// let input = "mut";
+/// let parsed = mutability(input).expect("mutability");
+/// assert_eq!(parsed, Mutability::Mutable);
+///
/// let input = "";
-/// assert_eq!(epsi(input).expect("maybe bang"), ());
+/// let parsed = mutability(input).expect("mutability");
+/// assert_eq!(parsed, Mutability::Immutable);
/// }
/// ```
#[macro_export]
@@ -181,7 +230,7 @@
/// use syn::{Expr, ExprKind};
/// use syn::parse::expr;
///
-/// named!(pub expr_with_arrow_call -> Expr, do_parse!(
+/// named!(expr_with_arrow_call -> Expr, do_parse!(
/// mut e: expr >>
/// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
/// e = Expr {
@@ -195,11 +244,12 @@
/// fn main() {
/// let input = "something => argument1 => argument2";
///
-/// let result = expr_with_arrow_call(input).expect("expr with arrow call");
+/// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
///
-/// println!("result = {:?}", result);
+/// println!("{:?}", parsed);
/// }
/// ```
+#[doc(hidden)]
#[macro_export]
macro_rules! tap {
($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
@@ -218,8 +268,8 @@
};
}
-/// Parses a series of things, separated by the given punctuation. Does not
-/// allow for a trailing seperator.
+/// Zero or more values separated by some separator. Does not allow a trailing
+/// seperator.
///
/// The implementation requires that the first parameter is a `punct!` macro,
/// and the second is a named parser.
@@ -227,6 +277,12 @@
/// - **Syntax:** `separated_list!(punct!("..."), THING)`
/// - **Output:** `Vec<THING>`
///
+/// You may also be looking for:
+///
+/// - `separated_nonempty_list!` - one or more values
+/// - `terminated_list!` - zero or more, allows trailing separator
+/// - `many0!` - zero or more, no separator
+///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
@@ -234,14 +290,15 @@
/// use syn::Expr;
/// use syn::parse::expr;
///
-/// named!(pub expr_list -> Vec<Expr>,
-/// separated_list!(punct!(","), expr));
+/// named!(expr_list -> Vec<Expr>,
+/// separated_list!(punct!(","), expr)
+/// );
///
/// fn main() {
/// let input = "1 + 1, things, Construct { this: thing }";
///
-/// let result = expr_list(input).expect("expr list");
-/// assert_eq!(result.len(), 3);
+/// let parsed = expr_list(input).expect("expr list");
+/// assert_eq!(parsed.len(), 3);
/// }
/// ```
#[macro_export]
@@ -251,8 +308,8 @@
};
}
-/// Parses a series of things, separated by the given punctuation. Allows for
-/// a trailing seperator.
+/// Zero or more values separated by some separator. A trailing separator is
+/// allowed.
///
/// The implementation requires that the first parameter is a `punct!` macro,
/// and the second is a named parser.
@@ -260,6 +317,12 @@
/// - **Syntax:** `terminated_list!(punct!("..."), THING)`
/// - **Output:** `Vec<THING>`
///
+/// You may also be looking for:
+///
+/// - `separated_list!` - zero or more, allows trailing separator
+/// - `separated_nonempty_list!` - one or more values
+/// - `many0!` - zero or more, no separator
+///
/// ```rust
/// extern crate syn;
/// #[macro_use] extern crate synom;
@@ -267,14 +330,15 @@
/// use syn::Expr;
/// use syn::parse::expr;
///
-/// named!(pub expr_list -> Vec<Expr>,
-/// terminated_list!(punct!(","), expr));
+/// named!(expr_list -> Vec<Expr>,
+/// terminated_list!(punct!(","), expr)
+/// );
///
/// fn main() {
/// let input = "1 + 1, things, Construct { this: thing },";
///
-/// let result = expr_list(input).expect("expr list");
-/// assert_eq!(result.len(), 3);
+/// let parsed = expr_list(input).expect("expr list");
+/// assert_eq!(parsed.len(), 3);
/// }
/// ```
#[macro_export]