#[cfg(feature = "parsing")] usecrate::buffer::Cursor; usecrate::thread::ThreadBound; use proc_macro2::{
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
}; #[cfg(feature = "printing")] use quote::ToTokens; use std::fmt::{self, Debug, Display}; use std::slice; use std::vec;
/// The result of a Syn parser. pubtype Result<T> = std::result::Result<T, Error>;
/// Error returned when a Syn parser cannot parse the input tokens. /// /// # Error reporting in proc macros /// /// The correct way to report errors back to the compiler from a procedural /// macro is by emitting an appropriately spanned invocation of /// [`compile_error!`] in the generated code. This produces a better diagnostic /// message than simply panicking the macro. /// /// [`compile_error!`]: std::compile_error! /// /// When parsing macro input, the [`parse_macro_input!`] macro handles the /// conversion to `compile_error!` automatically. /// /// [`parse_macro_input!`]: crate::parse_macro_input! /// /// ``` /// # extern crate proc_macro; /// # /// use proc_macro::TokenStream; /// use syn::parse::{Parse, ParseStream, Result}; /// use syn::{parse_macro_input, ItemFn}; /// /// # const IGNORE: &str = stringify! { /// #[proc_macro_attribute] /// # }; /// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { /// let args = parse_macro_input!(args as MyAttrArgs); /// let input = parse_macro_input!(input as ItemFn); /// /// /* ... */ /// # TokenStream::new() /// } /// /// struct MyAttrArgs { /// # _k: [(); { stringify! { /// ... /// # }; 0 }] /// } /// /// impl Parse for MyAttrArgs { /// fn parse(input: ParseStream) -> Result<Self> { /// # stringify! { /// ... /// # }; /// # unimplemented!() /// } /// } /// ``` /// /// For errors that arise later than the initial parsing stage, the /// [`.to_compile_error()`] or [`.into_compile_error()`] methods can be used to /// perform an explicit conversion to `compile_error!`. /// /// [`.to_compile_error()`]: Error::to_compile_error /// [`.into_compile_error()`]: Error::into_compile_error /// /// ``` /// # extern crate proc_macro; /// # /// # use proc_macro::TokenStream; /// # use syn::{parse_macro_input, DeriveInput}; /// # /// # const IGNORE: &str = stringify! { /// #[proc_macro_derive(MyDerive)] /// # }; /// pub fn my_derive(input: TokenStream) -> TokenStream { /// let input = parse_macro_input!(input as DeriveInput); /// /// // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream> /// expand::my_derive(input) /// .unwrap_or_else(syn::Error::into_compile_error) /// .into() /// } /// # /// # mod expand { /// # use proc_macro2::TokenStream; /// # use syn::{DeriveInput, Result}; /// # /// # pub fn my_derive(input: DeriveInput) -> Result<TokenStream> { /// # unimplemented!() /// # } /// # } /// ``` pubstruct Error {
messages: Vec<ErrorMessage>,
}
struct ErrorMessage { // Span is implemented as an index into a thread-local interner to keep the // size small. It is not safe to access from a different thread. We want // errors to be Send and Sync to play nicely with ecosystem crates for error // handling, so pin the span we're given to its original thread and assume // it is Span::call_site if accessed from any other thread.
span: ThreadBound<SpanRange>,
message: String,
}
// Cannot use std::ops::Range<Span> because that does not implement Copy, // whereas ThreadBound<T> requires a Copy impl as a way to ensure no Drop impls // are involved. struct SpanRange {
start: Span,
end: Span,
}
#[cfg(test)] struct _Test where
Error: Send + Sync;
impl Error { /// Usually the [`ParseStream::error`] method will be used instead, which /// automatically uses the correct span from the current position of the /// parse stream. /// /// Use `Error::new` when the error needs to be triggered on some span other /// than where the parse stream is currently positioned. /// /// [`ParseStream::error`]: crate::parse::ParseBuffer::error /// /// # Example /// /// ``` /// use syn::{Error, Ident, LitStr, Result, Token}; /// use syn::parse::ParseStream; /// /// // Parses input that looks like `name = "string"` where the key must be /// // the identifier `name` and the value may be any string literal. /// // Returns the string literal. /// fn parse_name(input: ParseStream) -> Result<LitStr> { /// let name_token: Ident = input.parse()?; /// if name_token != "name" { /// // Trigger an error not on the current position of the stream, /// // but on the position of the unexpected identifier. /// return Err(Error::new(name_token.span(), "expected `name`")); /// } /// input.parse::<Token![=]>()?; /// let s: LitStr = input.parse()?; /// Ok(s) /// } /// ``` pubfn new<T: Display>(span: Span, message: T) -> Self { return new(span, message.to_string());
/// Creates an error with the specified message spanning the given syntax /// tree node. /// /// Unlike the `Error::new` constructor, this constructor takes an argument /// `tokens` which is a syntax tree node. This allows the resulting `Error` /// to attempt to span all tokens inside of `tokens`. While you would /// typically be able to use the `Spanned` trait with the above `Error::new` /// constructor, implementation limitations today mean that /// `Error::new_spanned` may provide a higher-quality error message on /// stable Rust. /// /// When in doubt it's recommended to stick to `Error::new` (or /// `ParseStream::error`)! #[cfg(feature = "printing")] #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] pubfn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self { return new_spanned(tokens.into_token_stream(), message.to_string());
fn new_spanned(tokens: TokenStream, message: String) -> Error { letmut iter = tokens.into_iter(); let start = iter.next().map_or_else(Span::call_site, |t| t.span()); let end = iter.last().map_or(start, |t| t.span());
Error {
messages: vec![ErrorMessage {
span: ThreadBound::new(SpanRange { start, end }),
message,
}],
}
}
}
/// The source location of the error. /// /// Spans are not thread-safe so this function returns `Span::call_site()` /// if called from a different thread than the one on which the `Error` was /// originally created. pubfn span(&self) -> Span { let SpanRange { start, end } = matchself.messages[0].span.get() {
Some(span) => *span,
None => return Span::call_site(),
};
start.join(end).unwrap_or(start)
}
/// Render the error as an invocation of [`compile_error!`]. /// /// The [`parse_macro_input!`] macro provides a convenient way to invoke /// this method correctly in a procedural macro. /// /// [`compile_error!`]: std::compile_error! /// [`parse_macro_input!`]: crate::parse_macro_input! pubfn to_compile_error(&self) -> TokenStream { self.messages
.iter()
.map(ErrorMessage::to_compile_error)
.collect()
}
/// Render the error as an invocation of [`compile_error!`]. /// /// [`compile_error!`]: std::compile_error! /// /// # Example /// /// ``` /// # extern crate proc_macro; /// # /// use proc_macro::TokenStream; /// use syn::{parse_macro_input, DeriveInput, Error}; /// /// # const _: &str = stringify! { /// #[proc_macro_derive(MyTrait)] /// # }; /// pub fn derive_my_trait(input: TokenStream) -> TokenStream { /// let input = parse_macro_input!(input as DeriveInput); /// my_trait::expand(input) /// .unwrap_or_else(Error::into_compile_error) /// .into() /// } /// /// mod my_trait { /// use proc_macro2::TokenStream; /// use syn::{DeriveInput, Result}; /// /// pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> { /// /* ... */ /// # unimplemented!() /// } /// } /// ``` pubfn into_compile_error(self) -> TokenStream { self.to_compile_error()
}
/// Add another error message to self such that when `to_compile_error()` is /// called, both errors will be emitted together. pubfn combine(&mutself, another: Error) { self.messages.extend(another.messages);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.