Provide a trait to invoke parser functions
diff --git a/src/lib.rs b/src/lib.rs
index afe414f..98aea1d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -509,9 +509,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 #[cfg(feature = "parsing")]
-use synom::Synom;
-#[cfg(feature = "parsing")]
-use buffer::TokenBuffer;
+use synom::{Synom, Parser};
 
 #[cfg(feature = "parsing")]
 mod error;
@@ -594,25 +592,13 @@
 where
     T: Synom,
 {
-    let buf = TokenBuffer::new2(tokens);
-    let result = T::parse(buf.begin());
-    let err = match result {
-        Ok((t, rest)) => {
-            if rest.eof() {
-                return Ok(t);
-            } else if rest == buf.begin() {
-                // parsed nothing
-                ParseError::new("failed to parse anything")
-            } else {
-                ParseError::new("failed to parse all tokens")
-            }
+    let parser = T::parse;
+    parser.parse2(tokens).map_err(|err| {
+        match T::description() {
+            Some(s) => ParseError::new(format!("failed to parse {}: {}", s, err)),
+            None => err,
         }
-        Err(err) => err,
-    };
-    match T::description() {
-        Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
-        None => Err(err),
-    }
+    })
 }
 
 /// Parse a string of Rust code into the chosen syntax tree node.
diff --git a/src/synom.rs b/src/synom.rs
index d14c3f8..5db92d3 100644
--- a/src/synom.rs
+++ b/src/synom.rs
@@ -8,14 +8,115 @@
 
 //! Parsing interface for parsing a token stream into a syntax tree node.
 //!
-//! All syntax tree nodes that can be parsed from a token stream need to
-//! implement the [`Synom`] trait. This trait is usually implemented using the
-//! [`nom`]-style parser combinator macros provided by Syn, but may also be
-//! implemented without macros be using the low-level [`Cursor`] API directly.
+//! Parsing in Syn is built on parser functions that take in a [`Cursor`] and
+//! produce a [`PResult<T>`] where `T` is some syntax tree node. `Cursor` is a
+//! cheaply copyable cursor over a range of tokens in a token stream, and
+//! `PResult` is a result that packages together a parsed syntax tree node `T`
+//! with a stream of remaining unparsed tokens after `T` represented as another
+//! `Cursor`, or a [`ParseError`] if parsing failed.
 //!
-//! [`Synom`]: trait.Synom.html
-//! [`nom`]: https://github.com/Geal/nom
 //! [`Cursor`]: ../buffer/index.html
+//! [`PResult<T>`]: type.PResult.html
+//! [`ParseError`]: struct.ParseError.html
+//!
+//! This `Cursor`- and `PResult`-based interface is convenient for parser
+//! combinators and parser implementations, but not necessarily when you just
+//! have some tokens that you want to parse. For that we expose the following
+//! two entry points.
+//!
+//! ## The `syn::parse*` functions
+//!
+//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve
+//! as an entry point for parsing syntax tree nodes that can be parsed in an
+//! obvious default way. These functions can return any syntax tree node that
+//! implements the [`Synom`] trait, which includes most types in Syn.
+//!
+//! [`syn::parse`]: ../fn.parse.html
+//! [`syn::parse2`]: ../fn.parse2.html
+//! [`syn::parse_str`]: ../fn.parse_str.html
+//! [`Synom`]: trait.Synom.html
+//!
+//! ```
+//! use syn::Type;
+//!
+//! # fn run_parser() -> Result<(), syn::synom::ParseError> {
+//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
+//! #     Ok(())
+//! # }
+//! #
+//! # fn main() {
+//! #     run_parser().unwrap();
+//! # }
+//! ```
+//!
+//! ## The `Parser` trait
+//!
+//! Some types can be parsed in several ways depending on context. For example
+//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like
+//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`]
+//! may or may not allow trailing punctuation, and parsing it the wrong way
+//! would either reject valid input or accept invalid input.
+//!
+//! [`Attribute`]: ../struct.Attribute.html
+//! [`Punctuated`]: ../punctuated/index.html
+//!
+//! The `Synom` trait is not implemented in these cases because there is no good
+//! behavior to consider the default.
+//!
+//! ```ignore
+//! // Can't parse `Punctuated` without knowing whether trailing punctuation
+//! // should be allowed in this context.
+//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?;
+//! ```
+//!
+//! In these cases the types provide a choice of parser functions rather than a
+//! single `Synom` implementation, and those parser functions can be invoked
+//! through the [`Parser`] trait.
+//!
+//! [`Parser`]: trait.Parser.html
+//!
+//! ```
+//! # #[macro_use]
+//! # extern crate syn;
+//! #
+//! # extern crate proc_macro2;
+//! # use proc_macro2::TokenStream;
+//! #
+//! use syn::synom::Parser;
+//! use syn::punctuated::Punctuated;
+//! use syn::{PathSegment, Expr, Attribute};
+//!
+//! # fn run_parsers() -> Result<(), syn::synom::ParseError> {
+//! #     let tokens = TokenStream::empty().into();
+//! // Parse a nonempty sequence of path segments separated by `::` punctuation
+//! // with no trailing punctuation.
+//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty;
+//! let path = parser.parse(tokens)?;
+//!
+//! #     let tokens = TokenStream::empty().into();
+//! // Parse a possibly empty sequence of expressions terminated by commas with
+//! // an optional trailing punctuation.
+//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated;
+//! let args = parser.parse(tokens)?;
+//!
+//! #     let tokens = TokenStream::empty().into();
+//! // Parse zero or more outer attributes but not inner attributes.
+//! named!(outer_attrs -> Vec<Attribute>, many0!(Attribute::parse_outer));
+//! let attrs = outer_attrs.parse(tokens)?;
+//! #
+//! #     Ok(())
+//! # }
+//! #
+//! # fn main() {}
+//! ```
+//!
+//! # Implementing a parser function
+//!
+//! Parser functions are usually implemented using the [`nom`]-style parser
+//! combinator macros provided by Syn, but may also be implemented without
+//! macros be using the low-level [`Cursor`] API directly.
+//!
+//! [`nom`]: https://github.com/Geal/nom
 //!
 //! The following parser combinator macros are available and a `Synom` parsing
 //! example is provided for each one.
@@ -44,14 +145,15 @@
 //!
 //! *This module is available if Syn is built with the `"parsing"` feature.*
 
-use proc_macro2::TokenStream;
+use proc_macro;
+use proc_macro2;
 
 pub use error::{PResult, ParseError};
 
-use buffer::Cursor;
+use buffer::{Cursor, TokenBuffer};
 
-/// Parsing interface implemented by all types that can be parsed from a token
-/// stream.
+/// Parsing interface implemented by all types that can be parsed in a default
+/// way from a token stream.
 ///
 /// Refer to the [module documentation] for details about parsing in Syn.
 ///
@@ -66,7 +168,7 @@
     }
 }
 
-impl Synom for TokenStream {
+impl Synom for proc_macro2::TokenStream {
     fn parse(input: Cursor) -> PResult<Self> {
         Ok((input.token_stream(), Cursor::empty()))
     }
@@ -75,3 +177,44 @@
         Some("arbitrary token stream")
     }
 }
+
+/// Parser that can parse Rust tokens into a particular syntax tree node.
+///
+/// Refer to the [module documentation] for details about parsing in Syn.
+///
+/// [module documentation]: index.html
+///
+/// *This trait is available if Syn is built with the `"parsing"` feature.*
+pub trait Parser: Sized {
+    type Output;
+
+    fn parse2(self, tokens: proc_macro2::TokenStream) -> Result<Self::Output, ParseError>;
+
+    fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output, ParseError> {
+        self.parse2(tokens.into())
+    }
+
+    fn parse_str(self, s: &str) -> Result<Self::Output, ParseError> {
+        match s.parse() {
+            Ok(tts) => self.parse2(tts),
+            Err(_) => Err(ParseError::new("error while lexing input string")),
+        }
+    }
+}
+
+impl<F, T> Parser for F where F: FnOnce(Cursor) -> PResult<T> {
+    type Output = T;
+
+    fn parse2(self, tokens: proc_macro2::TokenStream) -> Result<T, ParseError> {
+        let buf = TokenBuffer::new2(tokens);
+        let (t, rest) = self(buf.begin())?;
+        if rest.eof() {
+            Ok(t)
+        } else if rest == buf.begin() {
+            // parsed nothing
+            Err(ParseError::new("failed to parse anything"))
+        } else {
+            Err(ParseError::new("failed to parse all tokens"))
+        }
+    }
+}