Separated/terminated_list for more flexible arguments
diff --git a/synom/src/helper.rs b/synom/src/helper.rs
index fb04d53..bcddd2e 100644
--- a/synom/src/helper.rs
+++ b/synom/src/helper.rs
@@ -271,9 +271,6 @@
 /// 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.
-///
 /// - **Syntax:** `separated_list!(punct!("..."), THING)`
 /// - **Output:** `Vec<THING>`
 ///
@@ -301,19 +298,91 @@
 ///     assert_eq!(parsed.len(), 3);
 /// }
 /// ```
+///
+/// ```rust
+/// extern crate syn;
+/// #[macro_use] extern crate synom;
+///
+/// use syn::Ident;
+/// use syn::parse::ident;
+///
+/// named!(run_on -> Vec<Ident>,
+///     terminated!(
+///         separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
+///         punct!("...")
+///     )
+/// );
+///
+/// fn main() {
+///     let input = "$expr and $ident and $pat ...";
+///
+///     let parsed = run_on(input).expect("run-on sentence");
+///     assert_eq!(parsed.len(), 3);
+///     assert_eq!(parsed[0], "expr");
+///     assert_eq!(parsed[1], "ident");
+///     assert_eq!(parsed[2], "pat");
+/// }
+/// ```
 #[macro_export]
 macro_rules! separated_list {
+    // Try to use this branch if possible - makes a difference in compile time.
     ($i:expr, punct!($sep:expr), $f:expr) => {
         $crate::helper::separated_list($i, $sep, $f, false)
     };
+
+    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
+        let mut res = ::std::vec::Vec::new();
+        let mut input = $i;
+
+        // get the first element
+        match $fmac!(input, $($fargs)*) {
+            $crate::IResult::Error => $crate::IResult::Done(input, res),
+            $crate::IResult::Done(i, o) => {
+                if i.len() == input.len() {
+                    $crate::IResult::Error
+                } else {
+                    res.push(o);
+                    input = i;
+
+                    // get the separator first
+                    while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
+                        if i2.len() == input.len() {
+                            break;
+                        }
+
+                        // get the element next
+                        if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
+                            if i3.len() == i2.len() {
+                                break;
+                            }
+                            res.push(o3);
+                            input = i3;
+                        } else {
+                            break;
+                        }
+                    }
+                    $crate::IResult::Done(input, res)
+                }
+            }
+        }
+    }};
+
+    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
+        separated_list!($i, $sepmac!($(separgs)*), call!($f))
+    };
+
+    ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
+        separated_list!($i, call!($sep), $fmac!($(fargs)*))
+    };
+
+    ($i:expr, $sep:expr, $f:expr) => {
+        separated_list!($i, call!($sep), call!($f))
+    };
 }
 
 /// 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.
-///
 /// - **Syntax:** `terminated_list!(punct!("..."), THING)`
 /// - **Output:** `Vec<THING>`
 ///
@@ -341,11 +410,89 @@
 ///     assert_eq!(parsed.len(), 3);
 /// }
 /// ```
+///
+/// ```rust
+/// extern crate syn;
+/// #[macro_use] extern crate synom;
+///
+/// use syn::Ident;
+/// use syn::parse::ident;
+///
+/// named!(run_on -> Vec<Ident>,
+///     terminated!(
+///         terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
+///         punct!("...")
+///     )
+/// );
+///
+/// fn main() {
+///     let input = "$expr and $ident and $pat and ...";
+///
+///     let parsed = run_on(input).expect("run-on sentence");
+///     assert_eq!(parsed.len(), 3);
+///     assert_eq!(parsed[0], "expr");
+///     assert_eq!(parsed[1], "ident");
+///     assert_eq!(parsed[2], "pat");
+/// }
+/// ```
 #[macro_export]
 macro_rules! terminated_list {
-    ($i:expr, punct!($sep:expr), $f:expr) => {
+    // Try to use this branch if possible - makes a difference in compile time.
+    ($i:expr, punct!($sep:expr), $f:ident) => {
         $crate::helper::separated_list($i, $sep, $f, true)
     };
+
+    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $fmac:ident!( $($fargs:tt)* )) => {{
+        let mut res = ::std::vec::Vec::new();
+        let mut input = $i;
+
+        // get the first element
+        match $fmac!(input, $($fargs)*) {
+            $crate::IResult::Error => $crate::IResult::Done(input, res),
+            $crate::IResult::Done(i, o) => {
+                if i.len() == input.len() {
+                    $crate::IResult::Error
+                } else {
+                    res.push(o);
+                    input = i;
+
+                    // get the separator first
+                    while let $crate::IResult::Done(i2, _) = $sepmac!(input, $($separgs)*) {
+                        if i2.len() == input.len() {
+                            break;
+                        }
+
+                        // get the element next
+                        if let $crate::IResult::Done(i3, o3) = $fmac!(i2, $($fargs)*) {
+                            if i3.len() == i2.len() {
+                                break;
+                            }
+                            res.push(o3);
+                            input = i3;
+                        } else {
+                            break;
+                        }
+                    }
+                    if let $crate::IResult::Done(after, _) = $sepmac!(input, $($separgs)*) {
+                        input = after;
+                    }
+                    $crate::IResult::Done(input, res)
+                }
+            }
+        }
+    }};
+
+    ($i:expr, $sepmac:ident!( $($separgs:tt)* ), $f:expr) => {
+        terminated_list!($i, $sepmac!($(separgs)*), call!($f))
+    };
+
+    ($i:expr, $sep:expr, $fmac:ident!( $($fargs:tt)* )) => {
+        terminated_list!($i, call!($sep), $fmac!($(fargs)*))
+    };
+
+    ($i:expr, $sep:expr, $f:expr) => {
+        terminated_list!($i, call!($sep), call!($f))
+    };
 }
 
 // Not public API.
@@ -359,7 +506,7 @@
 
     // get the first element
     match f(input) {
-        IResult::Error => IResult::Done(input, Vec::new()),
+        IResult::Error => IResult::Done(input, res),
         IResult::Done(i, o) => {
             if i.len() == input.len() {
                 IResult::Error