1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
//! Error types for the [`query`](`crate::query`) module.
//!
//! The main error type is [`ParseErrorReport`], which contains
//! all [`ParseErrors`](`ParseError`) encountered during parsing.
//!
//! # Examples
//!
//! Retrieving the part of input that caused a parse error:
//!
//! ```rust
//! use rsonpath_lib::query::JsonPathQuery;
//! use rsonpath_lib::query::error::ParserError;
//!
//! let query_str =
//! "$.prop..invalid$chars.this_is_fine";
//! // ^ ^
//! // |_____|________________ start_idx of the error
//! // |________________ at this point the parser recovers
//! // ^^^^^^_________________ error length of 6
//! let result = JsonPathQuery::parse(query_str);
//!
//! match result {
//! Err(ParserError::SyntaxError { report }) => {
//! assert_eq!(report.errors().count(), 1);
//! let parse_error = report.errors().next().unwrap();
//! assert_eq!(parse_error.start_idx, 15);
//! assert_eq!(parse_error.len, 6);
//! let start = parse_error.start_idx;
//! let end = parse_error.start_idx + parse_error.len;
//! let invalid_tokens = &query_str[start..end];
//! assert_eq!(invalid_tokens, "$chars");
//! },
//! _ => unreachable!(),
//! }
//! ```
use std::{
fmt::{self, Display},
num::TryFromIntError,
};
use thiserror::Error;
/// Errors raised by the query parser.
#[derive(Debug, Error)]
pub enum ParserError {
/// Parsing error that occurred due to invalid input.
#[error("one or more parsing errors occurred:\n{}", .report)]
SyntaxError {
/// Error report.
report: ParseErrorReport,
},
/// Internal parser error. This is not expected to happen,
/// and signifies a bug in [`query`](`crate::query`).
#[error(
"unexpected error in the parser; please report this issue at {}",
crate::error::BUG_REPORT_URL
)]
InternalNomError {
/// Source error from the [`nom`] crate.
#[from]
#[source]
source: nom::error::Error<String>,
},
}
/// Error report created during the parser's run over a single input string.
#[derive(Debug)]
pub struct ParseErrorReport {
errors: Vec<ParseError>,
}
impl Display for ParseErrorReport {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for error in self.errors() {
writeln!(f, "{error}\n")?;
}
Ok(())
}
}
/// Single error raised during parsing, defined as the
/// contiguous sequence of characters that caused the error.
#[derive(Debug)]
pub struct ParseError {
/// The index at which the error occurred.
pub start_idx: usize,
/// The number of characters that the parser recognised as invalid.
pub len: usize,
}
impl Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"invalid tokens of length {} at position {} ",
self.len, self.start_idx
)
}
}
impl ParseError {
fn end_idx(&self) -> usize {
self.start_idx + self.len - 1
}
}
impl ParseErrorReport {
pub(crate) fn new() -> Self {
Self { errors: vec![] }
}
pub(crate) fn record_at(&mut self, idx: usize) {
match self.errors.last_mut() {
Some(last_error) if last_error.end_idx() + 1 == idx => last_error.len += 1,
_ => self.add_new(idx),
}
}
/// Retrieves an [`Iterator`] over all [`ParseErrors`](`ParseError`)
/// in the report.
#[inline]
pub fn errors(&self) -> impl Iterator<Item = &ParseError> {
self.errors.iter()
}
fn add_new(&mut self, idx: usize) {
self.errors.push(ParseError {
start_idx: idx,
len: 1,
})
}
}
/// Errors raised by the query compiler.
#[derive(Debug, Error)]
pub enum CompilerError {
/// Max automaton size was exceeded during compilation of the query.
#[error("Max automaton size was exceeded. Query is too complex.")]
QueryTooComplex(#[source] Option<TryFromIntError>),
/// Compiler error that occurred due to a known limitation.
#[error(transparent)]
NotSupported(#[from] crate::error::UnsupportedFeatureError),
}