Address feedback, preserving inner err

pull/775/head
Yuri Astrakhan 1 year ago
parent 463a7bd796
commit b50a6fa13a
  1. 4
      lib/oxigraph/src/storage/error.rs
  2. 106
      lib/oxrdf/src/parser.rs
  3. 33
      lib/oxrdfio/src/error.rs
  4. 23
      lib/oxrdfxml/src/error.rs
  5. 26
      lib/oxrdfxml/src/parser.rs
  6. 20
      lib/oxsdatatypes/src/date_time.rs
  7. 37
      lib/oxsdatatypes/src/decimal.rs
  8. 34
      lib/sparesults/src/csv.rs
  9. 57
      lib/sparesults/src/error.rs
  10. 16
      lib/spargebra/src/parser.rs

@ -49,7 +49,7 @@ impl CorruptionError {
/// Builds an error from a printable error message. /// Builds an error from a printable error message.
#[inline] #[inline]
pub(crate) fn new(error: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self { pub(crate) fn new(error: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
CorruptionErrorKind::Other(error.into()).into() Self(CorruptionErrorKind::Other(error.into()))
} }
#[inline] #[inline]
@ -67,7 +67,7 @@ impl CorruptionError {
/// Builds an error from a printable error message. /// Builds an error from a printable error message.
#[inline] #[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self { pub(crate) fn msg(msg: impl Into<String>) -> Self {
CorruptionErrorKind::Msg(msg.into()).into() Self(CorruptionErrorKind::Msg(msg.into()))
} }
} }

@ -29,9 +29,9 @@ impl FromStr for NamedNode {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let (term, left) = read_named_node(s)?; let (term, left) = read_named_node(s)?;
if !left.is_empty() { if !left.is_empty() {
return Err(TermParseErrorKind::msg( return Err(Self::Err::msg(
"Named node serialization should end with a >", "Named node serialization should end with a >",
))?; ));
} }
Ok(term) Ok(term)
} }
@ -54,9 +54,9 @@ impl FromStr for BlankNode {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let (term, left) = read_blank_node(s)?; let (term, left) = read_blank_node(s)?;
if !left.is_empty() { if !left.is_empty() {
return Err(TermParseErrorKind::msg( return Err(Self::Err::msg(
"Blank node serialization should not contain whitespaces", "Blank node serialization should not contain whitespaces",
))?; ));
} }
Ok(term) Ok(term)
} }
@ -107,7 +107,7 @@ impl FromStr for Literal {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let (term, left) = read_literal(s)?; let (term, left) = read_literal(s)?;
if !left.is_empty() { if !left.is_empty() {
return Err(TermParseErrorKind::msg("Invalid literal serialization"))?; return Err(Self::Err::msg("Invalid literal serialization"));
} }
Ok(term) Ok(term)
} }
@ -139,7 +139,7 @@ impl FromStr for Term {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let (term, left) = read_term(s, 0)?; let (term, left) = read_term(s, 0)?;
if !left.is_empty() { if !left.is_empty() {
return Err(TermParseErrorKind::msg("Invalid term serialization"))?; return Err(Self::Err::msg("Invalid term serialization"));
} }
Ok(term) Ok(term)
} }
@ -161,40 +161,42 @@ impl FromStr for Variable {
/// ``` /// ```
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
if !s.starts_with('?') && !s.starts_with('$') { if !s.starts_with('?') && !s.starts_with('$') {
return Err(TermParseErrorKind::msg( return Err(Self::Err::msg(
"Variable serialization should start with ? or $", "Variable serialization should start with ? or $",
))?; ));
} }
Ok( Self::new(&s[1..]).map_err(|error| {
Self::new(&s[1..]).map_err(|error| TermParseErrorKind::Variable { TermParseError(TermParseErrorKind::Variable {
value: s.to_owned(), value: s.to_owned(),
error, error,
})?, })
) })
} }
} }
fn read_named_node(s: &str) -> Result<(NamedNode, &str), TermParseErrorKind> { fn read_named_node(s: &str) -> Result<(NamedNode, &str), TermParseError> {
let s = s.trim(); let s = s.trim();
if let Some(remain) = s.strip_prefix('<') { if let Some(remain) = s.strip_prefix('<') {
let end = remain.find('>').ok_or_else(|| { let end = remain
TermParseErrorKind::msg("Named node serialization should end with a >") .find('>')
})?; .ok_or_else(|| TermParseError::msg("Named node serialization should end with a >"))?;
let (value, remain) = remain.split_at(end); let (value, remain) = remain.split_at(end);
let remain = &remain[1..]; let remain = &remain[1..];
let term = NamedNode::new(value).map_err(|error| TermParseErrorKind::Iri { let term = NamedNode::new(value).map_err(|error| {
value: value.to_owned(), TermParseError(TermParseErrorKind::Iri {
error, value: value.to_owned(),
error,
})
})?; })?;
Ok((term, remain)) Ok((term, remain))
} else { } else {
Err(TermParseErrorKind::msg( Err(TermParseError::msg(
"Named node serialization should start with a <", "Named node serialization should start with a <",
)) ))
} }
} }
fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseErrorKind> { fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseError> {
let s = s.trim(); let s = s.trim();
if let Some(remain) = s.strip_prefix("_:") { if let Some(remain) = s.strip_prefix("_:") {
let end = remain let end = remain
@ -204,19 +206,21 @@ fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseErrorKind> {
}) })
.unwrap_or(remain.len()); .unwrap_or(remain.len());
let (value, remain) = remain.split_at(end); let (value, remain) = remain.split_at(end);
let term = BlankNode::new(value).map_err(|error| TermParseErrorKind::BlankNode { let term = BlankNode::new(value).map_err(|error| {
value: value.to_owned(), TermParseError(TermParseErrorKind::BlankNode {
error, value: value.to_owned(),
error,
})
})?; })?;
Ok((term, remain)) Ok((term, remain))
} else { } else {
Err(TermParseErrorKind::msg( Err(TermParseError::msg(
"Blank node serialization should start with '_:'", "Blank node serialization should start with '_:'",
))? ))
} }
} }
fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { fn read_literal(s: &str) -> Result<(Literal, &str), TermParseError> {
let s = s.trim(); let s = s.trim();
if let Some(s) = s.strip_prefix('"') { if let Some(s) = s.strip_prefix('"') {
let mut value = String::with_capacity(s.len()); let mut value = String::with_capacity(s.len());
@ -232,9 +236,11 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> {
let (language, remain) = remain.split_at(end); let (language, remain) = remain.split_at(end);
Ok(( Ok((
Literal::new_language_tagged_literal(value, language).map_err( Literal::new_language_tagged_literal(value, language).map_err(
|error| TermParseErrorKind::LanguageTag { |error| {
value: language.to_owned(), TermParseError(TermParseErrorKind::LanguageTag {
error, value: language.to_owned(),
error,
})
}, },
)?, )?,
remain, remain,
@ -259,16 +265,16 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> {
'\\' => '\\', '\\' => '\\',
'u' => read_hexa_char(&mut chars, 4)?, 'u' => read_hexa_char(&mut chars, 4)?,
'U' => read_hexa_char(&mut chars, 8)?, 'U' => read_hexa_char(&mut chars, 8)?,
_ => return Err(TermParseErrorKind::msg("Unexpected escaped char"))?, _ => return Err(TermParseError::msg("Unexpected escaped char")),
}) })
} else { } else {
return Err(TermParseErrorKind::msg("Unexpected literal end")); return Err(TermParseError::msg("Unexpected literal end"));
} }
} }
_ => value.push(c), _ => value.push(c),
} }
} }
Err(TermParseErrorKind::msg("Unexpected literal end")) Err(TermParseError::msg("Unexpected literal end"))
} else if let Some(remain) = s.strip_prefix("true") { } else if let Some(remain) = s.strip_prefix("true") {
Ok((Literal::new_typed_literal("true", xsd::BOOLEAN), remain)) Ok((Literal::new_typed_literal("true", xsd::BOOLEAN), remain))
} else if let Some(remain) = s.strip_prefix("false") { } else if let Some(remain) = s.strip_prefix("false") {
@ -276,7 +282,7 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> {
} else { } else {
let input = s.as_bytes(); let input = s.as_bytes();
if input.is_empty() { if input.is_empty() {
return Err(TermParseErrorKind::msg("Empty term serialization")); return Err(TermParseError::msg("Empty term serialization"));
} }
let mut cursor = match input.first() { let mut cursor = match input.first() {
@ -315,7 +321,7 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> {
if count_exponent > 0 { if count_exponent > 0 {
Ok((Literal::new_typed_literal(s, xsd::DOUBLE), &s[cursor..])) Ok((Literal::new_typed_literal(s, xsd::DOUBLE), &s[cursor..]))
} else { } else {
Err(TermParseErrorKind::msg( Err(TermParseError::msg(
"Double serialization with an invalid exponent", "Double serialization with an invalid exponent",
)) ))
} }
@ -323,24 +329,21 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> {
if count_after > 0 { if count_after > 0 {
Ok((Literal::new_typed_literal(s, xsd::DECIMAL), &s[cursor..])) Ok((Literal::new_typed_literal(s, xsd::DECIMAL), &s[cursor..]))
} else { } else {
Err(TermParseErrorKind::msg( Err(TermParseError::msg(
"Decimal serialization without floating part", "Decimal serialization without floating part",
)) ))
} }
} else if count_before > 0 { } else if count_before > 0 {
Ok((Literal::new_typed_literal(s, xsd::INTEGER), &s[cursor..])) Ok((Literal::new_typed_literal(s, xsd::INTEGER), &s[cursor..]))
} else { } else {
Err(TermParseErrorKind::msg("Empty integer serialization")) Err(TermParseError::msg("Empty integer serialization"))
} }
} }
} }
fn read_term( fn read_term(s: &str, number_of_recursive_calls: usize) -> Result<(Term, &str), TermParseError> {
s: &str,
number_of_recursive_calls: usize,
) -> Result<(Term, &str), TermParseErrorKind> {
if number_of_recursive_calls == MAX_NUMBER_OF_NESTED_TRIPLES { if number_of_recursive_calls == MAX_NUMBER_OF_NESTED_TRIPLES {
return Err(TermParseErrorKind::msg( return Err(TermParseError::msg(
"Too many nested triples. The parser fails here to avoid a stack overflow.", "Too many nested triples. The parser fails here to avoid a stack overflow.",
)); ));
} }
@ -360,7 +363,7 @@ fn read_term(
Term::NamedNode(s) => s.into(), Term::NamedNode(s) => s.into(),
Term::BlankNode(s) => s.into(), Term::BlankNode(s) => s.into(),
Term::Literal(_) => { Term::Literal(_) => {
return Err(TermParseErrorKind::msg( return Err(TermParseError::msg(
"Literals are not allowed in subject position", "Literals are not allowed in subject position",
)) ))
} }
@ -373,14 +376,14 @@ fn read_term(
remain, remain,
)) ))
} else { } else {
Err(TermParseErrorKind::msg( Err(TermParseError::msg(
"Nested triple serialization should be enclosed between << and >>", "Nested triple serialization should be enclosed between << and >>",
)) ))
} }
} }
#[cfg(not(feature = "rdf-star"))] #[cfg(not(feature = "rdf-star"))]
{ {
Err(TermParseErrorKind::msg("RDF-star is not supported")) Err(TermParseError::msg("RDF-star is not supported"))
} }
} else if s.starts_with('<') { } else if s.starts_with('<') {
let (term, remain) = read_named_node(s)?; let (term, remain) = read_named_node(s)?;
@ -394,7 +397,7 @@ fn read_term(
} }
} }
fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result<char, TermParseErrorKind> { fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result<char, TermParseError> {
let mut value = 0; let mut value = 0;
for _ in 0..len { for _ in 0..len {
if let Some(c) = input.next() { if let Some(c) = input.next() {
@ -404,17 +407,16 @@ fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result<char, TermParseEr
'a'..='f' => u32::from(c) - u32::from('a') + 10, 'a'..='f' => u32::from(c) - u32::from('a') + 10,
'A'..='F' => u32::from(c) - u32::from('A') + 10, 'A'..='F' => u32::from(c) - u32::from('A') + 10,
_ => { _ => {
return Err(TermParseErrorKind::msg( return Err(TermParseError::msg(
"Unexpected character in a unicode escape", "Unexpected character in a unicode escape",
)) ))
} }
} }
} else { } else {
return Err(TermParseErrorKind::msg("Unexpected literal string end")); return Err(TermParseError::msg("Unexpected literal string end"));
} }
} }
char::from_u32(value) char::from_u32(value).ok_or_else(|| TermParseError::msg("Invalid encoded unicode code point"))
.ok_or_else(|| TermParseErrorKind::msg("Invalid encoded unicode code point"))
} }
/// An error raised during term serialization parsing using the [`FromStr`] trait. /// An error raised during term serialization parsing using the [`FromStr`] trait.
@ -446,8 +448,8 @@ enum TermParseErrorKind {
Msg { msg: &'static str }, Msg { msg: &'static str },
} }
impl TermParseErrorKind { impl TermParseError {
pub(crate) fn msg(msg: &'static str) -> Self { pub(crate) fn msg(msg: &'static str) -> Self {
TermParseErrorKind::Msg { msg } Self(TermParseErrorKind::Msg { msg })
} }
} }

@ -14,24 +14,16 @@ pub enum ParseError {
impl ParseError { impl ParseError {
pub(crate) fn msg(msg: &'static str) -> Self { pub(crate) fn msg(msg: &'static str) -> Self {
Self::Syntax(SyntaxErrorKind::Msg { msg }.into()) Self::Syntax(SyntaxError(SyntaxErrorKind::Msg { msg }))
} }
} }
// impl From<oxttl::SyntaxError> for SyntaxError { impl From<oxttl::SyntaxError> for SyntaxError {
// #[inline] #[inline]
// fn from(error: oxttl::SyntaxError) -> Self { fn from(error: oxttl::SyntaxError) -> Self {
// Self(SyntaxErrorKind::Turtle(error)) Self(SyntaxErrorKind::Turtle(error))
// } }
// } }
//
// impl From<oxrdfxml::SyntaxError> for SyntaxError {
// #[inline]
// fn from(error: oxrdfxml::SyntaxError) -> Self {
// Self(SyntaxErrorKind::RdfXml(error))
// }
// }
//
impl From<oxttl::ParseError> for ParseError { impl From<oxttl::ParseError> for ParseError {
#[inline] #[inline]
@ -43,6 +35,13 @@ impl From<oxttl::ParseError> for ParseError {
} }
} }
impl From<oxrdfxml::SyntaxError> for SyntaxError {
#[inline]
fn from(error: oxrdfxml::SyntaxError) -> Self {
Self(SyntaxErrorKind::RdfXml(error))
}
}
impl From<oxrdfxml::ParseError> for ParseError { impl From<oxrdfxml::ParseError> for ParseError {
#[inline] #[inline]
fn from(error: oxrdfxml::ParseError) -> Self { fn from(error: oxrdfxml::ParseError) -> Self {
@ -83,7 +82,7 @@ impl SyntaxError {
/// The location of the error inside of the file. /// The location of the error inside of the file.
#[inline] #[inline]
pub fn location(&self) -> Option<Range<TextPosition>> { pub fn location(&self) -> Option<Range<TextPosition>> {
match self { match &self.0 {
SyntaxErrorKind::Turtle(e) => { SyntaxErrorKind::Turtle(e) => {
let location = e.location(); let location = e.location();
Some( Some(
@ -106,7 +105,7 @@ impl SyntaxError {
impl From<SyntaxError> for io::Error { impl From<SyntaxError> for io::Error {
#[inline] #[inline]
fn from(error: SyntaxError) -> Self { fn from(error: SyntaxError) -> Self {
match error { match error.0 {
SyntaxErrorKind::Turtle(error) => error.into(), SyntaxErrorKind::Turtle(error) => error.into(),
SyntaxErrorKind::RdfXml(error) => error.into(), SyntaxErrorKind::RdfXml(error) => error.into(),
SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg), SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg),

@ -31,14 +31,23 @@ impl From<quick_xml::Error> for ParseError {
quick_xml::Error::Io(error) => { quick_xml::Error::Io(error) => {
Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e))) Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e)))
} }
_ => Self::Syntax(SyntaxError::Xml(error)), _ => Self::Syntax(SyntaxError {
inner: SyntaxErrorKind::Xml(error),
}),
} }
} }
} }
/// An error in the syntax of the parsed file. /// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum SyntaxError { #[error(transparent)]
pub struct SyntaxError {
#[from]
pub(crate) inner: SyntaxErrorKind,
}
#[derive(Debug, thiserror::Error)]
pub enum SyntaxErrorKind {
#[error(transparent)] #[error(transparent)]
Xml(#[from] quick_xml::Error), Xml(#[from] quick_xml::Error),
#[error("error while parsing IRI '{iri}': {error}")] #[error("error while parsing IRI '{iri}': {error}")]
@ -61,15 +70,17 @@ impl SyntaxError {
/// Builds an error from a printable error message. /// Builds an error from a printable error message.
#[inline] #[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self { pub(crate) fn msg(msg: impl Into<String>) -> Self {
Self::Msg { msg: msg.into() } Self {
inner: SyntaxErrorKind::Msg { msg: msg.into() },
}
} }
} }
impl From<SyntaxError> for io::Error { impl From<SyntaxError> for io::Error {
#[inline] #[inline]
fn from(error: SyntaxError) -> Self { fn from(error: SyntaxError) -> Self {
match error { match error.inner {
SyntaxError::Xml(error) => match error { SyntaxErrorKind::Xml(error) => match error {
quick_xml::Error::Io(error) => { quick_xml::Error::Io(error) => {
Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e)) Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e))
} }
@ -78,7 +89,7 @@ impl From<SyntaxError> for io::Error {
} }
_ => Self::new(io::ErrorKind::InvalidData, error), _ => Self::new(io::ErrorKind::InvalidData, error),
}, },
SyntaxError::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg), SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg),
_ => Self::new(io::ErrorKind::InvalidData, error), _ => Self::new(io::ErrorKind::InvalidData, error),
} }
} }

@ -1,4 +1,4 @@
use crate::error::{ParseError, SyntaxError}; use crate::error::{ParseError, SyntaxError, SyntaxErrorKind};
use crate::utils::*; use crate::utils::*;
use oxilangtag::LanguageTag; use oxilangtag::LanguageTag;
use oxiri::{Iri, IriParseError}; use oxiri::{Iri, IriParseError};
@ -575,7 +575,9 @@ impl<R> RdfXmlReader<R> {
tag tag
} else { } else {
LanguageTag::parse(tag.to_ascii_lowercase()) LanguageTag::parse(tag.to_ascii_lowercase())
.map_err(|error| SyntaxError::InvalidLanguageTag { tag, error })? .map_err(|error| SyntaxError {
inner: SyntaxErrorKind::InvalidLanguageTag { tag, error },
})?
.into_inner() .into_inner()
}); });
} else if attribute.key.as_ref() == b"xml:base" { } else if attribute.key.as_ref() == b"xml:base" {
@ -586,7 +588,9 @@ impl<R> RdfXmlReader<R> {
} else { } else {
Iri::parse(iri.clone()) Iri::parse(iri.clone())
} }
.map_err(|error| SyntaxError::InvalidIri { iri, error })?, .map_err(|error| SyntaxError {
inner: SyntaxErrorKind::InvalidIri { iri, error },
})?,
) )
} else { } else {
// We ignore other xml attributes // We ignore other xml attributes
@ -1165,9 +1169,11 @@ impl<R> RdfXmlReader<R> {
} else { } else {
base_iri.resolve(&relative_iri) base_iri.resolve(&relative_iri)
} }
.map_err(|error| SyntaxError::InvalidIri { .map_err(|error| SyntaxError {
iri: relative_iri, inner: SyntaxErrorKind::InvalidIri {
error, iri: relative_iri,
error,
},
})? })?
.into_inner(), .into_inner(),
)) ))
@ -1181,9 +1187,11 @@ impl<R> RdfXmlReader<R> {
relative_iri relative_iri
} else { } else {
Iri::parse(relative_iri.clone()) Iri::parse(relative_iri.clone())
.map_err(|error| SyntaxError::InvalidIri { .map_err(|error| SyntaxError {
iri: relative_iri, inner: SyntaxErrorKind::InvalidIri {
error, iri: relative_iri,
error,
},
})? })?
.into_inner() .into_inner()
})) }))

@ -2038,8 +2038,12 @@ fn time_on_timeline(props: &DateTimeSevenPropertyModel) -> Option<Decimal> {
} }
/// A parsing error /// A parsing error
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct ParseDateTimeError(#[from] ParseDateTimeErrorKind);
#[derive(Debug, Clone, thiserror::Error)] #[derive(Debug, Clone, thiserror::Error)]
pub enum ParseDateTimeError { enum ParseDateTimeErrorKind {
#[error("{day} is not a valid day of {month}")] #[error("{day} is not a valid day of {month}")]
InvalidDayOfMonth { day: u8, month: u8 }, InvalidDayOfMonth { day: u8, month: u8 },
#[error(transparent)] #[error(transparent)]
@ -2052,7 +2056,7 @@ pub enum ParseDateTimeError {
impl ParseDateTimeError { impl ParseDateTimeError {
const fn msg(message: &'static str) -> Self { const fn msg(message: &'static str) -> Self {
Self::Message(message) Self(ParseDateTimeErrorKind::Message(message))
} }
} }
@ -2308,7 +2312,7 @@ fn timezone_frag(input: &str) -> Result<(TimezoneOffset, &str), ParseDateTimeErr
Ok(( Ok((
TimezoneOffset::new(sign * (hours * 60 + i16::from(minutes))) TimezoneOffset::new(sign * (hours * 60 + i16::from(minutes)))
.map_err(ParseDateTimeError::InvalidTimezone)?, .map_err(|e| ParseDateTimeError(ParseDateTimeErrorKind::InvalidTimezone(e)))?,
input, input,
)) ))
} }
@ -2378,7 +2382,9 @@ fn optional_end<T>(
fn validate_day_of_month(year: Option<i64>, month: u8, day: u8) -> Result<(), ParseDateTimeError> { fn validate_day_of_month(year: Option<i64>, month: u8, day: u8) -> Result<(), ParseDateTimeError> {
// Constraint: Day-of-month Values // Constraint: Day-of-month Values
if day > days_in_month(year, month) { if day > days_in_month(year, month) {
return Err(ParseDateTimeError::InvalidDayOfMonth { day, month }); return Err(ParseDateTimeError(
ParseDateTimeErrorKind::InvalidDayOfMonth { day, month },
));
} }
Ok(()) Ok(())
} }
@ -2390,6 +2396,12 @@ fn validate_day_of_month(year: Option<i64>, month: u8, day: u8) -> Result<(), Pa
#[error("overflow during xsd:dateTime computation")] #[error("overflow during xsd:dateTime computation")]
pub struct DateTimeOverflowError; pub struct DateTimeOverflowError;
impl From<DateTimeOverflowError> for ParseDateTimeError {
fn from(error: DateTimeOverflowError) -> Self {
Self(ParseDateTimeErrorKind::Overflow(error))
}
}
/// The value provided as timezone is not valid. /// The value provided as timezone is not valid.
/// ///
/// Matches XPath [`FODT0003` error](https://www.w3.org/TR/xpath-functions-31/#ERRFODT0003). /// Matches XPath [`FODT0003` error](https://www.w3.org/TR/xpath-functions-31/#ERRFODT0003).

@ -465,7 +465,7 @@ impl FromStr for Decimal {
// (\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+) // (\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)
let input = input.as_bytes(); let input = input.as_bytes();
if input.is_empty() { if input.is_empty() {
return Err(ParseDecimalError::UnexpectedEnd); return Err(PARSE_UNEXPECTED_END);
} }
let (sign, mut input) = match input.first() { let (sign, mut input) = match input.first() {
@ -480,9 +480,9 @@ impl FromStr for Decimal {
if c.is_ascii_digit() { if c.is_ascii_digit() {
value = value value = value
.checked_mul(10) .checked_mul(10)
.ok_or(ParseDecimalError::Overflow)? .ok_or(PARSE_OVERFLOW)?
.checked_add(sign * i128::from(*c - b'0')) .checked_add(sign * i128::from(*c - b'0'))
.ok_or(ParseDecimalError::Overflow)?; .ok_or(PARSE_OVERFLOW)?;
input = &input[1..]; input = &input[1..];
} else { } else {
break; break;
@ -492,12 +492,12 @@ impl FromStr for Decimal {
let mut exp = DECIMAL_PART_POW; let mut exp = DECIMAL_PART_POW;
if let Some(c) = input.first() { if let Some(c) = input.first() {
if *c != b'.' { if *c != b'.' {
return Err(ParseDecimalError::UnexpectedChar); return Err(PARSE_UNEXPECTED_CHAR);
} }
input = &input[1..]; input = &input[1..];
if input.is_empty() && !with_before_dot { if input.is_empty() && !with_before_dot {
// We only have a dot // We only have a dot
return Err(ParseDecimalError::UnexpectedEnd); return Err(PARSE_UNEXPECTED_END);
} }
while input.last() == Some(&b'0') { while input.last() == Some(&b'0') {
// Hack to avoid underflows // Hack to avoid underflows
@ -508,25 +508,25 @@ impl FromStr for Decimal {
exp /= 10; exp /= 10;
value = value value = value
.checked_mul(10) .checked_mul(10)
.ok_or(ParseDecimalError::Overflow)? .ok_or(PARSE_OVERFLOW)?
.checked_add(sign * i128::from(*c - b'0')) .checked_add(sign * i128::from(*c - b'0'))
.ok_or(ParseDecimalError::Overflow)?; .ok_or(PARSE_OVERFLOW)?;
input = &input[1..]; input = &input[1..];
} else { } else {
return Err(ParseDecimalError::UnexpectedChar); return Err(PARSE_UNEXPECTED_CHAR);
} }
} }
if exp == 0 { if exp == 0 {
// Underflow // Underflow
return Err(ParseDecimalError::Underflow); return Err(PARSE_UNDERFLOW);
} }
} else if !with_before_dot { } else if !with_before_dot {
// It's empty // It's empty
return Err(ParseDecimalError::UnexpectedEnd); return Err(PARSE_UNEXPECTED_END);
} }
Ok(Self { Ok(Self {
value: value.checked_mul(exp).ok_or(ParseDecimalError::Overflow)?, value: value.checked_mul(exp).ok_or(PARSE_OVERFLOW)?,
}) })
} }
} }
@ -608,8 +608,12 @@ impl fmt::Display for Decimal {
} }
/// An error when parsing a [`Decimal`]. /// An error when parsing a [`Decimal`].
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct ParseDecimalError(#[from] DecimalParseErrorKind);
#[derive(Debug, Clone, thiserror::Error)] #[derive(Debug, Clone, thiserror::Error)]
pub enum ParseDecimalError { enum DecimalParseErrorKind {
#[error("Value overflow")] #[error("Value overflow")]
Overflow, Overflow,
#[error("Value underflow")] #[error("Value underflow")]
@ -620,9 +624,16 @@ pub enum ParseDecimalError {
UnexpectedEnd, UnexpectedEnd,
} }
const PARSE_OVERFLOW: ParseDecimalError = ParseDecimalError(DecimalParseErrorKind::Overflow);
const PARSE_UNDERFLOW: ParseDecimalError = ParseDecimalError(DecimalParseErrorKind::Underflow);
const PARSE_UNEXPECTED_CHAR: ParseDecimalError =
ParseDecimalError(DecimalParseErrorKind::UnexpectedChar);
const PARSE_UNEXPECTED_END: ParseDecimalError =
ParseDecimalError(DecimalParseErrorKind::UnexpectedEnd);
impl From<TooLargeForDecimalError> for ParseDecimalError { impl From<TooLargeForDecimalError> for ParseDecimalError {
fn from(_: TooLargeForDecimalError) -> Self { fn from(_: TooLargeForDecimalError) -> Self {
Self::Overflow Self(DecimalParseErrorKind::Overflow)
} }
} }

@ -1,6 +1,6 @@
//! Implementation of [SPARQL 1.1 Query Results CSV and TSV Formats](https://www.w3.org/TR/sparql11-results-csv-tsv/) //! Implementation of [SPARQL 1.1 Query Results CSV and TSV Formats](https://www.w3.org/TR/sparql11-results-csv-tsv/)
use crate::error::{ParseError, SyntaxError, TextPosition}; use crate::error::{ParseError, SyntaxError, SyntaxErrorKind, TextPosition};
use memchr::memchr; use memchr::memchr;
use oxrdf::vocab::xsd; use oxrdf::vocab::xsd;
use oxrdf::*; use oxrdf::*;
@ -508,21 +508,23 @@ impl<R: Read> TsvSolutionsReader<R> {
.sum::<usize>(); .sum::<usize>();
let start_position_bytes = let start_position_bytes =
line.split('\t').take(i).map(|c| c.len() + 1).sum::<usize>(); line.split('\t').take(i).map(|c| c.len() + 1).sum::<usize>();
SyntaxError::Term { SyntaxError {
error: e, inner: SyntaxErrorKind::Term {
term: v.into(), error: e,
location: TextPosition { term: v.into(),
line: self.reader.line_count - 1, location: TextPosition {
column: start_position_char.try_into().unwrap(), line: self.reader.line_count - 1,
offset: self.reader.last_line_start column: start_position_char.try_into().unwrap(),
+ u64::try_from(start_position_bytes).unwrap(), offset: self.reader.last_line_start
}..TextPosition { + u64::try_from(start_position_bytes).unwrap(),
line: self.reader.line_count - 1, }..TextPosition {
column: (start_position_char + v.chars().count()) line: self.reader.line_count - 1,
.try_into() column: (start_position_char + v.chars().count())
.unwrap(), .try_into()
offset: self.reader.last_line_start .unwrap(),
+ u64::try_from(start_position_bytes + v.len()).unwrap(), offset: self.reader.last_line_start
+ u64::try_from(start_position_bytes + v.len()).unwrap(),
},
}, },
} }
})?)) })?))

@ -40,14 +40,23 @@ impl From<quick_xml::Error> for ParseError {
quick_xml::Error::Io(error) => { quick_xml::Error::Io(error) => {
Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e))) Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e)))
} }
_ => Self::Syntax(SyntaxError::Xml(error)), _ => Self::Syntax(SyntaxError {
inner: SyntaxErrorKind::Xml(error),
}),
} }
} }
} }
/// An error in the syntax of the parsed file. /// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum SyntaxError { #[error(transparent)]
pub struct SyntaxError {
#[from]
pub(crate) inner: SyntaxErrorKind,
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum SyntaxErrorKind {
#[error(transparent)] #[error(transparent)]
Json(#[from] json_event_parser::SyntaxError), Json(#[from] json_event_parser::SyntaxError),
#[error(transparent)] #[error(transparent)]
@ -70,26 +79,30 @@ impl SyntaxError {
/// Builds an error from a printable error message. /// Builds an error from a printable error message.
#[inline] #[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self { pub(crate) fn msg(msg: impl Into<String>) -> Self {
Self::Msg { Self {
msg: msg.into(), inner: SyntaxErrorKind::Msg {
location: None, msg: msg.into(),
location: None,
},
} }
} }
/// Builds an error from a printable error message and a location /// Builds an error from a printable error message and a location
#[inline] #[inline]
pub(crate) fn located_message(msg: impl Into<String>, location: Range<TextPosition>) -> Self { pub(crate) fn located_message(msg: impl Into<String>, location: Range<TextPosition>) -> Self {
Self::Msg { Self {
msg: msg.into(), inner: SyntaxErrorKind::Msg {
location: Some(location), msg: msg.into(),
location: Some(location),
},
} }
} }
/// The location of the error inside of the file. /// The location of the error inside of the file.
#[inline] #[inline]
pub fn location(&self) -> Option<Range<TextPosition>> { pub fn location(&self) -> Option<Range<TextPosition>> {
match self { match &self.inner {
Self::Json(e) => { SyntaxErrorKind::Json(e) => {
let location = e.location(); let location = e.location();
Some( Some(
TextPosition { TextPosition {
@ -103,9 +116,9 @@ impl SyntaxError {
}, },
) )
} }
Self::Term { location, .. } => Some(location.clone()), SyntaxErrorKind::Term { location, .. } => Some(location.clone()),
Self::Msg { location, .. } => location.clone(), SyntaxErrorKind::Msg { location, .. } => location.clone(),
Self::Xml(_) => None, SyntaxErrorKind::Xml(_) => None,
} }
} }
} }
@ -113,9 +126,9 @@ impl SyntaxError {
impl From<SyntaxError> for io::Error { impl From<SyntaxError> for io::Error {
#[inline] #[inline]
fn from(error: SyntaxError) -> Self { fn from(error: SyntaxError) -> Self {
match error { match error.inner {
SyntaxError::Json(error) => Self::new(io::ErrorKind::InvalidData, error), SyntaxErrorKind::Json(error) => Self::new(io::ErrorKind::InvalidData, error),
SyntaxError::Xml(error) => match error { SyntaxErrorKind::Xml(error) => match error {
quick_xml::Error::Io(error) => { quick_xml::Error::Io(error) => {
Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e)) Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e))
} }
@ -124,8 +137,16 @@ impl From<SyntaxError> for io::Error {
} }
_ => Self::new(io::ErrorKind::InvalidData, error), _ => Self::new(io::ErrorKind::InvalidData, error),
}, },
SyntaxError::Term { .. } => Self::new(io::ErrorKind::InvalidData, error), SyntaxErrorKind::Term { .. } => Self::new(io::ErrorKind::InvalidData, error),
SyntaxError::Msg { msg, .. } => Self::new(io::ErrorKind::InvalidData, msg), SyntaxErrorKind::Msg { msg, .. } => Self::new(io::ErrorKind::InvalidData, msg),
}
}
}
impl From<json_event_parser::SyntaxError> for SyntaxError {
fn from(error: json_event_parser::SyntaxError) -> Self {
Self {
inner: SyntaxErrorKind::Json(error),
} }
} }
} }

@ -17,13 +17,14 @@ use std::str::FromStr;
/// Parses a SPARQL query with an optional base IRI to resolve relative IRIs in the query. /// Parses a SPARQL query with an optional base IRI to resolve relative IRIs in the query.
pub fn parse_query(query: &str, base_iri: Option<&str>) -> Result<Query, ParseError> { pub fn parse_query(query: &str, base_iri: Option<&str>) -> Result<Query, ParseError> {
let mut state = ParserState::from_base_iri(base_iri)?; let mut state = ParserState::from_base_iri(base_iri)?;
parser::QueryUnit(query, &mut state).map_err(ParseError::Parser) parser::QueryUnit(query, &mut state).map_err(|e| ParseError(ParseErrorKind::Parser(e)))
} }
/// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query. /// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query.
pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, ParseError> { pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, ParseError> {
let mut state = ParserState::from_base_iri(base_iri)?; let mut state = ParserState::from_base_iri(base_iri)?;
let operations = parser::UpdateInit(update, &mut state).map_err(ParseError::Parser)?; let operations = parser::UpdateInit(update, &mut state)
.map_err(|e| ParseError(ParseErrorKind::Parser(e)))?;
Ok(Update { Ok(Update {
operations, operations,
base_iri: state.base_iri, base_iri: state.base_iri,
@ -32,7 +33,11 @@ pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, Pars
/// Error returned during SPARQL parsing. /// Error returned during SPARQL parsing.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum ParseError { #[error(transparent)]
pub struct ParseError(#[from] ParseErrorKind);
#[derive(Debug, thiserror::Error)]
enum ParseErrorKind {
#[error("Invalid SPARQL base IRI provided: {0}")] #[error("Invalid SPARQL base IRI provided: {0}")]
InvalidBaseIri(#[from] IriParseError), InvalidBaseIri(#[from] IriParseError),
#[error(transparent)] #[error(transparent)]
@ -667,7 +672,10 @@ impl ParserState {
pub(crate) fn from_base_iri(base_iri: Option<&str>) -> Result<Self, ParseError> { pub(crate) fn from_base_iri(base_iri: Option<&str>) -> Result<Self, ParseError> {
Ok(Self { Ok(Self {
base_iri: if let Some(base_iri) = base_iri { base_iri: if let Some(base_iri) = base_iri {
Some(Iri::parse(base_iri.to_owned()).map_err(ParseError::InvalidBaseIri)?) Some(
Iri::parse(base_iri.to_owned())
.map_err(|e| ParseError(ParseErrorKind::InvalidBaseIri(e)))?,
)
} else { } else {
None None
}, },

Loading…
Cancel
Save