Error renaming

```
enum sparesults::error::ParseError -> QueryResultsParseError
struct sparesults::error::SyntaxError -> QueryResultsSyntaxError
    Inlined inner

enum oxrdfxml::error::ParseError -> RdfXmlParseError
struct oxrdfxml::error::SyntaxError -> RdfXmlSyntaxError

enum oxttl::toolkit::error::ParseError -> TurtleParseError
struct oxttl::toolkit::error::SyntaxError -> TurtleSyntaxError

enum oxrdfio::error::ParseError -> RdfParseError
struct oxrdfio::error::SyntaxError -> RdfSyntaxError

struct spargebra::parser::ParseError -> SparqlSyntaxError
enum spargebra::parser::ParseErrorKind
  Parser -> Syntax
```
pull/782/head
Yuri Astrakhan 11 months ago committed by Thomas Tanon
parent 655ecd3e91
commit 0400f04915
  1. 6
      Cargo.toml
  2. 6
      lib/oxigraph/src/io/read.rs
  3. 24
      lib/oxigraph/src/sparql/algebra.rs
  4. 8
      lib/oxigraph/src/sparql/error.rs
  5. 2
      lib/oxigraph/src/sparql/mod.rs
  6. 9
      lib/oxigraph/src/sparql/model.rs
  7. 4
      lib/oxigraph/src/storage/error.rs
  8. 6
      lib/oxigraph/src/store.rs
  9. 2
      lib/oxrdfio/Cargo.toml
  10. 52
      lib/oxrdfio/src/error.rs
  11. 2
      lib/oxrdfio/src/lib.rs
  12. 38
      lib/oxrdfio/src/parser.rs
  13. 2
      lib/oxrdfxml/Cargo.toml
  14. 24
      lib/oxrdfxml/src/error.rs
  15. 2
      lib/oxrdfxml/src/lib.rs
  16. 124
      lib/oxrdfxml/src/parser.rs
  17. 2
      lib/oxttl/Cargo.toml
  18. 2
      lib/oxttl/src/lib.rs
  19. 18
      lib/oxttl/src/n3.rs
  20. 12
      lib/oxttl/src/nquads.rs
  21. 12
      lib/oxttl/src/ntriples.rs
  22. 24
      lib/oxttl/src/toolkit/error.rs
  23. 11
      lib/oxttl/src/toolkit/lexer.rs
  24. 2
      lib/oxttl/src/toolkit/mod.rs
  25. 14
      lib/oxttl/src/toolkit/parser.rs
  26. 16
      lib/oxttl/src/trig.rs
  27. 16
      lib/oxttl/src/turtle.rs
  28. 52
      lib/sparesults/src/csv.rs
  29. 65
      lib/sparesults/src/error.rs
  30. 167
      lib/sparesults/src/json.rs
  31. 2
      lib/sparesults/src/lib.rs
  32. 20
      lib/sparesults/src/parser.rs
  33. 83
      lib/sparesults/src/xml.rs
  34. 2
      lib/spargebra/src/lib.rs
  35. 16
      lib/spargebra/src/parser.rs
  36. 12
      lib/spargebra/src/query.rs
  37. 12
      lib/spargebra/src/update.rs
  38. 8
      python/src/io.rs
  39. 13
      python/src/sparql.rs

@ -70,11 +70,11 @@ zstd = ">=0.12, <0.14"
# Internal dependencies
oxigraph = { version = "0.4.0-alpha.3-dev", path = "lib/oxigraph" }
oxrdf = { version = "0.2.0-alpha.2", path = "lib/oxrdf" }
oxrdfio = { version = "0.1.0-alpha.2", path = "lib/oxrdfio" }
oxrdfxml = { version = "0.1.0-alpha.2", path = "lib/oxrdfxml" }
oxrdfio = { version = "0.1.0-alpha.3-dev", path = "lib/oxrdfio" }
oxrdfxml = { version = "0.1.0-alpha.3-dev", path = "lib/oxrdfxml" }
oxrocksdb-sys = { version = "0.4.0-alpha.3-dev", path = "./oxrocksdb-sys" }
oxsdatatypes = { version = "0.2.0-alpha.1", path = "lib/oxsdatatypes" }
oxttl = { version = "0.1.0-alpha.2", path = "lib/oxttl" }
oxttl = { version = "0.1.0-alpha.3-dev", path = "lib/oxttl" }
sparesults = { version = "0.2.0-alpha.2", path = "lib/sparesults" }
spargebra = { version = "0.3.0-alpha.2", path = "lib/spargebra" }
sparopt = { version = "0.1.0-alpha.2", path = "lib/sparopt" }

@ -5,7 +5,7 @@
use crate::io::{DatasetFormat, GraphFormat};
use crate::model::*;
use oxiri::IriParseError;
use oxrdfio::{FromReadQuadReader, ParseError, RdfParser};
use oxrdfio::{FromReadQuadReader, RdfParseError, RdfParser};
use std::io::Read;
/// Parsers for RDF graph serialization formats.
@ -100,7 +100,7 @@ pub struct TripleReader<R: Read> {
}
impl<R: Read> Iterator for TripleReader<R> {
type Item = Result<Triple, ParseError>;
type Item = Result<Triple, RdfParseError>;
fn next(&mut self) -> Option<Self::Item> {
Some(self.parser.next()?.map(Into::into).map_err(Into::into))
@ -192,7 +192,7 @@ pub struct QuadReader<R: Read> {
}
impl<R: Read> Iterator for QuadReader<R> {
type Item = Result<Quad, ParseError>;
type Item = Result<Quad, RdfParseError>;
fn next(&mut self) -> Option<Self::Item> {
Some(self.parser.next()?.map_err(Into::into))

@ -38,7 +38,10 @@ pub struct Query {
impl Query {
/// Parses a SPARQL query with an optional base IRI to resolve relative IRIs in the query.
pub fn parse(query: &str, base_iri: Option<&str>) -> Result<Self, spargebra::ParseError> {
pub fn parse(
query: &str,
base_iri: Option<&str>,
) -> Result<Self, spargebra::SparqlSyntaxError> {
let start = Timer::now();
let query = Self::from(spargebra::Query::parse(query, base_iri)?);
Ok(Self {
@ -66,7 +69,7 @@ impl fmt::Display for Query {
}
impl FromStr for Query {
type Err = spargebra::ParseError;
type Err = spargebra::SparqlSyntaxError;
fn from_str(query: &str) -> Result<Self, Self::Err> {
Self::parse(query, None)
@ -74,7 +77,7 @@ impl FromStr for Query {
}
impl TryFrom<&str> for Query {
type Error = spargebra::ParseError;
type Error = spargebra::SparqlSyntaxError;
fn try_from(query: &str) -> Result<Self, Self::Error> {
Self::from_str(query)
@ -82,7 +85,7 @@ impl TryFrom<&str> for Query {
}
impl TryFrom<&String> for Query {
type Error = spargebra::ParseError;
type Error = spargebra::SparqlSyntaxError;
fn try_from(query: &String) -> Result<Self, Self::Error> {
Self::from_str(query)
@ -113,7 +116,7 @@ impl From<spargebra::Query> for Query {
/// let update = Update::parse(update_str, None)?;
///
/// assert_eq!(update.to_string().trim(), update_str);
/// # Ok::<_, oxigraph::sparql::ParseError>(())
/// # Ok::<_, oxigraph::sparql::SparqlSyntaxError>(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct Update {
@ -123,7 +126,10 @@ pub struct Update {
impl Update {
/// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query.
pub fn parse(update: &str, base_iri: Option<&str>) -> Result<Self, spargebra::ParseError> {
pub fn parse(
update: &str,
base_iri: Option<&str>,
) -> Result<Self, spargebra::SparqlSyntaxError> {
let update = spargebra::Update::parse(update, base_iri)?;
Ok(Self {
using_datasets: update
@ -159,7 +165,7 @@ impl fmt::Display for Update {
}
impl FromStr for Update {
type Err = spargebra::ParseError;
type Err = spargebra::SparqlSyntaxError;
fn from_str(update: &str) -> Result<Self, Self::Err> {
Self::parse(update, None)
@ -167,7 +173,7 @@ impl FromStr for Update {
}
impl TryFrom<&str> for Update {
type Error = spargebra::ParseError;
type Error = spargebra::SparqlSyntaxError;
fn try_from(update: &str) -> Result<Self, Self::Error> {
Self::from_str(update)
@ -175,7 +181,7 @@ impl TryFrom<&str> for Update {
}
impl TryFrom<&String> for Update {
type Error = spargebra::ParseError;
type Error = spargebra::SparqlSyntaxError;
fn try_from(update: &String) -> Result<Self, Self::Error> {
Self::from_str(update)

@ -1,7 +1,7 @@
use crate::io::ParseError as RdfParseError;
use crate::io::RdfParseError;
use crate::model::NamedNode;
use crate::sparql::results::ParseError as ResultsParseError;
use crate::sparql::ParseError;
use crate::sparql::results::QueryResultsParseError as ResultsParseError;
use crate::sparql::SparqlSyntaxError;
use crate::storage::StorageError;
use std::convert::Infallible;
use std::error::Error;
@ -13,7 +13,7 @@ use std::io;
pub enum EvaluationError {
/// An error in SPARQL parsing.
#[error(transparent)]
Parsing(#[from] ParseError),
Parsing(#[from] SparqlSyntaxError),
/// An error from the storage.
#[error(transparent)]
Storage(#[from] StorageError),

@ -25,7 +25,7 @@ use crate::storage::StorageReader;
use json_event_parser::{JsonEvent, ToWriteJsonWriter};
pub use oxrdf::{Variable, VariableNameParseError};
use oxsdatatypes::{DayTimeDuration, Float};
pub use spargebra::ParseError;
pub use spargebra::SparqlSyntaxError;
use sparopt::algebra::GraphPattern;
use sparopt::Optimizer;
use std::collections::HashMap;

@ -2,8 +2,8 @@ use crate::io::{RdfFormat, RdfSerializer};
use crate::model::*;
use crate::sparql::error::EvaluationError;
use crate::sparql::results::{
FromReadQueryResultsReader, FromReadSolutionsReader, ParseError, QueryResultsFormat,
QueryResultsParser, QueryResultsSerializer,
FromReadQueryResultsReader, FromReadSolutionsReader, QueryResultsFormat,
QueryResultsParseError, QueryResultsParser, QueryResultsSerializer,
};
use oxrdf::{Variable, VariableRef};
pub use sparesults::QuerySolution;
@ -22,7 +22,10 @@ pub enum QueryResults {
impl QueryResults {
/// Reads a SPARQL query results serialization.
pub fn read(read: impl Read + 'static, format: QueryResultsFormat) -> Result<Self, ParseError> {
pub fn read(
read: impl Read + 'static,
format: QueryResultsFormat,
) -> Result<Self, QueryResultsParseError> {
Ok(QueryResultsParser::from_format(format)
.parse_read(read)?
.into())

@ -1,4 +1,4 @@
use crate::io::{ParseError, RdfFormat};
use crate::io::{RdfFormat, RdfParseError};
use crate::storage::numeric_encoder::EncodedTerm;
use oxiri::IriParseError;
use oxrdf::TermRef;
@ -83,7 +83,7 @@ impl From<CorruptionError> for io::Error {
pub enum LoaderError {
/// An error raised while reading the file.
#[error(transparent)]
Parsing(#[from] ParseError),
Parsing(#[from] RdfParseError),
/// An error raised during the insertion in the store.
#[error(transparent)]
Storage(#[from] StorageError),

@ -26,7 +26,7 @@
//! # Result::<_, Box<dyn std::error::Error>>::Ok(())
//! ```
#[cfg(not(target_family = "wasm"))]
use crate::io::ParseError;
use crate::io::RdfParseError;
use crate::io::{RdfFormat, RdfParser, RdfSerializer};
use crate::model::*;
use crate::sparql::{
@ -1592,7 +1592,7 @@ impl Iterator for GraphNameIter {
#[must_use]
pub struct BulkLoader {
storage: StorageBulkLoader,
on_parse_error: Option<Box<dyn Fn(ParseError) -> Result<(), ParseError>>>,
on_parse_error: Option<Box<dyn Fn(RdfParseError) -> Result<(), RdfParseError>>>,
}
#[cfg(not(target_family = "wasm"))]
@ -1647,7 +1647,7 @@ impl BulkLoader {
/// By default the parsing fails.
pub fn on_parse_error(
mut self,
callback: impl Fn(ParseError) -> Result<(), ParseError> + 'static,
callback: impl Fn(RdfParseError) -> Result<(), RdfParseError> + 'static,
) -> Self {
self.on_parse_error = Some(Box::new(callback));
self

@ -1,6 +1,6 @@
[package]
name = "oxrdfio"
version = "0.1.0-alpha.2"
version = "0.1.0-alpha.3-dev"
authors.workspace = true
license.workspace = true
readme = "README.md"

@ -3,61 +3,61 @@ use std::ops::Range;
/// Error returned during RDF format parsing.
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
pub enum RdfParseError {
/// I/O error during parsing (file not found...).
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
#[error(transparent)]
Syntax(#[from] SyntaxError),
Syntax(#[from] RdfSyntaxError),
}
impl ParseError {
impl RdfParseError {
pub(crate) fn msg(msg: &'static str) -> Self {
Self::Syntax(SyntaxError(SyntaxErrorKind::Msg(msg)))
Self::Syntax(RdfSyntaxError(SyntaxErrorKind::Msg(msg)))
}
}
impl From<oxttl::SyntaxError> for SyntaxError {
impl From<oxttl::TurtleSyntaxError> for RdfSyntaxError {
#[inline]
fn from(error: oxttl::SyntaxError) -> Self {
fn from(error: oxttl::TurtleSyntaxError) -> Self {
Self(SyntaxErrorKind::Turtle(error))
}
}
impl From<oxttl::ParseError> for ParseError {
impl From<oxttl::TurtleParseError> for RdfParseError {
#[inline]
fn from(error: oxttl::ParseError) -> Self {
fn from(error: oxttl::TurtleParseError) -> Self {
match error {
oxttl::ParseError::Syntax(e) => Self::Syntax(e.into()),
oxttl::ParseError::Io(e) => Self::Io(e),
oxttl::TurtleParseError::Syntax(e) => Self::Syntax(e.into()),
oxttl::TurtleParseError::Io(e) => Self::Io(e),
}
}
}
impl From<oxrdfxml::SyntaxError> for SyntaxError {
impl From<oxrdfxml::RdfXmlSyntaxError> for RdfSyntaxError {
#[inline]
fn from(error: oxrdfxml::SyntaxError) -> Self {
fn from(error: oxrdfxml::RdfXmlSyntaxError) -> Self {
Self(SyntaxErrorKind::RdfXml(error))
}
}
impl From<oxrdfxml::ParseError> for ParseError {
impl From<oxrdfxml::RdfXmlParseError> for RdfParseError {
#[inline]
fn from(error: oxrdfxml::ParseError) -> Self {
fn from(error: oxrdfxml::RdfXmlParseError) -> Self {
match error {
oxrdfxml::ParseError::Syntax(e) => Self::Syntax(e.into()),
oxrdfxml::ParseError::Io(e) => Self::Io(e),
oxrdfxml::RdfXmlParseError::Syntax(e) => Self::Syntax(e.into()),
oxrdfxml::RdfXmlParseError::Io(e) => Self::Io(e),
}
}
}
impl From<ParseError> for io::Error {
impl From<RdfParseError> for io::Error {
#[inline]
fn from(error: ParseError) -> Self {
fn from(error: RdfParseError) -> Self {
match error {
ParseError::Io(error) => error,
ParseError::Syntax(error) => error.into(),
RdfParseError::Io(error) => error,
RdfParseError::Syntax(error) => error.into(),
}
}
}
@ -65,20 +65,20 @@ impl From<ParseError> for io::Error {
/// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct SyntaxError(#[from] SyntaxErrorKind);
pub struct RdfSyntaxError(#[from] SyntaxErrorKind);
/// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)]
enum SyntaxErrorKind {
#[error(transparent)]
Turtle(#[from] oxttl::SyntaxError),
Turtle(#[from] oxttl::TurtleSyntaxError),
#[error(transparent)]
RdfXml(#[from] oxrdfxml::SyntaxError),
RdfXml(#[from] oxrdfxml::RdfXmlSyntaxError),
#[error("{0}")]
Msg(&'static str),
}
impl SyntaxError {
impl RdfSyntaxError {
/// The location of the error inside of the file.
#[inline]
pub fn location(&self) -> Option<Range<TextPosition>> {
@ -102,9 +102,9 @@ impl SyntaxError {
}
}
impl From<SyntaxError> for io::Error {
impl From<RdfSyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
fn from(error: RdfSyntaxError) -> Self {
match error.0 {
SyntaxErrorKind::Turtle(error) => error.into(),
SyntaxErrorKind::RdfXml(error) => error.into(),

@ -9,7 +9,7 @@ mod format;
mod parser;
mod serializer;
pub use error::{ParseError, SyntaxError, TextPosition};
pub use error::{RdfParseError, RdfSyntaxError, TextPosition};
pub use format::RdfFormat;
#[cfg(feature = "async-tokio")]
pub use parser::FromTokioAsyncReadQuadReader;

@ -1,6 +1,6 @@
//! Utilities to read RDF graphs and datasets.
pub use crate::error::ParseError;
pub use crate::error::RdfParseError;
use crate::format::RdfFormat;
use oxrdf::{BlankNode, GraphName, IriParseError, Quad, Subject, Term, Triple};
#[cfg(feature = "async-tokio")]
@ -310,7 +310,7 @@ impl RdfParser {
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxrdfio::ParseError> {
/// # async fn main() -> Result<(), oxrdfio::RdfParseError> {
/// let file = "<http://example.com/s> <http://example.com/p> <http://example.com/o> .";
///
/// let parser = RdfParser::from_format(RdfFormat::NTriples);
@ -396,7 +396,7 @@ enum FromReadQuadReaderKind<R: Read> {
}
impl<R: Read> Iterator for FromReadQuadReader<R> {
type Item = Result<Quad, ParseError>;
type Item = Result<Quad, RdfParseError>;
fn next(&mut self) -> Option<Self::Item> {
Some(match &mut self.parser {
@ -507,7 +507,7 @@ impl<R: Read> FromReadQuadReader<R> {
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxrdfio::ParseError> {
/// # async fn main() -> Result<(), oxrdfio::RdfParseError> {
/// let file = "<http://example.com/s> <http://example.com/p> <http://example.com/o> .";
///
/// let parser = RdfParser::from_format(RdfFormat::NTriples);
@ -537,7 +537,7 @@ enum FromTokioAsyncReadQuadReaderKind<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadQuadReader<R> {
pub async fn next(&mut self) -> Option<Result<Quad, ParseError>> {
pub async fn next(&mut self) -> Option<Result<Quad, RdfParseError>> {
Some(match &mut self.parser {
FromTokioAsyncReadQuadReaderKind::N3(parser) => match parser.next().await? {
Ok(quad) => self.mapper.map_n3_quad(quad),
@ -578,7 +578,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadQuadReader<R> {
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -618,7 +618,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadQuadReader<R> {
/// use oxrdfio::{RdfFormat, RdfParser};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -728,18 +728,18 @@ impl QuadMapper {
}
}
fn map_graph_name(&mut self, graph_name: GraphName) -> Result<GraphName, ParseError> {
fn map_graph_name(&mut self, graph_name: GraphName) -> Result<GraphName, RdfParseError> {
match graph_name {
GraphName::NamedNode(node) => {
if self.without_named_graphs {
Err(ParseError::msg("Named graphs are not allowed"))
Err(RdfParseError::msg("Named graphs are not allowed"))
} else {
Ok(node.into())
}
}
GraphName::BlankNode(node) => {
if self.without_named_graphs {
Err(ParseError::msg("Named graphs are not allowed"))
Err(RdfParseError::msg("Named graphs are not allowed"))
} else {
Ok(self.map_blank_node(node).into())
}
@ -748,7 +748,7 @@ impl QuadMapper {
}
}
fn map_quad(&mut self, quad: Quad) -> Result<Quad, ParseError> {
fn map_quad(&mut self, quad: Quad) -> Result<Quad, RdfParseError> {
Ok(Quad {
subject: self.map_subject(quad.subject),
predicate: quad.predicate,
@ -761,33 +761,33 @@ impl QuadMapper {
self.map_triple(triple).in_graph(self.default_graph.clone())
}
fn map_n3_quad(&mut self, quad: N3Quad) -> Result<Quad, ParseError> {
fn map_n3_quad(&mut self, quad: N3Quad) -> Result<Quad, RdfParseError> {
Ok(Quad {
subject: match quad.subject {
N3Term::NamedNode(s) => Ok(s.into()),
N3Term::BlankNode(s) => Ok(self.map_blank_node(s).into()),
N3Term::Literal(_) => Err(ParseError::msg(
N3Term::Literal(_) => Err(RdfParseError::msg(
"literals are not allowed in regular RDF subjects",
)),
#[cfg(feature = "rdf-star")]
N3Term::Triple(s) => Ok(self.map_triple(*s).into()),
N3Term::Variable(_) => Err(ParseError::msg(
N3Term::Variable(_) => Err(RdfParseError::msg(
"variables are not allowed in regular RDF subjects",
)),
}?,
predicate: match quad.predicate {
N3Term::NamedNode(p) => Ok(p),
N3Term::BlankNode(_) => Err(ParseError::msg(
N3Term::BlankNode(_) => Err(RdfParseError::msg(
"blank nodes are not allowed in regular RDF predicates",
)),
N3Term::Literal(_) => Err(ParseError::msg(
N3Term::Literal(_) => Err(RdfParseError::msg(
"literals are not allowed in regular RDF predicates",
)),
#[cfg(feature = "rdf-star")]
N3Term::Triple(_) => Err(ParseError::msg(
N3Term::Triple(_) => Err(RdfParseError::msg(
"quoted triples are not allowed in regular RDF predicates",
)),
N3Term::Variable(_) => Err(ParseError::msg(
N3Term::Variable(_) => Err(RdfParseError::msg(
"variables are not allowed in regular RDF predicates",
)),
}?,
@ -797,7 +797,7 @@ impl QuadMapper {
N3Term::Literal(o) => Ok(o.into()),
#[cfg(feature = "rdf-star")]
N3Term::Triple(o) => Ok(self.map_triple(*o).into()),
N3Term::Variable(_) => Err(ParseError::msg(
N3Term::Variable(_) => Err(RdfParseError::msg(
"variables are not allowed in regular RDF objects",
)),
}?,

@ -1,6 +1,6 @@
[package]
name = "oxrdfxml"
version = "0.1.0-alpha.2"
version = "0.1.0-alpha.3-dev"
authors.workspace = true
license.workspace = true
readme = "README.md"

@ -5,33 +5,33 @@ use std::sync::Arc;
/// Error returned during RDF/XML parsing.
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
pub enum RdfXmlParseError {
/// I/O error during parsing (file not found...).
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
#[error(transparent)]
Syntax(#[from] SyntaxError),
Syntax(#[from] RdfXmlSyntaxError),
}
impl From<ParseError> for io::Error {
impl From<RdfXmlParseError> for io::Error {
#[inline]
fn from(error: ParseError) -> Self {
fn from(error: RdfXmlParseError) -> Self {
match error {
ParseError::Io(error) => error,
ParseError::Syntax(error) => error.into(),
RdfXmlParseError::Io(error) => error,
RdfXmlParseError::Syntax(error) => error.into(),
}
}
}
impl From<quick_xml::Error> for ParseError {
impl From<quick_xml::Error> for RdfXmlParseError {
#[inline]
fn from(error: quick_xml::Error) -> Self {
match error {
quick_xml::Error::Io(error) => {
Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e)))
}
_ => Self::Syntax(SyntaxError(SyntaxErrorKind::Xml(error))),
_ => Self::Syntax(RdfXmlSyntaxError(SyntaxErrorKind::Xml(error))),
}
}
}
@ -39,7 +39,7 @@ impl From<quick_xml::Error> for ParseError {
/// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct SyntaxError(#[from] pub(crate) SyntaxErrorKind);
pub struct RdfXmlSyntaxError(#[from] pub(crate) SyntaxErrorKind);
#[derive(Debug, thiserror::Error)]
pub enum SyntaxErrorKind {
@ -61,7 +61,7 @@ pub enum SyntaxErrorKind {
Msg(String),
}
impl SyntaxError {
impl RdfXmlSyntaxError {
/// Builds an error from a printable error message.
#[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self {
@ -69,9 +69,9 @@ impl SyntaxError {
}
}
impl From<SyntaxError> for io::Error {
impl From<RdfXmlSyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
fn from(error: RdfXmlSyntaxError) -> Self {
match error.0 {
SyntaxErrorKind::Xml(error) => match error {
quick_xml::Error::Io(error) => {

@ -9,7 +9,7 @@ mod parser;
mod serializer;
mod utils;
pub use error::{ParseError, SyntaxError};
pub use error::{RdfXmlParseError, RdfXmlSyntaxError};
#[cfg(feature = "async-tokio")]
pub use parser::FromTokioAsyncReadRdfXmlReader;
pub use parser::{FromReadRdfXmlReader, RdfXmlParser};

@ -1,4 +1,4 @@
use crate::error::{ParseError, SyntaxError, SyntaxErrorKind};
use crate::error::{RdfXmlParseError, RdfXmlSyntaxError, SyntaxErrorKind};
use crate::utils::*;
use oxilangtag::LanguageTag;
use oxiri::{Iri, IriParseError};
@ -126,7 +126,7 @@ impl RdfXmlParser {
/// use oxrdfxml::RdfXmlParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxrdfxml::ParseError> {
/// # async fn main() -> Result<(), oxrdfxml::RdfXmlParseError> {
/// let file = br#"<?xml version="1.0"?>
/// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
/// <rdf:Description rdf:about="http://example.com/foo">
@ -214,7 +214,7 @@ pub struct FromReadRdfXmlReader<R: Read> {
}
impl<R: Read> Iterator for FromReadRdfXmlReader<R> {
type Item = Result<Triple, ParseError>;
type Item = Result<Triple, RdfXmlParseError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
@ -236,7 +236,7 @@ impl<R: Read> FromReadRdfXmlReader<R> {
self.reader.reader.buffer_position()
}
fn parse_step(&mut self) -> Result<(), ParseError> {
fn parse_step(&mut self) -> Result<(), RdfXmlParseError> {
self.reader_buffer.clear();
let event = self
.reader
@ -255,7 +255,7 @@ impl<R: Read> FromReadRdfXmlReader<R> {
/// use oxrdfxml::RdfXmlParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxrdfxml::ParseError> {
/// # async fn main() -> Result<(), oxrdfxml::RdfXmlParseError> {
/// let file = br#"<?xml version="1.0"?>
/// <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:schema="http://schema.org/">
/// <rdf:Description rdf:about="http://example.com/foo">
@ -289,7 +289,7 @@ pub struct FromTokioAsyncReadRdfXmlReader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadRdfXmlReader<R> {
/// Reads the next triple or returns `None` if the file is finished.
pub async fn next(&mut self) -> Option<Result<Triple, ParseError>> {
pub async fn next(&mut self) -> Option<Result<Triple, RdfXmlParseError>> {
loop {
if let Some(triple) = self.results.pop() {
return Some(Ok(triple));
@ -307,7 +307,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadRdfXmlReader<R> {
self.reader.reader.buffer_position()
}
async fn parse_step(&mut self) -> Result<(), ParseError> {
async fn parse_step(&mut self) -> Result<(), RdfXmlParseError> {
self.reader_buffer.clear();
let event = self
.reader
@ -440,20 +440,21 @@ impl<R> RdfXmlReader<R> {
&mut self,
event: Event<'_>,
results: &mut Vec<Triple>,
) -> Result<(), ParseError> {
) -> Result<(), RdfXmlParseError> {
match event {
Event::Start(event) => self.parse_start_event(&event, results),
Event::End(event) => self.parse_end_event(&event, results),
Event::Empty(_) => {
Err(SyntaxError::msg("The expand_empty_elements option must be enabled").into())
}
Event::Empty(_) => Err(RdfXmlSyntaxError::msg(
"The expand_empty_elements option must be enabled",
)
.into()),
Event::Text(event) => self.parse_text_event(&event),
Event::CData(event) => self.parse_text_event(&event.escape()?),
Event::Comment(_) | Event::PI(_) => Ok(()),
Event::Decl(decl) => {
if let Some(encoding) = decl.encoding() {
if !is_utf8(&encoding?) {
return Err(SyntaxError::msg(
return Err(RdfXmlSyntaxError::msg(
"Only UTF-8 is supported by the RDF/XML parser",
)
.into());
@ -469,7 +470,7 @@ impl<R> RdfXmlReader<R> {
}
}
fn parse_doctype(&mut self, dt: &BytesText<'_>) -> Result<(), ParseError> {
fn parse_doctype(&mut self, dt: &BytesText<'_>) -> Result<(), RdfXmlParseError> {
// we extract entities
for input in self
.reader
@ -481,20 +482,20 @@ impl<R> RdfXmlReader<R> {
if let Some(input) = input.strip_prefix("!ENTITY") {
let input = input.trim_start().strip_prefix('%').unwrap_or(input);
let (entity_name, input) = input.trim_start().split_once(|c: char| c.is_ascii_whitespace()).ok_or_else(|| {
SyntaxError::msg(
RdfXmlSyntaxError::msg(
"<!ENTITY declarations should contain both an entity name and an entity value",
)
})?;
let input = input.trim_start().strip_prefix('\"').ok_or_else(|| {
SyntaxError::msg("<!ENTITY values should be enclosed in double quotes")
RdfXmlSyntaxError::msg("<!ENTITY values should be enclosed in double quotes")
})?;
let (entity_value, input) = input.split_once('"').ok_or_else(|| {
SyntaxError::msg(
RdfXmlSyntaxError::msg(
"<!ENTITY declarations values should be enclosed in double quotes",
)
})?;
input.trim_start().strip_prefix('>').ok_or_else(|| {
SyntaxError::msg("<!ENTITY declarations values should end with >")
RdfXmlSyntaxError::msg("<!ENTITY declarations values should end with >")
})?;
// Resolves custom entities within the current entity definition.
@ -511,7 +512,7 @@ impl<R> RdfXmlReader<R> {
&mut self,
event: &BytesStart<'_>,
results: &mut Vec<Triple>,
) -> Result<(), ParseError> {
) -> Result<(), RdfXmlParseError> {
#[derive(PartialEq, Eq)]
enum RdfXmlParseType {
Default,
@ -576,7 +577,10 @@ impl<R> RdfXmlReader<R> {
} else {
LanguageTag::parse(tag.to_ascii_lowercase())
.map_err(|error| {
SyntaxError(SyntaxErrorKind::InvalidLanguageTag { tag, error })
RdfXmlSyntaxError(SyntaxErrorKind::InvalidLanguageTag {
tag,
error,
})
})?
.into_inner()
});
@ -588,7 +592,9 @@ impl<R> RdfXmlReader<R> {
} else {
Iri::parse(iri.clone())
}
.map_err(|error| SyntaxError(SyntaxErrorKind::InvalidIri { iri, error }))?,
.map_err(|error| {
RdfXmlSyntaxError(SyntaxErrorKind::InvalidIri { iri, error })
})?,
)
} else {
// We ignore other xml attributes
@ -598,16 +604,17 @@ impl<R> RdfXmlReader<R> {
if *attribute_url == *RDF_ID {
let mut id = self.convert_attribute(&attribute)?;
if !is_nc_name(&id) {
return Err(
SyntaxError::msg(format!("{id} is not a valid rdf:ID value")).into(),
);
return Err(RdfXmlSyntaxError::msg(format!(
"{id} is not a valid rdf:ID value"
))
.into());
}
id.insert(0, '#');
id_attr = Some(id);
} else if *attribute_url == *RDF_BAG_ID {
let bag_id = self.convert_attribute(&attribute)?;
if !is_nc_name(&bag_id) {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"{bag_id} is not a valid rdf:bagID value"
))
.into());
@ -615,7 +622,7 @@ impl<R> RdfXmlReader<R> {
} else if *attribute_url == *RDF_NODE_ID {
let id = self.convert_attribute(&attribute)?;
if !is_nc_name(&id) {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"{id} is not a valid rdf:nodeID value"
))
.into());
@ -637,7 +644,7 @@ impl<R> RdfXmlReader<R> {
} else if attribute_url == rdf::TYPE.as_str() {
type_attr = Some(attribute);
} else if RESERVED_RDF_ATTRIBUTES.contains(&&*attribute_url) {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"{attribute_url} is not a valid attribute"
))
.into());
@ -655,7 +662,7 @@ impl<R> RdfXmlReader<R> {
Some(iri) => {
let iri = self.resolve_iri(&base_iri, iri)?;
if self.known_rdf_id.contains(iri.as_str()) {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"{iri} has already been used as rdf:ID value"
))
.into());
@ -694,13 +701,14 @@ impl<R> RdfXmlReader<R> {
},
Some(RdfXmlState::ParseTypeLiteralPropertyElt { .. }) => {
return Err(
SyntaxError::msg("ParseTypeLiteralPropertyElt production children should never be considered as a RDF/XML content").into()
RdfXmlSyntaxError::msg("ParseTypeLiteralPropertyElt production children should never be considered as a RDF/XML content").into()
);
}
None => {
return Err(
SyntaxError::msg("No state in the stack: the XML is not balanced").into(),
);
return Err(RdfXmlSyntaxError::msg(
"No state in the stack: the XML is not balanced",
)
.into());
}
};
@ -709,7 +717,7 @@ impl<R> RdfXmlReader<R> {
if *tag_name == *RDF_RDF {
RdfXmlState::Rdf { base_iri, language }
} else if RESERVED_RDF_ELEMENTS.contains(&&*tag_name) {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"Invalid node element tag name: {tag_name}"
))
.into());
@ -729,7 +737,7 @@ impl<R> RdfXmlReader<R> {
}
RdfXmlNextProduction::NodeElt => {
if RESERVED_RDF_ELEMENTS.contains(&&*tag_name) {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"Invalid property element tag name: {tag_name}"
))
.into());
@ -750,7 +758,7 @@ impl<R> RdfXmlReader<R> {
let iri = if *tag_name == *RDF_LI {
let Some(RdfXmlState::NodeElt { li_counter, .. }) = self.state.last_mut()
else {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"Invalid property element tag name: {tag_name}"
))
.into());
@ -762,7 +770,7 @@ impl<R> RdfXmlReader<R> {
} else if RESERVED_RDF_ELEMENTS.contains(&&*tag_name)
|| *tag_name == *RDF_DESCRIPTION
{
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"Invalid property element tag name: {tag_name}"
))
.into());
@ -780,7 +788,7 @@ impl<R> RdfXmlReader<R> {
(Some(resource_attr), None) => Subject::from(resource_attr),
(None, Some(node_id_attr)) => node_id_attr.into(),
(None, None) => BlankNode::default().into(),
(Some(_), Some(_)) => return Err(SyntaxError::msg("Not both rdf:resource and rdf:nodeID could be set at the same time").into())
(Some(_), Some(_)) => return Err(RdfXmlSyntaxError::msg("Not both rdf:resource and rdf:nodeID could be set at the same time").into())
};
Self::emit_property_attrs(&object, property_attrs, &language, results);
if let Some(type_attr) = type_attr {
@ -847,7 +855,7 @@ impl<R> RdfXmlReader<R> {
&mut self,
event: &BytesEnd<'_>,
results: &mut Vec<Triple>,
) -> Result<(), ParseError> {
) -> Result<(), RdfXmlParseError> {
// Literal case
if self.in_literal_depth > 0 {
if let Some(RdfXmlState::ParseTypeLiteralPropertyElt { writer, .. }) =
@ -867,7 +875,7 @@ impl<R> RdfXmlReader<R> {
Ok(())
}
fn parse_text_event(&mut self, event: &BytesText<'_>) -> Result<(), ParseError> {
fn parse_text_event(&mut self, event: &BytesText<'_>) -> Result<(), RdfXmlParseError> {
let text = event.unescape_with(|e| self.resolve_entity(e))?.to_string();
match self.state.last_mut() {
Some(RdfXmlState::PropertyElt { object, .. }) => {
@ -884,18 +892,18 @@ impl<R> RdfXmlReader<R> {
if event.iter().copied().all(is_whitespace) {
Ok(())
} else {
Err(SyntaxError::msg(format!("Unexpected text event: '{text}'")).into())
Err(RdfXmlSyntaxError::msg(format!("Unexpected text event: '{text}'")).into())
}
}
}
}
fn resolve_tag_name(&self, qname: QName<'_>) -> Result<String, ParseError> {
fn resolve_tag_name(&self, qname: QName<'_>) -> Result<String, RdfXmlParseError> {
let (namespace, local_name) = self.reader.resolve_element(qname);
self.resolve_ns_name(namespace, local_name)
}
fn resolve_attribute_name(&self, qname: QName<'_>) -> Result<String, ParseError> {
fn resolve_attribute_name(&self, qname: QName<'_>) -> Result<String, RdfXmlParseError> {
let (namespace, local_name) = self.reader.resolve_attribute(qname);
self.resolve_ns_name(namespace, local_name)
}
@ -904,7 +912,7 @@ impl<R> RdfXmlReader<R> {
&self,
namespace: ResolveResult<'_>,
local_name: LocalName<'_>,
) -> Result<String, ParseError> {
) -> Result<String, RdfXmlParseError> {
match namespace {
ResolveResult::Bound(ns) => {
let mut value = Vec::with_capacity(ns.as_ref().len() + local_name.as_ref().len());
@ -917,9 +925,9 @@ impl<R> RdfXmlReader<R> {
.to_string())
}
ResolveResult::Unbound => {
Err(SyntaxError::msg("XML namespaces are required in RDF/XML").into())
Err(RdfXmlSyntaxError::msg("XML namespaces are required in RDF/XML").into())
}
ResolveResult::Unknown(v) => Err(SyntaxError::msg(format!(
ResolveResult::Unknown(v) => Err(RdfXmlSyntaxError::msg(format!(
"Unknown prefix {}:",
self.reader.decoder().decode(&v)?
))
@ -938,24 +946,24 @@ impl<R> RdfXmlReader<R> {
type_attr: Option<NamedNode>,
property_attrs: Vec<(NamedNode, String)>,
results: &mut Vec<Triple>,
) -> Result<RdfXmlState, SyntaxError> {
) -> Result<RdfXmlState, RdfXmlSyntaxError> {
let subject = match (id_attr, node_id_attr, about_attr) {
(Some(id_attr), None, None) => Subject::from(id_attr),
(None, Some(node_id_attr), None) => node_id_attr.into(),
(None, None, Some(about_attr)) => about_attr.into(),
(None, None, None) => BlankNode::default().into(),
(Some(_), Some(_), _) => {
return Err(SyntaxError::msg(
return Err(RdfXmlSyntaxError::msg(
"Not both rdf:ID and rdf:nodeID could be set at the same time",
))
}
(_, Some(_), Some(_)) => {
return Err(SyntaxError::msg(
return Err(RdfXmlSyntaxError::msg(
"Not both rdf:nodeID and rdf:resource could be set at the same time",
))
}
(Some(_), _, Some(_)) => {
return Err(SyntaxError::msg(
return Err(RdfXmlSyntaxError::msg(
"Not both rdf:ID and rdf:resource could be set at the same time",
))
}
@ -1004,7 +1012,7 @@ impl<R> RdfXmlReader<R> {
&mut self,
state: RdfXmlState,
results: &mut Vec<Triple>,
) -> Result<(), SyntaxError> {
) -> Result<(), RdfXmlSyntaxError> {
match state {
RdfXmlState::PropertyElt {
iri,
@ -1059,7 +1067,7 @@ impl<R> RdfXmlReader<R> {
if emit {
let object = writer.into_inner();
if object.is_empty() {
return Err(SyntaxError::msg(format!(
return Err(RdfXmlSyntaxError::msg(format!(
"No value found for rdf:XMLLiteral value of property {iri}"
)));
}
@ -1068,7 +1076,9 @@ impl<R> RdfXmlReader<R> {
iri,
Literal::new_typed_literal(
str::from_utf8(&object).map_err(|_| {
SyntaxError::msg("The XML literal is not in valid UTF-8".to_owned())
RdfXmlSyntaxError::msg(
"The XML literal is not in valid UTF-8".to_owned(),
)
})?,
rdf::XML_LITERAL,
),
@ -1141,7 +1151,7 @@ impl<R> RdfXmlReader<R> {
}
}
fn convert_attribute(&self, attribute: &Attribute<'_>) -> Result<String, ParseError> {
fn convert_attribute(&self, attribute: &Attribute<'_>) -> Result<String, RdfXmlParseError> {
Ok(attribute
.decode_and_unescape_value_with(&self.reader, |e| self.resolve_entity(e))?
.into_owned())
@ -1151,7 +1161,7 @@ impl<R> RdfXmlReader<R> {
&self,
base_iri: &Option<Iri<String>>,
attribute: &Attribute<'_>,
) -> Result<NamedNode, ParseError> {
) -> Result<NamedNode, RdfXmlParseError> {
Ok(self.resolve_iri(base_iri, self.convert_attribute(attribute)?)?)
}
@ -1159,7 +1169,7 @@ impl<R> RdfXmlReader<R> {
&self,
base_iri: &Option<Iri<String>>,
relative_iri: String,
) -> Result<NamedNode, SyntaxError> {
) -> Result<NamedNode, RdfXmlSyntaxError> {
if let Some(base_iri) = base_iri {
Ok(NamedNode::new_unchecked(
if self.unchecked {
@ -1168,7 +1178,7 @@ impl<R> RdfXmlReader<R> {
base_iri.resolve(&relative_iri)
}
.map_err(|error| {
SyntaxError(SyntaxErrorKind::InvalidIri {
RdfXmlSyntaxError(SyntaxErrorKind::InvalidIri {
iri: relative_iri,
error,
})
@ -1180,13 +1190,13 @@ impl<R> RdfXmlReader<R> {
}
}
fn parse_iri(&self, relative_iri: String) -> Result<NamedNode, SyntaxError> {
fn parse_iri(&self, relative_iri: String) -> Result<NamedNode, RdfXmlSyntaxError> {
Ok(NamedNode::new_unchecked(if self.unchecked {
relative_iri
} else {
Iri::parse(relative_iri.clone())
.map_err(|error| {
SyntaxError(SyntaxErrorKind::InvalidIri {
RdfXmlSyntaxError(SyntaxErrorKind::InvalidIri {
iri: relative_iri,
error,
})

@ -1,6 +1,6 @@
[package]
name = "oxttl"
version = "0.1.0-alpha.2"
version = "0.1.0-alpha.3-dev"
authors.workspace = true
license.workspace = true
readme = "README.md"

@ -17,7 +17,7 @@ pub mod turtle;
pub use crate::n3::N3Parser;
pub use crate::nquads::{NQuadsParser, NQuadsSerializer};
pub use crate::ntriples::{NTriplesParser, NTriplesSerializer};
pub use crate::toolkit::{ParseError, SyntaxError, TextPosition};
pub use crate::toolkit::{TextPosition, TurtleParseError, TurtleSyntaxError};
pub use crate::trig::{TriGParser, TriGSerializer};
pub use crate::turtle::{TurtleParser, TurtleSerializer};

@ -4,9 +4,9 @@ use crate::lexer::{resolve_local_name, N3Lexer, N3LexerMode, N3LexerOptions, N3T
#[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{
FromReadIterator, Lexer, Parser, RuleRecognizer, RuleRecognizerError, SyntaxError,
FromReadIterator, Lexer, Parser, RuleRecognizer, RuleRecognizerError, TurtleSyntaxError,
};
use crate::{ParseError, MAX_BUFFER_SIZE, MIN_BUFFER_SIZE};
use crate::{TurtleParseError, MAX_BUFFER_SIZE, MIN_BUFFER_SIZE};
use oxiri::{Iri, IriParseError};
use oxrdf::vocab::{rdf, xsd};
#[cfg(feature = "rdf-star")]
@ -291,7 +291,7 @@ impl N3Parser {
/// use oxttl::n3::{N3Parser, N3Term};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -461,7 +461,7 @@ impl<R: Read> FromReadN3Reader<R> {
}
impl<R: Read> Iterator for FromReadN3Reader<R> {
type Item = Result<N3Quad, ParseError>;
type Item = Result<N3Quad, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
@ -477,7 +477,7 @@ impl<R: Read> Iterator for FromReadN3Reader<R> {
/// use oxttl::n3::{N3Parser, N3Term};
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -508,7 +508,7 @@ pub struct FromTokioAsyncReadN3Reader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadN3Reader<R> {
/// Reads the next triple or returns `None` if the file is finished.
pub async fn next(&mut self) -> Option<Result<N3Quad, ParseError>> {
pub async fn next(&mut self) -> Option<Result<N3Quad, TurtleParseError>> {
Some(self.inner.next().await?.map(Into::into))
}
@ -522,7 +522,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadN3Reader<R> {
/// use oxttl::N3Parser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -551,7 +551,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadN3Reader<R> {
/// use oxttl::N3Parser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -641,7 +641,7 @@ impl LowLevelN3Reader {
///
/// Returns [`None`] if the parsing is finished or more data is required.
/// If it is the case more data should be fed using [`extend_from_slice`](Self::extend_from_slice).
pub fn read_next(&mut self) -> Option<Result<N3Quad, SyntaxError>> {
pub fn read_next(&mut self) -> Option<Result<N3Quad, TurtleSyntaxError>> {
self.parser.read_next()
}

@ -4,7 +4,7 @@
use crate::line_formats::NQuadsRecognizer;
#[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError};
use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
use oxrdf::{Quad, QuadRef};
use std::io::{self, Read, Write};
#[cfg(feature = "async-tokio")]
@ -106,7 +106,7 @@ impl NQuadsParser {
/// use oxttl::NQuadsParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"<http://example.com/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
/// <http://example.com/foo> <http://schema.org/name> "Foo" .
/// <http://example.com/bar> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
@ -213,7 +213,7 @@ pub struct FromReadNQuadsReader<R: Read> {
}
impl<R: Read> Iterator for FromReadNQuadsReader<R> {
type Item = Result<Quad, ParseError>;
type Item = Result<Quad, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
@ -228,7 +228,7 @@ impl<R: Read> Iterator for FromReadNQuadsReader<R> {
/// use oxttl::NQuadsParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"<http://example.com/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
/// <http://example.com/foo> <http://schema.org/name> "Foo" .
/// <http://example.com/bar> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
@ -256,7 +256,7 @@ pub struct FromTokioAsyncReadNQuadsReader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadNQuadsReader<R> {
/// Reads the next triple or returns `None` if the file is finished.
pub async fn next(&mut self) -> Option<Result<Quad, ParseError>> {
pub async fn next(&mut self) -> Option<Result<Quad, TurtleParseError>> {
Some(self.inner.next().await?.map(Into::into))
}
}
@ -323,7 +323,7 @@ impl LowLevelNQuadsReader {
///
/// Returns [`None`] if the parsing is finished or more data is required.
/// If it is the case more data should be fed using [`extend_from_slice`](Self::extend_from_slice).
pub fn read_next(&mut self) -> Option<Result<Quad, SyntaxError>> {
pub fn read_next(&mut self) -> Option<Result<Quad, TurtleSyntaxError>> {
self.parser.read_next()
}
}

@ -4,7 +4,7 @@
use crate::line_formats::NQuadsRecognizer;
#[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError};
use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
use oxrdf::{Triple, TripleRef};
use std::io::{self, Read, Write};
#[cfg(feature = "async-tokio")]
@ -106,7 +106,7 @@ impl NTriplesParser {
/// use oxttl::NTriplesParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"<http://example.com/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
/// <http://example.com/foo> <http://schema.org/name> "Foo" .
/// <http://example.com/bar> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
@ -213,7 +213,7 @@ pub struct FromReadNTriplesReader<R: Read> {
}
impl<R: Read> Iterator for FromReadNTriplesReader<R> {
type Item = Result<Triple, ParseError>;
type Item = Result<Triple, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.map(Into::into))
@ -228,7 +228,7 @@ impl<R: Read> Iterator for FromReadNTriplesReader<R> {
/// use oxttl::NTriplesParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"<http://example.com/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
/// <http://example.com/foo> <http://schema.org/name> "Foo" .
/// <http://example.com/bar> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://schema.org/Person> .
@ -256,7 +256,7 @@ pub struct FromTokioAsyncReadNTriplesReader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadNTriplesReader<R> {
/// Reads the next triple or returns `None` if the file is finished.
pub async fn next(&mut self) -> Option<Result<Triple, ParseError>> {
pub async fn next(&mut self) -> Option<Result<Triple, TurtleParseError>> {
Some(self.inner.next().await?.map(Into::into))
}
}
@ -323,7 +323,7 @@ impl LowLevelNTriplesReader {
///
/// Returns [`None`] if the parsing is finished or more data is required.
/// If it is the case more data should be fed using [`extend_from_slice`](Self::extend_from_slice).
pub fn read_next(&mut self) -> Option<Result<Triple, SyntaxError>> {
pub fn read_next(&mut self) -> Option<Result<Triple, TurtleSyntaxError>> {
Some(self.parser.read_next()?.map(Into::into))
}
}

@ -13,12 +13,12 @@ pub struct TextPosition {
///
/// It is composed of a message and a byte range in the input.
#[derive(Debug, thiserror::Error)]
pub struct SyntaxError {
pub struct TurtleSyntaxError {
pub(super) location: Range<TextPosition>,
pub(super) message: String,
}
impl SyntaxError {
impl TurtleSyntaxError {
/// The location of the error inside of the file.
#[inline]
pub fn location(&self) -> Range<TextPosition> {
@ -32,7 +32,7 @@ impl SyntaxError {
}
}
impl fmt::Display for SyntaxError {
impl fmt::Display for TurtleSyntaxError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.location.start.offset + 1 >= self.location.end.offset {
@ -66,32 +66,32 @@ impl fmt::Display for SyntaxError {
}
}
impl From<SyntaxError> for io::Error {
impl From<TurtleSyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
fn from(error: TurtleSyntaxError) -> Self {
Self::new(io::ErrorKind::InvalidData, error)
}
}
/// A parsing error.
///
/// It is the union of [`SyntaxError`] and [`io::Error`].
/// It is the union of [`TurtleSyntaxError`] and [`io::Error`].
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
pub enum TurtleParseError {
/// I/O error during parsing (file not found...).
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
#[error(transparent)]
Syntax(#[from] SyntaxError),
Syntax(#[from] TurtleSyntaxError),
}
impl From<ParseError> for io::Error {
impl From<TurtleParseError> for io::Error {
#[inline]
fn from(error: ParseError) -> Self {
fn from(error: TurtleParseError) -> Self {
match error {
ParseError::Syntax(e) => e.into(),
ParseError::Io(e) => e,
TurtleParseError::Syntax(e) => e.into(),
TurtleParseError::Io(e) => e,
}
}
}

@ -1,4 +1,4 @@
use crate::toolkit::error::{SyntaxError, TextPosition};
use crate::toolkit::error::{TextPosition, TurtleSyntaxError};
use memchr::{memchr2, memchr2_iter};
use std::borrow::Cow;
use std::cmp::min;
@ -163,7 +163,10 @@ impl<R: TokenRecognizer> Lexer<R> {
}
#[allow(clippy::unwrap_in_result)]
pub fn read_next(&mut self, options: &R::Options) -> Option<Result<R::Token<'_>, SyntaxError>> {
pub fn read_next(
&mut self,
options: &R::Options,
) -> Option<Result<R::Token<'_>, TurtleSyntaxError>> {
self.skip_whitespaces_and_comments()?;
self.previous_position = self.position;
let Some((consumed, result)) = self.parser.recognize_next_token(
@ -194,7 +197,7 @@ impl<R: TokenRecognizer> Lexer<R> {
),
offset: self.position.global_offset,
};
let error = SyntaxError {
let error = TurtleSyntaxError {
location: new_position..new_position,
message: "Unexpected end of file".into(),
};
@ -224,7 +227,7 @@ impl<R: TokenRecognizer> Lexer<R> {
self.position.buffer_offset += consumed;
self.position.global_offset += u64::try_from(consumed).unwrap();
self.position.global_line += new_line_jumps;
Some(result.map_err(|e| SyntaxError {
Some(result.map_err(|e| TurtleSyntaxError {
location: self.location_from_buffer_offset_range(e.location),
message: e.message,
}))

@ -6,7 +6,7 @@ mod error;
mod lexer;
mod parser;
pub use self::error::{ParseError, SyntaxError, TextPosition};
pub use self::error::{TextPosition, TurtleParseError, TurtleSyntaxError};
pub use self::lexer::{Lexer, TokenRecognizer, TokenRecognizerError};
#[cfg(feature = "async-tokio")]
pub use self::parser::FromTokioAsyncReadIterator;

@ -1,4 +1,4 @@
use crate::toolkit::error::{ParseError, SyntaxError};
use crate::toolkit::error::{TurtleParseError, TurtleSyntaxError};
use crate::toolkit::lexer::{Lexer, TokenRecognizer};
use std::io::Read;
#[cfg(feature = "async-tokio")]
@ -77,10 +77,10 @@ impl<RR: RuleRecognizer> Parser<RR> {
self.state.is_none() && self.results.is_empty() && self.errors.is_empty()
}
pub fn read_next(&mut self) -> Option<Result<RR::Output, SyntaxError>> {
pub fn read_next(&mut self) -> Option<Result<RR::Output, TurtleSyntaxError>> {
loop {
if let Some(error) = self.errors.pop() {
return Some(Err(SyntaxError {
return Some(Err(TurtleSyntaxError {
location: self.lexer.last_token_location(),
message: error
.message
@ -141,12 +141,12 @@ pub struct FromReadIterator<R: Read, RR: RuleRecognizer> {
}
impl<R: Read, RR: RuleRecognizer> Iterator for FromReadIterator<R, RR> {
type Item = Result<RR::Output, ParseError>;
type Item = Result<RR::Output, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> {
while !self.parser.is_end() {
if let Some(result) = self.parser.read_next() {
return Some(result.map_err(ParseError::Syntax));
return Some(result.map_err(TurtleParseError::Syntax));
}
if let Err(e) = self.parser.lexer.extend_from_read(&mut self.read) {
return Some(Err(e.into()));
@ -164,10 +164,10 @@ pub struct FromTokioAsyncReadIterator<R: AsyncRead + Unpin, RR: RuleRecognizer>
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin, RR: RuleRecognizer> FromTokioAsyncReadIterator<R, RR> {
pub async fn next(&mut self) -> Option<Result<RR::Output, ParseError>> {
pub async fn next(&mut self) -> Option<Result<RR::Output, TurtleParseError>> {
while !self.parser.is_end() {
if let Some(result) = self.parser.read_next() {
return Some(result.map_err(ParseError::Syntax));
return Some(result.map_err(TurtleParseError::Syntax));
}
if let Err(e) = self
.parser

@ -5,7 +5,7 @@ use crate::lexer::N3Lexer;
use crate::terse::TriGRecognizer;
#[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError};
use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
use oxiri::{Iri, IriParseError};
use oxrdf::vocab::{rdf, xsd};
use oxrdf::{
@ -140,7 +140,7 @@ impl TriGParser {
/// use oxttl::TriGParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -314,7 +314,7 @@ impl<R: Read> FromReadTriGReader<R> {
}
impl<R: Read> Iterator for FromReadTriGReader<R> {
type Item = Result<Quad, ParseError>;
type Item = Result<Quad, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
@ -330,7 +330,7 @@ impl<R: Read> Iterator for FromReadTriGReader<R> {
/// use oxttl::TriGParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -360,7 +360,7 @@ pub struct FromTokioAsyncReadTriGReader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadTriGReader<R> {
/// Reads the next triple or returns `None` if the file is finished.
pub async fn next(&mut self) -> Option<Result<Quad, ParseError>> {
pub async fn next(&mut self) -> Option<Result<Quad, TurtleParseError>> {
Some(self.inner.next().await?.map(Into::into))
}
@ -374,7 +374,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTriGReader<R> {
/// use oxttl::TriGParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -403,7 +403,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTriGReader<R> {
/// use oxttl::TriGParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -492,7 +492,7 @@ impl LowLevelTriGReader {
///
/// Returns [`None`] if the parsing is finished or more data is required.
/// If it is the case more data should be fed using [`extend_from_slice`](Self::extend_from_slice).
pub fn read_next(&mut self) -> Option<Result<Quad, SyntaxError>> {
pub fn read_next(&mut self) -> Option<Result<Quad, TurtleSyntaxError>> {
self.parser.read_next()
}

@ -4,7 +4,7 @@
use crate::terse::TriGRecognizer;
#[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError};
use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
#[cfg(feature = "async-tokio")]
use crate::trig::ToTokioAsyncWriteTriGWriter;
use crate::trig::{LowLevelTriGWriter, ToWriteTriGWriter, TriGSerializer};
@ -138,7 +138,7 @@ impl TurtleParser {
/// use oxttl::TurtleParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -312,7 +312,7 @@ impl<R: Read> FromReadTurtleReader<R> {
}
impl<R: Read> Iterator for FromReadTurtleReader<R> {
type Item = Result<Triple, ParseError>;
type Item = Result<Triple, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.map(Into::into))
@ -328,7 +328,7 @@ impl<R: Read> Iterator for FromReadTurtleReader<R> {
/// use oxttl::TurtleParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -358,7 +358,7 @@ pub struct FromTokioAsyncReadTurtleReader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// Reads the next triple or returns `None` if the file is finished.
pub async fn next(&mut self) -> Option<Result<Triple, ParseError>> {
pub async fn next(&mut self) -> Option<Result<Triple, TurtleParseError>> {
Some(self.inner.next().await?.map(Into::into))
}
@ -372,7 +372,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// use oxttl::TurtleParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -401,7 +401,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// use oxttl::TurtleParser;
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> {
/// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ;
@ -490,7 +490,7 @@ impl LowLevelTurtleReader {
///
/// Returns [`None`] if the parsing is finished or more data is required.
/// If it is the case more data should be fed using [`extend_from_slice`](Self::extend_from_slice).
pub fn read_next(&mut self) -> Option<Result<Triple, SyntaxError>> {
pub fn read_next(&mut self) -> Option<Result<Triple, TurtleSyntaxError>> {
Some(self.parser.read_next()?.map(Into::into))
}

@ -1,6 +1,8 @@
//! 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, SyntaxErrorKind, TextPosition};
use crate::error::{
QueryResultsParseError, QueryResultsSyntaxError, SyntaxErrorKind, TextPosition,
};
use memchr::memchr;
use oxrdf::vocab::xsd;
use oxrdf::*;
@ -432,7 +434,7 @@ pub enum TsvQueryResultsReader<R: Read> {
}
impl<R: Read> TsvQueryResultsReader<R> {
pub fn read(mut read: R) -> Result<Self, ParseError> {
pub fn read(mut read: R) -> Result<Self, QueryResultsParseError> {
let mut reader = LineReader::new();
let mut buffer = Vec::new();
@ -451,13 +453,13 @@ impl<R: Read> TsvQueryResultsReader<R> {
for v in line.split('\t') {
let v = v.trim();
if v.is_empty() {
return Err(SyntaxError::msg("Empty column on the first row. The first row should be a list of variables like ?foo or $bar").into());
return Err(QueryResultsSyntaxError::msg("Empty column on the first row. The first row should be a list of variables like ?foo or $bar").into());
}
let variable = Variable::from_str(v).map_err(|e| {
SyntaxError::msg(format!("Invalid variable declaration '{v}': {e}"))
QueryResultsSyntaxError::msg(format!("Invalid variable declaration '{v}': {e}"))
})?;
if variables.contains(&variable) {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"The variable {variable} is declared twice"
))
.into());
@ -487,7 +489,7 @@ pub struct TsvSolutionsReader<R: Read> {
impl<R: Read> TsvSolutionsReader<R> {
#[allow(clippy::unwrap_in_result)]
pub fn read_next(&mut self) -> Result<Option<Vec<Option<Term>>>, ParseError> {
pub fn read_next(&mut self) -> Result<Option<Vec<Option<Term>>>, QueryResultsParseError> {
let line = self.reader.next_line(&mut self.buffer, &mut self.read)?;
if line.is_empty() {
return Ok(None); // EOF
@ -508,35 +510,33 @@ impl<R: Read> TsvSolutionsReader<R> {
.sum::<usize>();
let start_position_bytes =
line.split('\t').take(i).map(|c| c.len() + 1).sum::<usize>();
SyntaxError {
inner: SyntaxErrorKind::Term {
error: e,
term: v.into(),
location: TextPosition {
line: self.reader.line_count - 1,
column: start_position_char.try_into().unwrap(),
offset: self.reader.last_line_start
+ u64::try_from(start_position_bytes).unwrap(),
}..TextPosition {
line: self.reader.line_count - 1,
column: (start_position_char + v.chars().count())
.try_into()
.unwrap(),
offset: self.reader.last_line_start
+ u64::try_from(start_position_bytes + v.len()).unwrap(),
},
QueryResultsSyntaxError(SyntaxErrorKind::Term {
error: e,
term: v.into(),
location: TextPosition {
line: self.reader.line_count - 1,
column: start_position_char.try_into().unwrap(),
offset: self.reader.last_line_start
+ u64::try_from(start_position_bytes).unwrap(),
}..TextPosition {
line: self.reader.line_count - 1,
column: (start_position_char + v.chars().count())
.try_into()
.unwrap(),
offset: self.reader.last_line_start
+ u64::try_from(start_position_bytes + v.len()).unwrap(),
},
}
})
})?))
}
})
.collect::<Result<Vec<_>, ParseError>>()?;
.collect::<Result<Vec<_>, QueryResultsParseError>>()?;
if elements.len() == self.column_len {
Ok(Some(elements))
} else if self.column_len == 0 && elements == [None] {
Ok(Some(Vec::new())) // Zero columns case
} else {
Err(SyntaxError::located_message(
Err(QueryResultsSyntaxError::located_message(
format!(
"This TSV files has {} columns but we found a row on line {} with {} columns: {}",
self.column_len,

@ -5,44 +5,44 @@ use std::sync::Arc;
/// Error returned during SPARQL result formats format parsing.
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
pub enum QueryResultsParseError {
/// I/O error during parsing (file not found...).
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
#[error(transparent)]
Syntax(#[from] SyntaxError),
Syntax(#[from] QueryResultsSyntaxError),
}
impl From<ParseError> for io::Error {
impl From<QueryResultsParseError> for io::Error {
#[inline]
fn from(error: ParseError) -> Self {
fn from(error: QueryResultsParseError) -> Self {
match error {
ParseError::Io(error) => error,
ParseError::Syntax(error) => error.into(),
QueryResultsParseError::Io(error) => error,
QueryResultsParseError::Syntax(error) => error.into(),
}
}
}
impl From<json_event_parser::ParseError> for ParseError {
impl From<json_event_parser::ParseError> for QueryResultsParseError {
fn from(error: json_event_parser::ParseError) -> Self {
match error {
json_event_parser::ParseError::Syntax(error) => SyntaxError::from(error).into(),
json_event_parser::ParseError::Syntax(error) => {
QueryResultsSyntaxError::from(error).into()
}
json_event_parser::ParseError::Io(error) => error.into(),
}
}
}
impl From<quick_xml::Error> for ParseError {
impl From<quick_xml::Error> for QueryResultsParseError {
#[inline]
fn from(error: quick_xml::Error) -> Self {
match error {
quick_xml::Error::Io(error) => {
Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e)))
}
_ => Self::Syntax(SyntaxError {
inner: SyntaxErrorKind::Xml(error),
}),
_ => Self::Syntax(QueryResultsSyntaxError(SyntaxErrorKind::Xml(error))),
}
}
}
@ -50,10 +50,7 @@ impl From<quick_xml::Error> for ParseError {
/// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct SyntaxError {
#[from]
pub(crate) inner: SyntaxErrorKind,
}
pub struct QueryResultsSyntaxError(#[from] pub(crate) SyntaxErrorKind);
#[derive(Debug, thiserror::Error)]
pub(crate) enum SyntaxErrorKind {
@ -75,33 +72,29 @@ pub(crate) enum SyntaxErrorKind {
},
}
impl SyntaxError {
impl QueryResultsSyntaxError {
/// Builds an error from a printable error message.
#[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self {
Self {
inner: SyntaxErrorKind::Msg {
msg: msg.into(),
location: None,
},
}
Self(SyntaxErrorKind::Msg {
msg: msg.into(),
location: None,
})
}
/// Builds an error from a printable error message and a location
#[inline]
pub(crate) fn located_message(msg: impl Into<String>, location: Range<TextPosition>) -> Self {
Self {
inner: SyntaxErrorKind::Msg {
msg: msg.into(),
location: Some(location),
},
}
Self(SyntaxErrorKind::Msg {
msg: msg.into(),
location: Some(location),
})
}
/// The location of the error inside of the file.
#[inline]
pub fn location(&self) -> Option<Range<TextPosition>> {
match &self.inner {
match &self.0 {
SyntaxErrorKind::Json(e) => {
let location = e.location();
Some(
@ -123,10 +116,10 @@ impl SyntaxError {
}
}
impl From<SyntaxError> for io::Error {
impl From<QueryResultsSyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
match error.inner {
fn from(error: QueryResultsSyntaxError) -> Self {
match error.0 {
SyntaxErrorKind::Json(error) => Self::new(io::ErrorKind::InvalidData, error),
SyntaxErrorKind::Xml(error) => match error {
quick_xml::Error::Io(error) => {
@ -143,11 +136,9 @@ impl From<SyntaxError> for io::Error {
}
}
impl From<json_event_parser::SyntaxError> for SyntaxError {
impl From<json_event_parser::SyntaxError> for QueryResultsSyntaxError {
fn from(error: json_event_parser::SyntaxError) -> Self {
Self {
inner: SyntaxErrorKind::Json(error),
}
Self(SyntaxErrorKind::Json(error))
}
}

@ -1,6 +1,6 @@
//! Implementation of [SPARQL Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/)
use crate::error::{ParseError, SyntaxError};
use crate::error::{QueryResultsParseError, QueryResultsSyntaxError};
#[cfg(feature = "async-tokio")]
use json_event_parser::ToTokioAsyncWriteJsonWriter;
use json_event_parser::{FromReadJsonReader, JsonEvent, ToWriteJsonWriter};
@ -233,14 +233,16 @@ pub enum JsonQueryResultsReader<R: Read> {
}
impl<R: Read> JsonQueryResultsReader<R> {
pub fn read(read: R) -> Result<Self, ParseError> {
pub fn read(read: R) -> Result<Self, QueryResultsParseError> {
let mut reader = FromReadJsonReader::new(read);
let mut variables = None;
let mut buffered_bindings: Option<Vec<_>> = None;
let mut output_iter = None;
if reader.read_next_event()? != JsonEvent::StartObject {
return Err(SyntaxError::msg("SPARQL JSON results should be an object").into());
return Err(
QueryResultsSyntaxError::msg("SPARQL JSON results should be an object").into(),
);
}
loop {
@ -269,14 +271,17 @@ impl<R: Read> JsonQueryResultsReader<R> {
}
"results" => {
if reader.read_next_event()? != JsonEvent::StartObject {
return Err(SyntaxError::msg("'results' should be an object").into());
return Err(QueryResultsSyntaxError::msg(
"'results' should be an object",
)
.into());
}
loop {
match reader.read_next_event()? {
JsonEvent::ObjectKey(k) if k == "bindings" => break, // Found
JsonEvent::ObjectKey(_) => ignore_value(&mut reader)?,
_ => {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"'results' should contain a 'bindings' key",
)
.into())
@ -284,7 +289,10 @@ impl<R: Read> JsonQueryResultsReader<R> {
}
}
if reader.read_next_event()? != JsonEvent::StartArray {
return Err(SyntaxError::msg("'bindings' should be an object").into());
return Err(QueryResultsSyntaxError::msg(
"'bindings' should be an object",
)
.into());
}
if let Some(variables) = variables {
let mut mapping = BTreeMap::default();
@ -318,9 +326,10 @@ impl<R: Read> JsonQueryResultsReader<R> {
values.push(read_value(&mut reader, 0)?);
}
_ => {
return Err(
SyntaxError::msg("Invalid result serialization").into()
return Err(QueryResultsSyntaxError::msg(
"Invalid result serialization",
)
.into())
}
}
}
@ -329,11 +338,11 @@ impl<R: Read> JsonQueryResultsReader<R> {
return if let JsonEvent::Boolean(v) = reader.read_next_event()? {
Ok(Self::Boolean(v))
} else {
Err(SyntaxError::msg("Unexpected boolean value").into())
Err(QueryResultsSyntaxError::msg("Unexpected boolean value").into())
}
}
_ => {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Expecting head or result key, found {key}"
))
.into());
@ -344,13 +353,18 @@ impl<R: Read> JsonQueryResultsReader<R> {
return if let Some(output_iter) = output_iter {
Ok(output_iter)
} else {
Err(SyntaxError::msg(
Err(QueryResultsSyntaxError::msg(
"Unexpected end of JSON object without 'results' or 'boolean' key",
)
.into())
}
}
_ => return Err(SyntaxError::msg("Invalid SPARQL results serialization").into()),
_ => {
return Err(QueryResultsSyntaxError::msg(
"Invalid SPARQL results serialization",
)
.into())
}
}
}
}
@ -371,7 +385,7 @@ enum JsonSolutionsReaderKind<R: Read> {
}
impl<R: Read> JsonSolutionsReader<R> {
pub fn read_next(&mut self) -> Result<Option<Vec<Option<Term>>>, ParseError> {
pub fn read_next(&mut self) -> Result<Option<Vec<Option<Term>>>, QueryResultsParseError> {
match &mut self.kind {
JsonSolutionsReaderKind::Streaming { reader } => {
let mut new_bindings = vec![None; self.mapping.len()];
@ -382,13 +396,18 @@ impl<R: Read> JsonSolutionsReader<R> {
JsonEvent::EndArray | JsonEvent::Eof => return Ok(None),
JsonEvent::ObjectKey(key) => {
let k = *self.mapping.get(key.as_ref()).ok_or_else(|| {
SyntaxError::msg(format!(
QueryResultsSyntaxError::msg(format!(
"The variable {key} has not been defined in the header"
))
})?;
new_bindings[k] = Some(read_value(reader, 0)?)
}
_ => return Err(SyntaxError::msg("Invalid result serialization").into()),
_ => {
return Err(QueryResultsSyntaxError::msg(
"Invalid result serialization",
)
.into())
}
}
}
}
@ -397,7 +416,7 @@ impl<R: Read> JsonSolutionsReader<R> {
let mut new_bindings = vec![None; self.mapping.len()];
for (variable, value) in variables.into_iter().zip(values) {
let k = *self.mapping.get(&variable).ok_or_else(|| {
SyntaxError::msg(format!(
QueryResultsSyntaxError::msg(format!(
"The variable {variable} has not been defined in the header"
))
})?;
@ -415,7 +434,7 @@ impl<R: Read> JsonSolutionsReader<R> {
fn read_value<R: Read>(
reader: &mut FromReadJsonReader<R>,
number_of_recursive_calls: usize,
) -> Result<Term, ParseError> {
) -> Result<Term, QueryResultsParseError> {
enum Type {
Uri,
BNode,
@ -432,7 +451,7 @@ fn read_value<R: Read>(
}
if number_of_recursive_calls == MAX_NUMBER_OF_NESTED_TRIPLES {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Too many nested triples ({MAX_NUMBER_OF_NESTED_TRIPLES}). The parser fails here to avoid a stack overflow."
))
.into());
@ -449,7 +468,7 @@ fn read_value<R: Read>(
#[cfg(feature = "rdf-star")]
let mut object = None;
if reader.read_next_event()? != JsonEvent::StartObject {
return Err(SyntaxError::msg("Term serializations should be an object").into());
return Err(QueryResultsSyntaxError::msg("Term serializations should be an object").into());
}
loop {
#[allow(unsafe_code)]
@ -472,7 +491,7 @@ fn read_value<R: Read>(
#[cfg(feature = "rdf-star")]
"object" => object = Some(read_value(reader, number_of_recursive_calls + 1)?),
_ => {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Unexpected key in term serialization: '{key}'"
))
.into())
@ -480,9 +499,10 @@ fn read_value<R: Read>(
},
JsonEvent::StartObject => {
if state != Some(State::Value) {
return Err(
SyntaxError::msg("Unexpected nested object in term serialization").into(),
);
return Err(QueryResultsSyntaxError::msg(
"Unexpected nested object in term serialization",
)
.into());
}
}
JsonEvent::String(s) => match state {
@ -494,9 +514,10 @@ fn read_value<R: Read>(
#[cfg(feature = "rdf-star")]
"triple" => t = Some(Type::Triple),
_ => {
return Err(
SyntaxError::msg(format!("Unexpected term type: '{s}'")).into()
)
return Err(QueryResultsSyntaxError::msg(format!(
"Unexpected term type: '{s}'"
))
.into())
}
};
state = None;
@ -510,10 +531,9 @@ fn read_value<R: Read>(
state = None;
}
Some(State::Datatype) => {
datatype = Some(
NamedNode::new(s)
.map_err(|e| SyntaxError::msg(format!("Invalid datatype IRI: {e}")))?,
);
datatype = Some(NamedNode::new(s).map_err(|e| {
QueryResultsSyntaxError::msg(format!("Invalid datatype IRI: {e}"))
})?);
state = None;
}
_ => (), // impossible
@ -523,41 +543,52 @@ fn read_value<R: Read>(
if s == State::Value {
state = None; // End of triple
} else {
return Err(
SyntaxError::msg("Term description values should be string").into()
);
return Err(QueryResultsSyntaxError::msg(
"Term description values should be string",
)
.into());
}
} else {
return match t {
None => Err(SyntaxError::msg(
None => Err(QueryResultsSyntaxError::msg(
"Term serialization should have a 'type' key",
)
.into()),
Some(Type::Uri) => Ok(NamedNode::new(value.ok_or_else(|| {
SyntaxError::msg("uri serialization should have a 'value' key")
QueryResultsSyntaxError::msg(
"uri serialization should have a 'value' key",
)
})?)
.map_err(|e| SyntaxError::msg(format!("Invalid uri value: {e}")))?
.map_err(|e| {
QueryResultsSyntaxError::msg(format!("Invalid uri value: {e}"))
})?
.into()),
Some(Type::BNode) => Ok(BlankNode::new(value.ok_or_else(|| {
SyntaxError::msg("bnode serialization should have a 'value' key")
QueryResultsSyntaxError::msg(
"bnode serialization should have a 'value' key",
)
})?)
.map_err(|e| SyntaxError::msg(format!("Invalid bnode value: {e}")))?
.map_err(|e| {
QueryResultsSyntaxError::msg(format!("Invalid bnode value: {e}"))
})?
.into()),
Some(Type::Literal) => {
let value = value.ok_or_else(|| {
SyntaxError::msg("literal serialization should have a 'value' key")
QueryResultsSyntaxError::msg(
"literal serialization should have a 'value' key",
)
})?;
Ok(match lang {
Some(lang) => {
if let Some(datatype) = datatype {
if datatype.as_ref() != rdf::LANG_STRING {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"xml:lang value '{lang}' provided with the datatype {datatype}"
)).into())
}
}
Literal::new_language_tagged_literal(value, &*lang).map_err(|e| {
SyntaxError::msg(format!("Invalid xml:lang value '{lang}': {e}"))
QueryResultsSyntaxError::msg(format!("Invalid xml:lang value '{lang}': {e}"))
})?
}
None => if let Some(datatype) = datatype {
@ -571,47 +602,53 @@ fn read_value<R: Read>(
#[cfg(feature = "rdf-star")]
Some(Type::Triple) => Ok(Triple::new(
match subject.ok_or_else(|| {
SyntaxError::msg("triple serialization should have a 'subject' key")
QueryResultsSyntaxError::msg(
"triple serialization should have a 'subject' key",
)
})? {
Term::NamedNode(subject) => subject.into(),
Term::BlankNode(subject) => subject.into(),
Term::Triple(subject) => Subject::Triple(subject),
Term::Literal(_) => {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"The 'subject' value should not be a literal",
)
.into())
}
},
match predicate.ok_or_else(|| {
SyntaxError::msg(
QueryResultsSyntaxError::msg(
"triple serialization should have a 'predicate' key",
)
})? {
Term::NamedNode(predicate) => predicate,
_ => {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"The 'predicate' value should be a uri",
)
.into())
}
},
object.ok_or_else(|| {
SyntaxError::msg("triple serialization should have a 'object' key")
QueryResultsSyntaxError::msg(
"triple serialization should have a 'object' key",
)
})?,
)
.into()),
};
}
}
_ => return Err(SyntaxError::msg("Invalid term serialization").into()),
_ => return Err(QueryResultsSyntaxError::msg("Invalid term serialization").into()),
}
}
}
fn read_head<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<Vec<Variable>, ParseError> {
fn read_head<R: Read>(
reader: &mut FromReadJsonReader<R>,
) -> Result<Vec<Variable>, QueryResultsParseError> {
if reader.read_next_event()? != JsonEvent::StartObject {
return Err(SyntaxError::msg("head should be an object").into());
return Err(QueryResultsSyntaxError::msg("head should be an object").into());
}
let mut variables = Vec::new();
loop {
@ -619,18 +656,21 @@ fn read_head<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<Vec<Variable
JsonEvent::ObjectKey(key) => match key.as_ref() {
"vars" => {
if reader.read_next_event()? != JsonEvent::StartArray {
return Err(SyntaxError::msg("Variable list should be an array").into());
return Err(QueryResultsSyntaxError::msg(
"Variable list should be an array",
)
.into());
}
loop {
match reader.read_next_event()? {
JsonEvent::String(s) => {
let new_var = Variable::new(s.as_ref()).map_err(|e| {
SyntaxError::msg(format!(
QueryResultsSyntaxError::msg(format!(
"Invalid variable declaration '{s}': {e}"
))
})?;
if variables.contains(&new_var) {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"The variable {new_var} is declared twice"
))
.into());
@ -639,23 +679,30 @@ fn read_head<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<Vec<Variable
}
JsonEvent::EndArray => break,
_ => {
return Err(
SyntaxError::msg("Variable names should be strings").into()
return Err(QueryResultsSyntaxError::msg(
"Variable names should be strings",
)
.into())
}
}
}
}
"link" => {
if reader.read_next_event()? != JsonEvent::StartArray {
return Err(SyntaxError::msg("Variable list should be an array").into());
return Err(QueryResultsSyntaxError::msg(
"Variable list should be an array",
)
.into());
}
loop {
match reader.read_next_event()? {
JsonEvent::String(_) => (),
JsonEvent::EndArray => break,
_ => {
return Err(SyntaxError::msg("Link names should be strings").into())
return Err(QueryResultsSyntaxError::msg(
"Link names should be strings",
)
.into())
}
}
}
@ -663,12 +710,12 @@ fn read_head<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<Vec<Variable
_ => ignore_value(reader)?,
},
JsonEvent::EndObject => return Ok(variables),
_ => return Err(SyntaxError::msg("Invalid head serialization").into()),
_ => return Err(QueryResultsSyntaxError::msg("Invalid head serialization").into()),
}
}
}
fn ignore_value<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<(), ParseError> {
fn ignore_value<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<(), QueryResultsParseError> {
let mut nesting = 0;
loop {
match reader.read_next_event()? {
@ -688,7 +735,9 @@ fn ignore_value<R: Read>(reader: &mut FromReadJsonReader<R>) -> Result<(), Parse
return Ok(());
}
}
JsonEvent::Eof => return Err(SyntaxError::msg("Unexpected end of file").into()),
JsonEvent::Eof => {
return Err(QueryResultsSyntaxError::msg("Unexpected end of file").into())
}
}
}
}

@ -13,7 +13,7 @@ mod serializer;
pub mod solution;
mod xml;
pub use crate::error::{ParseError, SyntaxError, TextPosition};
pub use crate::error::{QueryResultsParseError, QueryResultsSyntaxError, TextPosition};
pub use crate::format::QueryResultsFormat;
pub use crate::parser::{FromReadQueryResultsReader, FromReadSolutionsReader, QueryResultsParser};
pub use crate::serializer::{QueryResultsSerializer, ToWriteSolutionsWriter};

@ -1,5 +1,5 @@
use crate::csv::{TsvQueryResultsReader, TsvSolutionsReader};
use crate::error::{ParseError, SyntaxError};
use crate::error::{QueryResultsParseError, QueryResultsSyntaxError};
use crate::format::QueryResultsFormat;
use crate::json::{JsonQueryResultsReader, JsonSolutionsReader};
use crate::solution::QuerySolution;
@ -32,7 +32,7 @@ use std::sync::Arc;
/// assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new_unchecked("foo"), &Literal::from("test").into())]);
/// }
/// }
/// # Result::<(),sparesults::ParseError>::Ok(())
/// # Result::<(),sparesults::QueryResultsParseError>::Ok(())
/// ```
pub struct QueryResultsParser {
format: QueryResultsFormat,
@ -68,12 +68,12 @@ impl QueryResultsParser {
/// assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new_unchecked("foo"), &Literal::from("test").into())]);
/// }
/// }
/// # Result::<(),sparesults::ParseError>::Ok(())
/// # Result::<(),sparesults::QueryResultsParseError>::Ok(())
/// ```
pub fn parse_read<R: Read>(
&self,
reader: R,
) -> Result<FromReadQueryResultsReader<R>, ParseError> {
) -> Result<FromReadQueryResultsReader<R>, QueryResultsParseError> {
Ok(match self.format {
QueryResultsFormat::Xml => match XmlQueryResultsReader::read(reader)? {
XmlQueryResultsReader::Boolean(r) => FromReadQueryResultsReader::Boolean(r),
@ -95,7 +95,7 @@ impl QueryResultsParser {
solutions: SolutionsReaderKind::Json(solutions),
}),
},
QueryResultsFormat::Csv => return Err(SyntaxError::msg("CSV SPARQL results syntax is lossy and can't be parsed to a proper RDF representation").into()),
QueryResultsFormat::Csv => return Err(QueryResultsSyntaxError::msg("CSV SPARQL results syntax is lossy and can't be parsed to a proper RDF representation").into()),
QueryResultsFormat::Tsv => match TsvQueryResultsReader::read(reader)? {
TsvQueryResultsReader::Boolean(r) => FromReadQueryResultsReader::Boolean(r),
TsvQueryResultsReader::Solutions {
@ -113,7 +113,7 @@ impl QueryResultsParser {
pub fn read_results<R: Read>(
&self,
reader: R,
) -> Result<FromReadQueryResultsReader<R>, ParseError> {
) -> Result<FromReadQueryResultsReader<R>, QueryResultsParseError> {
self.parse_read(reader)
}
}
@ -161,7 +161,7 @@ impl From<QueryResultsFormat> for QueryResultsParser {
/// );
/// }
/// }
/// # Result::<(),sparesults::ParseError>::Ok(())
/// # Result::<(),sparesults::QueryResultsParseError>::Ok(())
/// ```
pub enum FromReadQueryResultsReader<R: Read> {
Solutions(FromReadSolutionsReader<R>),
@ -184,7 +184,7 @@ pub enum FromReadQueryResultsReader<R: Read> {
/// assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new_unchecked("foo"), &Literal::from("test").into())]);
/// }
/// }
/// # Result::<(),sparesults::ParseError>::Ok(())
/// # Result::<(),sparesults::QueryResultsParseError>::Ok(())
/// ```
pub struct FromReadSolutionsReader<R: Read> {
variables: Arc<[Variable]>,
@ -217,7 +217,7 @@ impl<R: Read> FromReadSolutionsReader<R> {
/// ]
/// );
/// }
/// # Result::<(),sparesults::ParseError>::Ok(())
/// # Result::<(),sparesults::QueryResultsParseError>::Ok(())
/// ```
#[inline]
pub fn variables(&self) -> &[Variable] {
@ -226,7 +226,7 @@ impl<R: Read> FromReadSolutionsReader<R> {
}
impl<R: Read> Iterator for FromReadSolutionsReader<R> {
type Item = Result<QuerySolution, ParseError>;
type Item = Result<QuerySolution, QueryResultsParseError>;
fn next(&mut self) -> Option<Self::Item> {
Some(

@ -1,6 +1,6 @@
//! Implementation of [SPARQL Query Results XML Format](https://www.w3.org/TR/rdf-sparql-XMLres/)
use crate::error::{ParseError, SyntaxError};
use crate::error::{QueryResultsParseError, QueryResultsSyntaxError};
use oxrdf::vocab::rdf;
use oxrdf::*;
use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event};
@ -227,7 +227,7 @@ pub enum XmlQueryResultsReader<R: Read> {
}
impl<R: Read> XmlQueryResultsReader<R> {
pub fn read(source: R) -> Result<Self, ParseError> {
pub fn read(source: R) -> Result<Self, QueryResultsParseError> {
enum State {
Start,
Sparql,
@ -254,14 +254,14 @@ impl<R: Read> XmlQueryResultsReader<R> {
if event.local_name().as_ref() == b"sparql" {
state = State::Sparql;
} else {
return Err(SyntaxError::msg(format!("Expecting <sparql> tag, found <{}>", decode(&reader, &event.name())?)).into());
return Err(QueryResultsSyntaxError::msg(format!("Expecting <sparql> tag, found <{}>", decode(&reader, &event.name())?)).into());
}
}
State::Sparql => {
if event.local_name().as_ref() == b"head" {
state = State::Head;
} else {
return Err(SyntaxError::msg(format!("Expecting <head> tag, found <{}>",decode(&reader, &event.name())?)).into());
return Err(QueryResultsSyntaxError::msg(format!("Expecting <head> tag, found <{}>", decode(&reader, &event.name())?)).into());
}
}
State::Head => {
@ -269,11 +269,11 @@ impl<R: Read> XmlQueryResultsReader<R> {
let name = event.attributes()
.filter_map(Result::ok)
.find(|attr| attr.key.local_name().as_ref() == b"name")
.ok_or_else(|| SyntaxError::msg("No name attribute found for the <variable> tag"))?
.ok_or_else(|| QueryResultsSyntaxError::msg("No name attribute found for the <variable> tag"))?
.decode_and_unescape_value(&reader)?;
let variable = Variable::new(name).map_err(|e| SyntaxError::msg(format!("Invalid variable name: {e}")))?;
let variable = Variable::new(name).map_err(|e| QueryResultsSyntaxError::msg(format!("Invalid variable name: {e}")))?;
if variables.contains(&variable) {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"The variable {variable} is declared twice"
))
.into());
@ -282,7 +282,7 @@ impl<R: Read> XmlQueryResultsReader<R> {
} else if event.local_name().as_ref() == b"link" {
// no op
} else {
return Err(SyntaxError::msg(format!("Expecting <variable> or <link> tag, found <{}>", decode(&reader, &event.name())?)).into());
return Err(QueryResultsSyntaxError::msg(format!("Expecting <variable> or <link> tag, found <{}>", decode(&reader, &event.name())?)).into());
}
}
State::AfterHead => {
@ -304,10 +304,10 @@ impl<R: Read> XmlQueryResultsReader<R> {
object_stack: Vec::new(),
}});
} else if event.local_name().as_ref() != b"link" && event.local_name().as_ref() != b"results" && event.local_name().as_ref() != b"boolean" {
return Err(SyntaxError::msg(format!("Expecting sparql tag, found <{}>", decode(&reader, &event.name())?)).into());
return Err(QueryResultsSyntaxError::msg(format!("Expecting sparql tag, found <{}>", decode(&reader, &event.name())?)).into());
}
}
State::Boolean => return Err(SyntaxError::msg(format!("Unexpected tag inside of <boolean> tag: <{}>", decode(&reader, &event.name())?)).into())
State::Boolean => return Err(QueryResultsSyntaxError::msg(format!("Unexpected tag inside of <boolean> tag: <{}>", decode(&reader, &event.name())?)).into())
},
Event::Text(event) => {
let value = event.unescape()?;
@ -318,10 +318,10 @@ impl<R: Read> XmlQueryResultsReader<R> {
} else if value == "false" {
Ok(Self::Boolean(false))
} else {
Err(SyntaxError::msg(format!("Unexpected boolean value. Found '{value}'")).into())
Err(QueryResultsSyntaxError::msg(format!("Unexpected boolean value. Found '{value}'")).into())
};
}
_ => Err(SyntaxError::msg(format!("Unexpected textual value found: '{value}'")).into())
_ => Err(QueryResultsSyntaxError::msg(format!("Unexpected textual value found: '{value}'")).into())
};
},
Event::End(event) => {
@ -330,10 +330,10 @@ impl<R: Read> XmlQueryResultsReader<R> {
state = State::AfterHead
}
} else {
return Err(SyntaxError::msg("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag").into());
return Err(QueryResultsSyntaxError::msg("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag").into());
}
},
Event::Eof => return Err(SyntaxError::msg("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag").into()),
Event::Eof => return Err(QueryResultsSyntaxError::msg("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag").into()),
_ => (),
}
}
@ -365,7 +365,7 @@ pub struct XmlSolutionsReader<R: Read> {
}
impl<R: Read> XmlSolutionsReader<R> {
pub fn read_next(&mut self) -> Result<Option<Vec<Option<Term>>>, ParseError> {
pub fn read_next(&mut self) -> Result<Option<Vec<Option<Term>>>, QueryResultsParseError> {
let mut state = State::Start;
let mut new_bindings = vec![None; self.mapping.len()];
@ -383,7 +383,7 @@ impl<R: Read> XmlSolutionsReader<R> {
if event.local_name().as_ref() == b"result" {
state = State::Result;
} else {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Expecting <result>, found <{}>",
decode(&self.reader, &event.name())?
))
@ -403,7 +403,7 @@ impl<R: Read> XmlSolutionsReader<R> {
)
}
None => {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"No name attribute found for the <binding> tag",
)
.into());
@ -411,7 +411,7 @@ impl<R: Read> XmlSolutionsReader<R> {
}
state = State::Binding;
} else {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Expecting <binding>, found <{}>",
decode(&self.reader, &event.name())?
))
@ -420,7 +420,7 @@ impl<R: Read> XmlSolutionsReader<R> {
}
State::Binding | State::Subject | State::Predicate | State::Object => {
if term.is_some() {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"There is already a value for the current binding",
)
.into());
@ -441,7 +441,7 @@ impl<R: Read> XmlSolutionsReader<R> {
let iri = attr.decode_and_unescape_value(&self.reader)?;
datatype =
Some(NamedNode::new(iri.to_string()).map_err(|e| {
SyntaxError::msg(format!(
QueryResultsSyntaxError::msg(format!(
"Invalid datatype IRI '{iri}': {e}"
))
})?);
@ -451,7 +451,7 @@ impl<R: Read> XmlSolutionsReader<R> {
} else if event.local_name().as_ref() == b"triple" {
state = State::Triple;
} else {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Expecting <uri>, <bnode> or <literal> found <{}>",
decode(&self.reader, &event.name())?
))
@ -466,7 +466,7 @@ impl<R: Read> XmlSolutionsReader<R> {
} else if event.local_name().as_ref() == b"object" {
state = State::Object
} else {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Expecting <subject>, <predicate> or <object> found <{}>",
decode(&self.reader, &event.name())?
))
@ -482,7 +482,9 @@ impl<R: Read> XmlSolutionsReader<R> {
term = Some(
NamedNode::new(data.to_string())
.map_err(|e| {
SyntaxError::msg(format!("Invalid IRI value '{data}': {e}"))
QueryResultsSyntaxError::msg(format!(
"Invalid IRI value '{data}': {e}"
))
})?
.into(),
)
@ -491,7 +493,7 @@ impl<R: Read> XmlSolutionsReader<R> {
term = Some(
BlankNode::new(data.to_string())
.map_err(|e| {
SyntaxError::msg(format!(
QueryResultsSyntaxError::msg(format!(
"Invalid blank node value '{data}': {e}"
))
})?
@ -502,7 +504,7 @@ impl<R: Read> XmlSolutionsReader<R> {
term = Some(build_literal(data, lang.take(), datatype.take())?.into());
}
_ => {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"Unexpected textual value found: {data}"
))
.into());
@ -518,11 +520,14 @@ impl<R: Read> XmlSolutionsReader<R> {
new_bindings[*var] = term.take()
} else {
return Err(
SyntaxError::msg(format!("The variable '{var}' is used in a binding but not declared in the variables list")).into()
QueryResultsSyntaxError::msg(format!("The variable '{var}' is used in a binding but not declared in the variables list")).into()
);
}
} else {
return Err(SyntaxError::msg("No name found for <binding> tag").into());
return Err(QueryResultsSyntaxError::msg(
"No name found for <binding> tag",
)
.into());
}
state = State::Result;
}
@ -548,7 +553,7 @@ impl<R: Read> XmlSolutionsReader<R> {
state = self
.stack
.pop()
.ok_or_else(|| SyntaxError::msg("Empty stack"))?
.ok_or_else(|| QueryResultsSyntaxError::msg("Empty stack"))?
}
State::BNode => {
if term.is_none() {
@ -558,7 +563,7 @@ impl<R: Read> XmlSolutionsReader<R> {
state = self
.stack
.pop()
.ok_or_else(|| SyntaxError::msg("Empty stack"))?
.ok_or_else(|| QueryResultsSyntaxError::msg("Empty stack"))?
}
State::Literal => {
if term.is_none() {
@ -568,7 +573,7 @@ impl<R: Read> XmlSolutionsReader<R> {
state = self
.stack
.pop()
.ok_or_else(|| SyntaxError::msg("Empty stack"))?;
.ok_or_else(|| QueryResultsSyntaxError::msg("Empty stack"))?;
}
State::Triple => {
#[cfg(feature = "rdf-star")]
@ -584,7 +589,7 @@ impl<R: Read> XmlSolutionsReader<R> {
Term::BlankNode(subject) => subject.into(),
Term::Triple(subject) => Subject::Triple(subject),
Term::Literal(_) => {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"The <subject> value should not be a <literal>",
)
.into())
@ -593,7 +598,7 @@ impl<R: Read> XmlSolutionsReader<R> {
match predicate {
Term::NamedNode(predicate) => predicate,
_ => {
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"The <predicate> value should be an <uri>",
)
.into())
@ -606,15 +611,15 @@ impl<R: Read> XmlSolutionsReader<R> {
state = self
.stack
.pop()
.ok_or_else(|| SyntaxError::msg("Empty stack"))?;
.ok_or_else(|| QueryResultsSyntaxError::msg("Empty stack"))?;
} else {
return Err(
SyntaxError::msg("A <triple> should contain a <subject>, a <predicate> and an <object>").into()
QueryResultsSyntaxError::msg("A <triple> should contain a <subject>, a <predicate> and an <object>").into()
);
}
#[cfg(not(feature = "rdf-star"))]
{
return Err(SyntaxError::msg(
return Err(QueryResultsSyntaxError::msg(
"The <triple> tag is only supported with RDF-star",
)
.into());
@ -633,19 +638,19 @@ fn build_literal(
value: impl Into<String>,
lang: Option<String>,
datatype: Option<NamedNode>,
) -> Result<Literal, ParseError> {
) -> Result<Literal, QueryResultsParseError> {
match lang {
Some(lang) => {
if let Some(datatype) = datatype {
if datatype.as_ref() != rdf::LANG_STRING {
return Err(SyntaxError::msg(format!(
return Err(QueryResultsSyntaxError::msg(format!(
"xml:lang value '{lang}' provided with the datatype {datatype}"
))
.into());
}
}
Literal::new_language_tagged_literal(value, &lang).map_err(|e| {
SyntaxError::msg(format!("Invalid xml:lang value '{lang}': {e}")).into()
QueryResultsSyntaxError::msg(format!("Invalid xml:lang value '{lang}': {e}")).into()
})
}
None => Ok(if let Some(datatype) = datatype {
@ -659,7 +664,7 @@ fn build_literal(
fn decode<'a, T>(
reader: &Reader<T>,
data: &'a impl AsRef<[u8]>,
) -> Result<Cow<'a, str>, ParseError> {
) -> Result<Cow<'a, str>, QueryResultsParseError> {
Ok(reader.decoder().decode(data.as_ref())?)
}

@ -10,6 +10,6 @@ mod query;
pub mod term;
mod update;
pub use parser::ParseError;
pub use parser::SparqlSyntaxError;
pub use query::*;
pub use update::*;

@ -15,16 +15,16 @@ use std::mem::take;
use std::str::FromStr;
/// 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, SparqlSyntaxError> {
let mut state = ParserState::from_base_iri(base_iri)?;
parser::QueryUnit(query, &mut state).map_err(|e| ParseError(ParseErrorKind::Parser(e)))
parser::QueryUnit(query, &mut state).map_err(|e| SparqlSyntaxError(ParseErrorKind::Syntax(e)))
}
/// 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, SparqlSyntaxError> {
let mut state = ParserState::from_base_iri(base_iri)?;
let operations = parser::UpdateInit(update, &mut state)
.map_err(|e| ParseError(ParseErrorKind::Parser(e)))?;
.map_err(|e| SparqlSyntaxError(ParseErrorKind::Syntax(e)))?;
Ok(Update {
operations,
base_iri: state.base_iri,
@ -34,14 +34,14 @@ pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, Pars
/// Error returned during SPARQL parsing.
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct ParseError(#[from] ParseErrorKind);
pub struct SparqlSyntaxError(#[from] ParseErrorKind);
#[derive(Debug, thiserror::Error)]
enum ParseErrorKind {
#[error("Invalid SPARQL base IRI provided: {0}")]
InvalidBaseIri(#[from] IriParseError),
#[error(transparent)]
Parser(#[from] peg::error::ParseError<LineCol>),
Syntax(#[from] peg::error::ParseError<LineCol>),
}
struct AnnotatedTerm {
@ -669,12 +669,12 @@ pub struct ParserState {
}
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, SparqlSyntaxError> {
Ok(Self {
base_iri: if let Some(base_iri) = base_iri {
Some(
Iri::parse(base_iri.to_owned())
.map_err(|e| ParseError(ParseErrorKind::InvalidBaseIri(e)))?,
.map_err(|e| SparqlSyntaxError(ParseErrorKind::InvalidBaseIri(e)))?,
)
} else {
None

@ -1,5 +1,5 @@
use crate::algebra::*;
use crate::parser::{parse_query, ParseError};
use crate::parser::{parse_query, SparqlSyntaxError};
use crate::term::*;
use oxiri::Iri;
use std::fmt;
@ -17,7 +17,7 @@ use std::str::FromStr;
/// query.to_sse(),
/// "(project (?s ?p ?o) (bgp (triple ?s ?p ?o)))"
/// );
/// # Ok::<_, spargebra::ParseError>(())
/// # Ok::<_, spargebra::SparqlSyntaxError>(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum Query {
@ -63,7 +63,7 @@ pub enum Query {
impl Query {
/// Parses a SPARQL query with an optional base IRI to resolve relative IRIs in the query.
pub fn parse(query: &str, base_iri: Option<&str>) -> Result<Self, ParseError> {
pub fn parse(query: &str, base_iri: Option<&str>) -> Result<Self, SparqlSyntaxError> {
parse_query(query, base_iri)
}
@ -276,7 +276,7 @@ impl fmt::Display for Query {
}
impl FromStr for Query {
type Err = ParseError;
type Err = SparqlSyntaxError;
fn from_str(query: &str) -> Result<Self, Self::Err> {
Self::parse(query, None)
@ -284,7 +284,7 @@ impl FromStr for Query {
}
impl<'a> TryFrom<&'a str> for Query {
type Error = ParseError;
type Error = SparqlSyntaxError;
fn try_from(query: &str) -> Result<Self, Self::Error> {
Self::from_str(query)
@ -292,7 +292,7 @@ impl<'a> TryFrom<&'a str> for Query {
}
impl<'a> TryFrom<&'a String> for Query {
type Error = ParseError;
type Error = SparqlSyntaxError;
fn try_from(query: &String) -> Result<Self, Self::Error> {
Self::from_str(query)

@ -1,5 +1,5 @@
use crate::algebra::*;
use crate::parser::{parse_update, ParseError};
use crate::parser::{parse_update, SparqlSyntaxError};
use crate::term::*;
use oxiri::Iri;
use std::fmt;
@ -14,7 +14,7 @@ use std::str::FromStr;
/// let update = Update::parse(update_str, None)?;
/// assert_eq!(update.to_string().trim(), update_str);
/// assert_eq!(update.to_sse(), "(update (clear all))");
/// # Ok::<_, spargebra::ParseError>(())
/// # Ok::<_, spargebra::SparqlSyntaxError>(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct Update {
@ -26,7 +26,7 @@ pub struct Update {
impl Update {
/// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query.
pub fn parse(update: &str, base_iri: Option<&str>) -> Result<Self, ParseError> {
pub fn parse(update: &str, base_iri: Option<&str>) -> Result<Self, SparqlSyntaxError> {
parse_update(update, base_iri)
}
@ -68,7 +68,7 @@ impl fmt::Display for Update {
}
impl FromStr for Update {
type Err = ParseError;
type Err = SparqlSyntaxError;
fn from_str(update: &str) -> Result<Self, Self::Err> {
Self::parse(update, None)
@ -76,7 +76,7 @@ impl FromStr for Update {
}
impl<'a> TryFrom<&'a str> for Update {
type Error = ParseError;
type Error = SparqlSyntaxError;
fn try_from(update: &str) -> Result<Self, Self::Error> {
Self::from_str(update)
@ -84,7 +84,7 @@ impl<'a> TryFrom<&'a str> for Update {
}
impl<'a> TryFrom<&'a String> for Update {
type Error = ParseError;
type Error = SparqlSyntaxError;
fn try_from(update: &String) -> Result<Self, Self::Error> {
Self::from_str(update)

@ -1,7 +1,7 @@
#![allow(clippy::needless_option_as_deref)]
use crate::model::{hash, PyQuad, PyTriple};
use oxigraph::io::{FromReadQuadReader, ParseError, RdfFormat, RdfParser, RdfSerializer};
use oxigraph::io::{FromReadQuadReader, RdfFormat, RdfParseError, RdfParser, RdfSerializer};
use oxigraph::model::QuadRef;
use pyo3::exceptions::{PyDeprecationWarning, PySyntaxError, PyValueError};
use pyo3::intern;
@ -556,9 +556,9 @@ pub enum PyRdfFormatInput {
MediaType(String),
}
pub fn map_parse_error(error: ParseError, file_path: Option<PathBuf>) -> PyErr {
pub fn map_parse_error(error: RdfParseError, file_path: Option<PathBuf>) -> PyErr {
match error {
ParseError::Syntax(error) => {
RdfParseError::Syntax(error) => {
// Python 3.9 does not support end line and end column
if python_version() >= (3, 10) {
let params = if let Some(location) = error.location() {
@ -588,7 +588,7 @@ pub fn map_parse_error(error: ParseError, file_path: Option<PathBuf>) -> PyErr {
PySyntaxError::new_err((error.to_string(), params))
}
}
ParseError::Io(error) => error.into(),
RdfParseError::Io(error) => error.into(),
}
}

@ -4,8 +4,8 @@ use crate::store::map_storage_error;
use oxigraph::io::RdfSerializer;
use oxigraph::model::Term;
use oxigraph::sparql::results::{
FromReadQueryResultsReader, FromReadSolutionsReader, ParseError, QueryResultsFormat,
QueryResultsParser, QueryResultsSerializer,
FromReadQueryResultsReader, FromReadSolutionsReader, QueryResultsFormat,
QueryResultsParseError, QueryResultsParser, QueryResultsSerializer,
};
use oxigraph::sparql::{
EvaluationError, Query, QueryResults, QuerySolution, QuerySolutionIter, QueryTripleIter,
@ -699,9 +699,12 @@ pub fn map_evaluation_error(error: EvaluationError) -> PyErr {
}
}
pub fn map_query_results_parse_error(error: ParseError, file_path: Option<PathBuf>) -> PyErr {
pub fn map_query_results_parse_error(
error: QueryResultsParseError,
file_path: Option<PathBuf>,
) -> PyErr {
match error {
ParseError::Syntax(error) => {
QueryResultsParseError::Syntax(error) => {
// Python 3.9 does not support end line and end column
if python_version() >= (3, 10) {
let params = if let Some(location) = error.location() {
@ -731,6 +734,6 @@ pub fn map_query_results_parse_error(error: ParseError, file_path: Option<PathBu
PySyntaxError::new_err((error.to_string(), params))
}
}
ParseError::Io(error) => error.into(),
QueryResultsParseError::Io(error) => error.into(),
}
}

Loading…
Cancel
Save