//! [`parse_macro_input!`]: ../macro.parse_macro_input.html
//!
//! ```
-//! extern crate proc_macro;
-//!
+//! # extern crate proc_macro;
+//! #
//! use proc_macro::TokenStream;
//! use syn::{braced, parse_macro_input, token, Field, Ident, Result, Token};
//! use syn::parse::{Parse, ParseStream};
//! [`Parser`]: trait.Parser.html
//!
//! ```
-//! extern crate proc_macro;
-//!
+//! # extern crate proc_macro;
+//! #
//! use proc_macro::TokenStream;
//! use syn::parse::Parser;
//! use syn::punctuated::Punctuated;
//!
//! ---
//!
-//! *This module is available if Syn is built with the `"parsing"` feature.*
+//! *This module is available only if Syn is built with the `"parsing"` feature.*
#[path = "discouraged.rs"]
pub mod discouraged;
/// 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 implementing and using
+/// the `Parse` trait.
+///
+/// [module documentation]: self
pub trait Parse: Sized {
fn parse(input: ParseStream) -> Result<Self>;
}
impl<'a> Drop for ParseBuffer<'a> {
fn drop(&mut self) {
- if !self.is_empty() {
+ if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(self.cursor()) {
let (inner, old_span) = inner_unexpected(self);
if old_span.is_none() {
- inner.set(Unexpected::Some(self.cursor().span()));
+ inner.set(Unexpected::Some(unexpected_span));
}
}
}
unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(to) }
}
-fn skip(input: ParseStream) -> bool {
- input
- .step(|cursor| {
- if let Some((_lifetime, rest)) = cursor.lifetime() {
- Ok((true, rest))
- } else if let Some((_token, rest)) = cursor.token_tree() {
- Ok((true, rest))
- } else {
- Ok((false, *cursor))
- }
- })
- .unwrap()
-}
-
pub(crate) fn new_parse_buffer(
scope: Span,
cursor: Cursor,
cell_clone(&buffer.unexpected).unwrap()
}
+fn span_of_unexpected_ignoring_nones(mut cursor: Cursor) -> Option<Span> {
+ if cursor.eof() {
+ return None;
+ }
+ while let Some((inner, _span, rest)) = cursor.group(Delimiter::None) {
+ if let Some(unexpected) = span_of_unexpected_ignoring_nones(inner) {
+ return Some(unexpected);
+ }
+ cursor = rest;
+ }
+ if cursor.eof() {
+ None
+ } else {
+ Some(cursor.span())
+ }
+}
+
impl<'a> ParseBuffer<'a> {
/// Parses a syntax tree node of type `T`, advancing the position of our
/// parse stream past it.
/// }
/// ```
pub fn peek2<T: Peek>(&self, token: T) -> bool {
- let ahead = self.fork();
- skip(&ahead) && ahead.peek(token)
+ let _ = token;
+ self.cursor().skip().map_or(false, T::Token::peek)
}
/// Looks at the third-next token in the parse stream.
pub fn peek3<T: Peek>(&self, token: T) -> bool {
- let ahead = self.fork();
- skip(&ahead) && skip(&ahead) && ahead.peek(token)
+ let _ = token;
+ self.cursor()
+ .skip()
+ .and_then(Cursor::skip)
+ .map_or(false, T::Token::peek)
}
/// Parses zero or more occurrences of `T` separated by punctuation of type
Ok(node)
}
+ /// Returns the `Span` of the next token in the parse stream, or
+ /// `Span::call_site()` if this parse stream has completely exhausted its
+ /// input `TokenStream`.
+ pub fn span(&self) -> Span {
+ let cursor = self.cursor();
+ if cursor.eof() {
+ self.scope
+ } else {
+ crate::buffer::open_span_of_group(cursor)
+ }
+ }
+
/// Provides low-level access to the token representation underlying this
/// parse stream.
///
///
/// [module documentation]: self
///
-/// *This trait is available if Syn is built with the `"parsing"` feature.*
+/// *This trait is available only if Syn is built with the `"parsing"` feature.*
pub trait Parser: Sized {
type Output;
/// This function will check that the input is fully parsed. If there are
/// any unparsed tokens at the end of the stream, an error is returned.
///
- /// *This method is available if Syn is built with both the `"parsing"` and
+ /// *This method is available only if Syn is built with both the `"parsing"` and
/// `"proc-macro"` features.*
#[cfg(all(
not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
// Not public API.
#[doc(hidden)]
+ #[cfg(any(feature = "full", feature = "derive"))]
fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
let _ = scope;
self.parse2(tokens)
// Not public API.
#[doc(hidden)]
+ #[cfg(any(feature = "full", feature = "derive"))]
fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
input.parse().and_then(|tokens| self.parse2(tokens))
}
let state = tokens_to_parse_buffer(&buf);
let node = self(&state)?;
state.check_unexpected()?;
- if state.is_empty() {
- Ok(node)
+ if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(state.cursor()) {
+ Err(Error::new(unexpected_span, "unexpected token"))
} else {
- Err(state.error("unexpected token"))
+ Ok(node)
}
}
#[doc(hidden)]
+ #[cfg(any(feature = "full", feature = "derive"))]
fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
let buf = TokenBuffer::new2(tokens);
let cursor = buf.begin();
let state = new_parse_buffer(scope, cursor, unexpected);
let node = self(&state)?;
state.check_unexpected()?;
- if state.is_empty() {
- Ok(node)
+ if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(state.cursor()) {
+ Err(Error::new(unexpected_span, "unexpected token"))
} else {
- Err(state.error("unexpected token"))
+ Ok(node)
}
}
#[doc(hidden)]
+ #[cfg(any(feature = "full", feature = "derive"))]
fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
self(input)
}
}
+#[cfg(any(feature = "full", feature = "derive"))]
pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) -> Result<F::Output> {
f.__parse_scoped(scope, tokens)
}
+#[cfg(any(feature = "full", feature = "derive"))]
pub(crate) fn parse_stream<F: Parser>(f: F, input: ParseStream) -> Result<F::Output> {
f.__parse_stream(input)
}
/// provided any attribute args.
///
/// ```
-/// extern crate proc_macro;
-///
+/// # extern crate proc_macro;
+/// #
/// use proc_macro::TokenStream;
/// use syn::parse_macro_input;
/// use syn::parse::Nothing;