Unify the error modules

This commit is contained in:
David Tolnay 2018-08-25 08:25:24 -04:00
parent 456c982ee2
commit ad4b247cf0
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
12 changed files with 134 additions and 162 deletions

View File

@ -6,9 +6,98 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use buffer::Cursor;
use std::error::Error;
use std;
use std::fmt::{self, Display};
use std::iter::FromIterator;
use proc_macro2::{
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
use buffer::Cursor;
/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;
/// Error returned when a Syn parser cannot parse the input tokens.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Debug)]
pub struct Error {
span: Span,
message: String,
}
impl Error {
pub fn new<T: Display>(span: Span, message: T) -> Self {
Error {
span: span,
message: message.to_string(),
}
}
/// 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!`]: https://doc.rust-lang.org/std/macro.compile_error.html
/// [`parse_macro_input!`]: ../macro.parse_macro_input.html
pub fn into_compile_error(self) -> TokenStream {
// compile_error!($message)
TokenStream::from_iter(vec![
TokenTree::Ident(Ident::new("compile_error", self.span)),
TokenTree::Punct({
let mut punct = Punct::new('!', Spacing::Alone);
punct.set_span(self.span);
punct
}),
TokenTree::Group({
let mut group = Group::new(Delimiter::Brace, {
TokenStream::from_iter(vec![TokenTree::Literal({
let mut string = Literal::string(&self.message);
string.set_span(self.span);
string
})])
});
group.set_span(self.span);
group
}),
])
}
}
// Not public API.
#[doc(hidden)]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
if cursor.eof() {
Error::new(scope, format!("unexpected end of input, {}", message))
} else {
Error::new(cursor.span(), message)
}
}
impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&self.message)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
"parse error"
}
}
impl From<LexError> for Error {
fn from(err: LexError) -> Self {
Error::new(Span::call_site(), format!("{:?}", err))
}
}
/// The result of a `Synom` parser.
///
@ -17,44 +106,11 @@ use std::fmt::{self, Display};
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
pub type PResult<'a, O> = Result<(O, Cursor<'a>), ParseError>;
pub type PResult<'a, O> = std::result::Result<(O, Cursor<'a>), Error>;
/// An error with a default error message.
///
/// NOTE: We should provide better error messages in the future.
pub fn parse_error<'a, O>() -> PResult<'a, O> {
Err(ParseError(None))
}
/// Error returned when a `Synom` parser cannot parse the input tokens.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Debug)]
pub struct ParseError(Option<String>);
impl Error for ParseError {
fn description(&self) -> &str {
match self.0 {
Some(ref desc) => desc,
None => "failed to parse",
}
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(self.description(), f)
}
}
impl ParseError {
// For syn use only. Not public API.
#[doc(hidden)]
pub fn new<T: Into<String>>(msg: T) -> Self {
ParseError(Some(msg.into()))
}
Err(Error::new(Span::call_site(), "parse error"))
}

View File

@ -582,11 +582,13 @@ mod span;
#[cfg(feature = "parsing")]
use synom::{Parser, Synom};
#[cfg(feature = "parsing")]
use proc_macro2::Span;
#[cfg(feature = "parsing")]
mod error;
pub mod error;
#[cfg(feature = "parsing")]
use error::ParseError;
use error::Error;
// Not public API.
#[cfg(feature = "parsing")]
@ -645,7 +647,7 @@ pub use error::parse_error;
feature = "parsing",
feature = "proc-macro"
))]
pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, Error>
where
T: Synom,
{
@ -665,13 +667,13 @@ where
///
/// *This function is available if Syn is built with the `"parsing"` feature.*
#[cfg(feature = "parsing")]
pub fn parse2<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
pub fn parse2<T>(tokens: proc_macro2::TokenStream) -> Result<T, Error>
where
T: Synom,
{
let parser = T::parse;
parser.parse2(tokens).map_err(|err| match T::description() {
Some(s) => ParseError::new(format!("failed to parse {}: {}", s, err)),
Some(s) => Error::new(Span::call_site(), format!("failed to parse {}: {}", s, err)),
None => err,
})
}
@ -705,10 +707,10 @@ where
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "parsing")]
pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
pub fn parse_str<T: Synom>(s: &str) -> Result<T, Error> {
match s.parse() {
Ok(tts) => parse2(tts),
Err(_) => Err(ParseError::new("error while lexing input string")),
Err(_) => Err(Error::new(Span::call_site(), "error while lexing input string")),
}
}
@ -753,7 +755,7 @@ pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
/// # fn main() { run().unwrap() }
/// ```
#[cfg(all(feature = "parsing", feature = "full"))]
pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
pub fn parse_file(mut content: &str) -> Result<File, Error> {
// Strip the BOM if it is present
const BOM: &'static str = "\u{feff}";
if content.starts_with(BOM) {

View File

@ -15,7 +15,7 @@ use proc_macro2::Ident;
#[cfg(feature = "parsing")]
use proc_macro2::TokenStream;
#[cfg(feature = "parsing")]
use {ParseError, Synom};
use {Error, Synom};
use proc_macro2::TokenTree;
@ -122,12 +122,12 @@ impl LitStr {
///
/// All spans in the syntax tree will point to the span of this `LitStr`.
#[cfg(feature = "parsing")]
pub fn parse<T: Synom>(&self) -> Result<T, ParseError> {
pub fn parse<T: Synom>(&self) -> Result<T, Error> {
use proc_macro2::Group;
// Parse string literal into a token stream with every span equal to the
// original literal's span.
fn spanned_tokens(s: &LitStr) -> Result<TokenStream, ParseError> {
fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
let stream = ::parse_str(&s.value())?;
Ok(respan_token_stream(stream, s.span()))
}

View File

@ -1,86 +0,0 @@
use std;
use std::fmt::{self, Display};
use std::iter::FromIterator;
use proc_macro2::{
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
use buffer::Cursor;
/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;
/// Error returned when a Syn parser cannot parse the input tokens.
#[derive(Debug)]
pub struct Error {
span: Span,
message: String,
}
impl Error {
pub fn new<T: Display>(span: Span, message: T) -> Self {
Error {
span: span,
message: message.to_string(),
}
}
/// 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!`]: https://doc.rust-lang.org/std/macro.compile_error.html
/// [`parse_macro_input!`]: ../macro.parse_macro_input.html
pub fn into_compile_error(self) -> TokenStream {
// compile_error!($message)
TokenStream::from_iter(vec![
TokenTree::Ident(Ident::new("compile_error", self.span)),
TokenTree::Punct({
let mut punct = Punct::new('!', Spacing::Alone);
punct.set_span(self.span);
punct
}),
TokenTree::Group({
let mut group = Group::new(Delimiter::Brace, {
TokenStream::from_iter(vec![TokenTree::Literal({
let mut string = Literal::string(&self.message);
string.set_span(self.span);
string
})])
});
group.set_span(self.span);
group
}),
])
}
}
// Not public API.
#[doc(hidden)]
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
if cursor.eof() {
Error::new(scope, format!("unexpected end of input, {}", message))
} else {
Error::new(cursor.span(), message)
}
}
impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&self.message)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
"parse error"
}
}
impl From<LexError> for Error {
fn from(err: LexError) -> Self {
Error::new(Span::call_site(), format!("{:?}", err))
}
}

View File

@ -1,6 +1,7 @@
use proc_macro2::Delimiter;
use super::parse::{ParseBuffer, Result};
use error::Result;
use super::parse::ParseBuffer;
use token;
pub struct Braces<'a> {

View File

@ -1,11 +1,10 @@
use std::cell::RefCell;
use buffer::Cursor;
use proc_macro2::Span;
use buffer::Cursor;
use error::{self, Error};
use span::IntoSpans;
use super::error;
use super::parse::Error;
use token::Token;
/// Support for checking the next token in a stream to decide how to parse.

View File

@ -7,8 +7,6 @@ pub mod lookahead;
#[macro_use]
mod group;
mod error;
use std::str::FromStr;
use buffer::TokenBuffer;
@ -16,7 +14,8 @@ use buffer::TokenBuffer;
use proc_macro;
use proc_macro2::{self, Span};
use self::parse::{Parse, ParseBuffer, Result};
use error::Result;
use self::parse::{Parse, ParseBuffer};
/// Parse tokens of source code into the chosen syntax tree node.
#[cfg(feature = "proc-macro")]

View File

@ -7,11 +7,9 @@ use std::mem;
use std::ops::Deref;
use buffer::Cursor;
use error::{self, Error, Result};
use proc_macro2::{Ident, Span};
use super::error;
pub use super::error::{Error, Result};
pub use super::lookahead::{Lookahead1, Peek};
/// Parsing interface implemented by all types that can be parsed in a default

View File

@ -13,11 +13,11 @@
//! 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.
//! `Cursor`, or an [`Error`] if parsing failed.
//!
//! [`Cursor`]: ../buffer/index.html
//! [`PResult<T>`]: type.PResult.html
//! [`ParseError`]: struct.ParseError.html
//! [`Error`]: struct.Error.html
//!
//! This `Cursor`- and `PResult`-based interface is convenient for parser
//! combinators and parser implementations, but not necessarily when you just
@ -39,7 +39,7 @@
//! ```
//! use syn::Type;
//!
//! # fn run_parser() -> Result<(), syn::synom::ParseError> {
//! # fn run_parser() -> Result<(), syn::synom::Error> {
//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
//! # Ok(())
//! # }
@ -90,7 +90,7 @@
//! use syn::punctuated::Punctuated;
//! use syn::{PathSegment, Expr, Attribute};
//!
//! # fn run_parsers() -> Result<(), syn::synom::ParseError> {
//! # fn run_parsers() -> Result<(), syn::synom::Error> {
//! # let tokens = TokenStream::new().into();
//! // Parse a nonempty sequence of path segments separated by `::` punctuation
//! // with no trailing punctuation.
@ -158,7 +158,7 @@ use proc_macro;
use proc_macro2::{Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree};
use error::parse_error;
pub use error::{PResult, ParseError};
pub use error::{PResult, Error};
use buffer::{Cursor, TokenBuffer};
use next;
@ -213,7 +213,7 @@ impl<T> Synom for T where T: next::parse::Parse {
let state = next::parse::ParseBuffer::new(Span::call_site(), input);
match <T as next::parse::Parse>::parse(&state) {
Ok(node) => Ok((node, state.cursor())),
Err(err) => Err(ParseError::new(err.to_string())),
Err(err) => Err(err),
}
}
}
@ -295,7 +295,7 @@ pub trait Parser: Sized {
type Output;
/// Parse a proc-macro2 token stream into the chosen syntax tree node.
fn parse2(self, tokens: TokenStream) -> Result<Self::Output, ParseError>;
fn parse2(self, tokens: TokenStream) -> Result<Self::Output, Error>;
/// Parse tokens of source code into the chosen syntax tree node.
///
@ -305,7 +305,7 @@ pub trait Parser: Sized {
not(all(target_arch = "wasm32", target_os = "unknown")),
feature = "proc-macro"
))]
fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output, ParseError> {
fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output, Error> {
self.parse2(tokens.into())
}
@ -315,10 +315,10 @@ pub trait Parser: Sized {
///
/// Every span in the resulting syntax tree will be set to resolve at the
/// macro call site.
fn parse_str(self, s: &str) -> Result<Self::Output, ParseError> {
fn parse_str(self, s: &str) -> Result<Self::Output, Error> {
match s.parse() {
Ok(tts) => self.parse2(tts),
Err(_) => Err(ParseError::new("error while lexing input string")),
Err(_) => Err(Error::new(Span::call_site(), "error while lexing input string")),
}
}
}
@ -329,16 +329,16 @@ where
{
type Output = T;
fn parse2(self, tokens: TokenStream) -> Result<T, ParseError> {
fn parse2(self, tokens: TokenStream) -> Result<T, Error> {
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"))
Err(Error::new(Span::call_site(), "failed to parse anything"))
} else {
Err(ParseError::new("failed to parse all tokens"))
Err(Error::new(Span::call_site(), "failed to parse all tokens"))
}
}
}

View File

@ -113,10 +113,12 @@ use proc_macro2::Spacing;
#[cfg(feature = "printing")]
use quote::{ToTokens, TokenStreamExt};
#[cfg(feature = "parsing")]
use error::Result;
#[cfg(feature = "parsing")]
use next::lookahead;
#[cfg(feature = "parsing")]
use next::parse::{Lookahead1, Parse, ParseStream, Result};
use next::parse::{Lookahead1, Parse, ParseStream};
use span::IntoSpans;
/// Marker trait for types that represent single tokens.
@ -772,7 +774,8 @@ mod parsing {
use proc_macro2::{Delimiter, Spacing, Span};
use buffer::Cursor;
use next::parse::{Error, ParseStream, Result};
use error::{Error, Result};
use next::parse::ParseStream;
use parse_error;
use span::FromSpans;
use synom::PResult;

View File

@ -11,9 +11,9 @@ extern crate syn;
use proc_macro2::{Ident, Span, TokenStream};
use std::str::FromStr;
use syn::synom::ParseError;
use syn::error::Error;
fn parse(s: &str) -> Result<Ident, ParseError> {
fn parse(s: &str) -> Result<Ident, Error> {
syn::parse2(TokenStream::from_str(s).unwrap())
}

View File

@ -175,7 +175,7 @@ fn run_test<T: Into<Meta>>(input: &str, expected: T) {
assert!(rest.eof());
e
}
Err(err) => panic!(err),
Err(err) => panic!(err.to_string()),
};
assert_eq!(expected.into(), attr.interpret_meta().unwrap());
}