use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
pub kind: ParseErrorKind,
pub position: usize,
pub fragment: String,
pub message: String,
}
impl ParseError {
#[must_use]
pub fn new(
kind: ParseErrorKind,
position: usize,
fragment: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self {
kind,
position,
fragment: fragment.into(),
message: message.into(),
}
}
#[must_use]
pub fn syntax(
position: usize,
fragment: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self::new(ParseErrorKind::SyntaxError, position, fragment, message)
}
#[must_use]
pub fn unexpected_token(position: usize, fragment: impl Into<String>, expected: &str) -> Self {
Self::new(
ParseErrorKind::UnexpectedToken,
position,
fragment,
format!("Expected {expected}"),
)
}
#[must_use]
pub fn unknown_column(column: impl Into<String>) -> Self {
let col = column.into();
Self::new(
ParseErrorKind::UnknownColumn,
0,
col.clone(),
format!("Unknown column '{col}'"),
)
}
#[must_use]
pub fn missing_parameter(param: impl Into<String>) -> Self {
let p = param.into();
Self::new(
ParseErrorKind::MissingParameter,
0,
p.clone(),
format!("Missing parameter '${p}'"),
)
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"[{}] {} at position {}",
self.kind.code(),
self.message,
self.position
)
}
}
impl std::error::Error for ParseError {}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseErrorKind {
SyntaxError,
UnexpectedToken,
UnknownColumn,
CollectionNotFound,
DimensionMismatch,
MissingParameter,
TypeMismatch,
ComplexityLimit,
}
impl ParseErrorKind {
#[must_use]
pub const fn code(&self) -> &'static str {
match self {
Self::SyntaxError | Self::UnexpectedToken => "E001",
Self::UnknownColumn => "E002",
Self::CollectionNotFound => "E003",
Self::DimensionMismatch => "E004",
Self::MissingParameter => "E005",
Self::TypeMismatch => "E006",
Self::ComplexityLimit => "E007",
}
}
}
#[cfg(test)]
#[path = "error_unit_tests.rs"]
mod tests;