//! Stream wrapper which provides an informative and easy to use error type. //! //! Unless you have specific constraints preventing you from using this error type (such as being //! a `no_std` environment) you probably want to use this stream type. It can easily be used //! through the [`EasyParser::easy_parse`] method. //! //! The provided `Errors` type is roughly the same as `ParseError` in combine 1.x and 2.x. //! //! ``` //! #[macro_use] //! extern crate combine; //! use combine::{easy, Parser, EasyParser, Stream, many1}; //! use combine::parser::char::letter; //! use combine::stream::StreamErrorFor; //! use combine::error::{ParseError, StreamError}; //! //! fn main() { //! parser!{ //! fn parser[Input]()(Input) -> String //! where [ //! Input: Stream>, //! Input::Range: PartialEq, //! // If we want to use the error type explicitly we need to help rustc infer //! // `StreamError` to `easy::Error` (rust-lang/rust#24159) //! Input::Error: ParseError< //! Input::Token, //! Input::Range, //! Input::Position, //! StreamError = easy::Error //! > //! ] //! { //! many1(letter()).and_then(|word: String| { //! if word == "combine" { //! Ok(word) //! } else { //! Err(easy::Error::Expected(easy::Info::Static("combine"))) //! } //! }) //! } //! } //! //! parser!{ //! fn parser2[Input]()(Input) -> String //! where [ //! Input: Stream, //! ] //! { //! many1(letter()).and_then(|word: String| { //! if word == "combine" { //! Ok(word) //! } else { //! // Alternatively it is possible to only use the methods provided by the //! // `StreamError` trait. //! // In that case the extra bound is not necessary (and this method will work //! // for other errors than `easy::Errors`) //! Err(StreamErrorFor::::expected_static_message("combine")) //! } //! }) //! } //! } //! //! let input = "combin"; //! let expected_error = Err(easy::Errors { //! errors: vec![ //! easy::Error::Expected("combine".into()) //! ], //! position: 0, //! }); //! assert_eq!( //! parser().easy_parse(input).map_err(|err| err.map_position(|p| p.translate_position(input))), //! expected_error //! ); //! assert_eq!( //! parser2().easy_parse(input).map_err(|err| err.map_position(|p| p.translate_position(input))), //! expected_error //! ); //! } //! //! ``` //! //! [`EasyParser::easy_parse`]: super::super::parser::EasyParser::easy_parse use std::{error::Error as StdError, fmt}; use crate::error::{Info as PrimitiveInfo, ParseResult, StreamError, Tracked}; use crate::stream::{ Positioned, RangeStream, RangeStreamOnce, ResetStream, StreamErrorFor, StreamOnce, }; /// Enum holding error information. Variants are defined for `Stream::Token` and `Stream::Range` as /// well as string variants holding easy descriptions. /// /// As there is implementations of `From` for `String` and `&'static str` the /// constructor need not be used directly as calling `msg.into()` should turn a message into the /// correct `Info` variant. #[derive(Clone, Debug)] pub enum Info { Token(T), Range(R), Owned(String), Static(&'static str), } impl From> for Info where F: fmt::Display, { fn from(info: PrimitiveInfo) -> Self { match info { PrimitiveInfo::Token(b) => Info::Token(b), PrimitiveInfo::Range(b) => Info::Range(b), PrimitiveInfo::Static(b) => Info::Static(b), PrimitiveInfo::Format(b) => Info::Owned(b.to_string()), } } } impl Info { pub fn map_token(self, f: F) -> Info where F: FnOnce(T) -> U, { use self::Info::*; match self { Token(t) => Token(f(t)), Range(r) => Range(r), Owned(s) => Owned(s), Static(x) => Static(x), } } pub fn map_range(self, f: F) -> Info where F: FnOnce(R) -> S, { use self::Info::*; match self { Token(t) => Token(t), Range(r) => Range(f(r)), Owned(s) => Owned(s), Static(x) => Static(x), } } } impl PartialEq for Info { fn eq(&self, other: &Info) -> bool { match (self, other) { (&Info::Token(ref l), &Info::Token(ref r)) => l == r, (&Info::Range(ref l), &Info::Range(ref r)) => l == r, (&Info::Owned(ref l), &Info::Owned(ref r)) => l == r, (&Info::Static(l), &Info::Owned(ref r)) => l == r, (&Info::Owned(ref l), &Info::Static(r)) => l == r, (&Info::Static(l), &Info::Static(r)) => l == r, _ => false, } } } impl fmt::Display for Info { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Info::Token(ref c) => write!(f, "`{}`", c), Info::Range(ref c) => write!(f, "`{}`", c), Info::Owned(ref s) => write!(f, "{}", s), Info::Static(s) => write!(f, "{}", s), } } } impl From for Info { fn from(s: char) -> Info { Info::Token(s) } } impl From for Info { fn from(s: String) -> Info { Info::Owned(s) } } impl From<&'static str> for Info { fn from(s: &'static str) -> Info { Info::Static(s) } } impl From for Info { fn from(s: u8) -> Info { Info::Token(s) } } /// Enum used to store information about an error that has occurred during parsing. #[derive(Debug)] pub enum Error { /// Error indicating an unexpected token has been encountered in the stream Unexpected(Info), /// Error indicating that the parser expected something else Expected(Info), /// Generic message Message(Info), /// Variant for containing other types of errors Other(Box), } impl StreamError for Error where Item: PartialEq, Range: PartialEq, { #[inline] fn unexpected_token(token: Item) -> Self { Error::Unexpected(Info::Token(token)) } #[inline] fn unexpected_range(token: Range) -> Self { Error::Unexpected(Info::Range(token)) } #[inline] fn unexpected_format(msg: T) -> Self where T: fmt::Display, { Error::Unexpected(Info::Owned(msg.to_string())) } #[inline] fn unexpected_static_message(msg: &'static str) -> Self { Error::Unexpected(Info::Static(msg)) } #[inline] fn expected_token(token: Item) -> Self { Error::Expected(Info::Token(token)) } #[inline] fn expected_range(token: Range) -> Self { Error::Expected(Info::Range(token)) } #[inline] fn expected_format(msg: T) -> Self where T: fmt::Display, { Error::Expected(Info::Owned(msg.to_string())) } #[inline] fn expected_static_message(msg: &'static str) -> Self { Error::Expected(Info::Static(msg)) } #[inline] fn message_format(msg: T) -> Self where T: fmt::Display, { Error::Message(Info::Owned(msg.to_string())) } #[inline] fn message_static_message(msg: &'static str) -> Self { Error::Message(Info::Static(msg)) } #[inline] fn message_token(token: Item) -> Self { Error::Message(Info::Token(token)) } #[inline] fn message_range(token: Range) -> Self { Error::Message(Info::Range(token)) } fn is_unexpected_end_of_input(&self) -> bool { *self == Self::end_of_input() } #[inline] fn other(err: E) -> Self where E: StdError + Send + Sync + 'static, { err.into() } #[inline] fn into_other(self) -> T where T: StreamError, { match self { Error::Unexpected(info) => match info { Info::Token(x) => T::unexpected_token(x), Info::Range(x) => T::unexpected_range(x), Info::Static(x) => T::unexpected_static_message(x), Info::Owned(x) => T::unexpected_format(x), }, Error::Expected(info) => match info { Info::Token(x) => T::expected_token(x), Info::Range(x) => T::expected_range(x), Info::Static(x) => T::expected_static_message(x), Info::Owned(x) => T::expected_format(x), }, Error::Message(info) => match info { Info::Token(x) => T::expected_token(x), Info::Range(x) => T::expected_range(x), Info::Static(x) => T::expected_static_message(x), Info::Owned(x) => T::expected_format(x), }, Error::Other(err) => T::message_format(err), } } } impl crate::error::ParseError for Error where Item: PartialEq, Range: PartialEq, Position: Default, { type StreamError = Self; #[inline] fn empty(_: Position) -> Self { Self::message_static_message("") } #[inline] fn from_error(_: Position, err: Self::StreamError) -> Self { err } #[inline] fn position(&self) -> Position { Position::default() } #[inline] fn set_position(&mut self, _position: Position) {} #[inline] fn add(&mut self, err: Self::StreamError) { *self = err; } #[inline] fn set_expected(self_: &mut Tracked, info: Self::StreamError, f: F) where F: FnOnce(&mut Tracked), { f(self_); self_.error = info; } fn is_unexpected_end_of_input(&self) -> bool { *self == Self::end_of_input() } #[inline] fn into_other(self) -> T where T: crate::error::ParseError, { T::from_error(Position::default(), StreamError::into_other(self)) } } impl crate::error::ParseErrorInto for Errors { fn into_other_error(self) -> T where T: crate::error::ParseError, Item2: From, Range2: From, Position2: From, { let mut error = T::empty(self.position.into()); for err in self.errors { error.add(crate::error::StreamErrorInto::::into_other_error(err)); } error } } impl crate::error::StreamErrorInto for Error { fn into_other_error(self) -> T where T: crate::error::StreamError, Item2: From, Range2: From, { match self { Error::Unexpected(info) => match info { Info::Token(x) => T::unexpected_token(x.into()), Info::Range(x) => T::unexpected_range(x.into()), Info::Static(x) => T::unexpected_static_message(x), Info::Owned(x) => T::unexpected_format(x), }, Error::Expected(info) => match info { Info::Token(x) => T::expected_token(x.into()), Info::Range(x) => T::expected_range(x.into()), Info::Static(x) => T::expected_static_message(x), Info::Owned(x) => T::expected_format(x), }, Error::Message(info) => match info { Info::Token(x) => T::expected_token(x.into()), Info::Range(x) => T::expected_range(x.into()), Info::Static(x) => T::expected_static_message(x), Info::Owned(x) => T::expected_format(x), }, Error::Other(err) => T::message_format(err), } } } impl crate::error::ParseError for Errors where Item: PartialEq, Range: PartialEq, Position: Ord + Clone, { type StreamError = Error; #[inline] fn empty(pos: Position) -> Self { Errors::empty(pos) } #[inline] fn from_error(position: Position, err: Self::StreamError) -> Self { Self::new(position, err) } #[inline] fn position(&self) -> Position { self.position.clone() } #[inline] fn set_position(&mut self, position: Position) { self.position = position; } #[inline] fn merge(self, other: Self) -> Self { Errors::merge(self, other) } #[inline] fn add(&mut self, err: Self::StreamError) { self.add_error(err); } #[inline] fn set_expected(self_: &mut Tracked, info: Self::StreamError, f: F) where F: FnOnce(&mut Tracked), { let start = self_.error.errors.len(); f(self_); // Replace all expected errors that were added from the previous add_error // with this expected error let mut i = 0; self_.error.errors.retain(|e| { if i < start { i += 1; true } else { match *e { Error::Expected(_) => false, _ => true, } } }); self_.error.add(info); } fn clear_expected(&mut self) { self.errors.retain(|e| match *e { Error::Expected(_) => false, _ => true, }) } fn is_unexpected_end_of_input(&self) -> bool { self.errors .iter() .any(StreamError::is_unexpected_end_of_input) } #[inline] fn into_other(mut self) -> T where T: crate::error::ParseError, { match self.errors.pop() { Some(err) => T::from_error(self.position, StreamError::into_other(err)), None => T::empty(self.position), } } } impl Error { pub fn map_token(self, f: F) -> Error where F: FnOnce(T) -> U, { use self::Error::*; match self { Unexpected(x) => Unexpected(x.map_token(f)), Expected(x) => Expected(x.map_token(f)), Message(x) => Message(x.map_token(f)), Other(x) => Other(x), } } pub fn map_range(self, f: F) -> Error where F: FnOnce(R) -> S, { use self::Error::*; match self { Unexpected(x) => Unexpected(x.map_range(f)), Expected(x) => Expected(x.map_range(f)), Message(x) => Message(x.map_range(f)), Other(x) => Other(x), } } } impl PartialEq for Error { fn eq(&self, other: &Error) -> bool { match (self, other) { (&Error::Unexpected(ref l), &Error::Unexpected(ref r)) | (&Error::Expected(ref l), &Error::Expected(ref r)) | (&Error::Message(ref l), &Error::Message(ref r)) => l == r, _ => false, } } } impl From for Error where E: StdError + 'static + Send + Sync, { fn from(e: E) -> Error { Error::Other(Box::new(e)) } } impl Error { /// Returns the `end_of_input` error. pub fn end_of_input() -> Error { Error::Unexpected("end of input".into()) } /// Formats a slice of errors in a human readable way. /// /// ```rust /// # extern crate combine; /// # use combine::*; /// # use combine::parser::char::*; /// # use combine::stream::position::{self, SourcePosition}; /// /// # fn main() { /// let input = r" /// ,123 /// "; /// let result = spaces().silent().with(char('.').or(char('a')).or(digit())) /// .easy_parse(position::Stream::new(input)); /// let m = format!("{}", result.unwrap_err()); /// let expected = r"Parse error at line: 2, column: 3 /// Unexpected `,` /// Expected `.`, `a` or digit /// "; /// assert_eq!(m, expected); /// # } /// ``` pub fn fmt_errors(errors: &[Error], f: &mut fmt::Formatter<'_>) -> fmt::Result where T: fmt::Display, R: fmt::Display, { // First print the token that we did not expect // There should really just be one unexpected message at this point though we print them // all to be safe let unexpected = errors.iter().filter(|e| match **e { Error::Unexpected(_) => true, _ => false, }); for error in unexpected { writeln!(f, "{}", error)?; } // Then we print out all the things that were expected in a comma separated list // 'Expected 'a', 'expression' or 'let' let iter = || { errors.iter().filter_map(|e| match *e { Error::Expected(ref err) => Some(err), _ => None, }) }; let expected_count = iter().count(); for (i, message) in iter().enumerate() { let s = match i { 0 => "Expected", _ if i < expected_count - 1 => ",", // Last expected message to be written _ => " or", }; write!(f, "{} {}", s, message)?; } if expected_count != 0 { writeln!(f)?; } // If there are any generic messages we print them out last let messages = errors.iter().filter(|e| match **e { Error::Message(_) | Error::Other(_) => true, _ => false, }); for error in messages { writeln!(f, "{}", error)?; } Ok(()) } } /// Convenience alias over `Errors` for `StreamOnce` types which makes it possible to specify the /// `Errors` type from a `StreamOnce` by writing `ParseError` instead of `Errors` pub type ParseError = Errors<::Token, ::Range, ::Position>; /// Struct which hold information about an error that occurred at a specific position. /// Can hold multiple instances of `Error` if more that one error occurred in the same position. #[derive(Debug, PartialEq)] pub struct Errors { /// The position where the error occurred pub position: P, /// A vector containing specific information on what errors occurred at `position`. Usually /// a fully formed message contains one `Unexpected` error and one or more `Expected` errors. /// `Message` and `Other` may also appear (`combine` never generates these errors on its own) /// and may warrant custom handling. pub errors: Vec>, } impl Errors { /// Constructs a new `ParseError` which occurred at `position`. #[inline] pub fn new(position: P, error: Error) -> Errors { Self::from_errors(position, vec![error]) } /// Constructs an error with no other information than the position it occurred at. #[inline] pub fn empty(position: P) -> Errors { Self::from_errors(position, vec![]) } /// Constructs a `ParseError` with multiple causes. #[inline] pub fn from_errors(position: P, errors: Vec>) -> Errors { Errors { position, errors } } /// Constructs an end of input error. Should be returned by parsers which encounter end of /// input unexpectedly. #[inline] pub fn end_of_input(position: P) -> Errors { Self::new(position, Error::end_of_input()) } /// Adds an error if `error` does not exist in this `ParseError` already (as determined byte /// `PartialEq`). pub fn add_error(&mut self, error: Error) where T: PartialEq, R: PartialEq, { // Don't add duplicate errors if self.errors.iter().all(|err| *err != error) { self.errors.push(error); } } /// Removes all `Expected` errors in `self` and adds `info` instead. pub fn set_expected(&mut self, info: Info) { // Remove all other expected messages self.errors.retain(|e| match *e { Error::Expected(_) => false, _ => true, }); self.errors.push(Error::Expected(info)); } /// Merges two `ParseError`s. If they exist at the same position the errors of `other` are /// added to `self` (using `add_error` to skip duplicates). If they are not at the same /// position the error furthest ahead are returned, ignoring the other `ParseError`. pub fn merge(mut self, mut other: Errors) -> Errors where P: Ord, T: PartialEq, R: PartialEq, { use std::cmp::Ordering; // Only keep the errors which occurred after consuming the most amount of data match self.position.cmp(&other.position) { Ordering::Less => other, Ordering::Greater => self, Ordering::Equal => { for message in other.errors.drain(..) { self.add_error(message); } self } } } /// Maps the position to a new value pub fn map_position(self, f: F) -> Errors where F: FnOnce(P) -> Q, { Errors::from_errors(f(self.position), self.errors) } /// Maps all token variants to a new value pub fn map_token(self, mut f: F) -> Errors where F: FnMut(T) -> U, { Errors::from_errors( self.position, self.errors .into_iter() .map(|error| error.map_token(&mut f)) .collect(), ) } /// Maps all range variants to a new value. /// /// ``` /// use combine::*; /// use combine::parser::range::range; /// println!( /// "{}", /// range(&"HTTP"[..]) /// .easy_parse("HTT") /// .unwrap_err() /// .map_range(|bytes| format!("{:?}", bytes)) /// ); /// ``` pub fn map_range(self, mut f: F) -> Errors where F: FnMut(R) -> S, { Errors::from_errors( self.position, self.errors .into_iter() .map(|error| error.map_range(&mut f)) .collect(), ) } } impl StdError for Errors where P: fmt::Display + fmt::Debug, T: fmt::Display + fmt::Debug, R: fmt::Display + fmt::Debug, { fn description(&self) -> &str { "parse error" } } impl fmt::Display for Errors where P: fmt::Display, T: fmt::Display, R: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "Parse error at {}", self.position)?; Error::fmt_errors(&self.errors, f) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Error::Unexpected(ref c) => write!(f, "Unexpected {}", c), Error::Expected(ref s) => write!(f, "Expected {}", s), Error::Message(ref msg) => msg.fmt(f), Error::Other(ref err) => err.fmt(f), } } } #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct Stream(pub S); impl From for Stream { fn from(stream: S) -> Self { Stream(stream) } } impl ResetStream for Stream where S: ResetStream + Positioned, S::Token: PartialEq, S::Range: PartialEq, { type Checkpoint = S::Checkpoint; fn checkpoint(&self) -> Self::Checkpoint { self.0.checkpoint() } fn reset(&mut self, checkpoint: Self::Checkpoint) -> Result<(), Self::Error> { self.0 .reset(checkpoint) .map_err(crate::error::ParseError::into_other) } } impl StreamOnce for Stream where S: StreamOnce + Positioned, S::Token: PartialEq, S::Range: PartialEq, { type Token = S::Token; type Range = S::Range; type Position = S::Position; type Error = ParseError; #[inline] fn uncons(&mut self) -> Result> { self.0.uncons().map_err(StreamError::into_other) } fn is_partial(&self) -> bool { self.0.is_partial() } } impl RangeStreamOnce for Stream where S: RangeStream, S::Token: PartialEq, S::Range: PartialEq, { #[inline] fn uncons_range(&mut self, size: usize) -> Result> { self.0.uncons_range(size).map_err(StreamError::into_other) } #[inline] fn uncons_while(&mut self, f: F) -> Result> where F: FnMut(Self::Token) -> bool, { self.0.uncons_while(f).map_err(StreamError::into_other) } #[inline] fn uncons_while1(&mut self, f: F) -> ParseResult> where F: FnMut(Self::Token) -> bool, { self.0.uncons_while1(f).map_err(StreamError::into_other) } #[inline] fn distance(&self, end: &Self::Checkpoint) -> usize { self.0.distance(end) } fn range(&self) -> Self::Range { self.0.range() } } impl Positioned for Stream where S: StreamOnce + Positioned, S::Token: PartialEq, S::Range: PartialEq, { fn position(&self) -> S::Position { self.0.position() } }