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 # Internal dependencies
oxigraph = { version = "0.4.0-alpha.3-dev", path = "lib/oxigraph" } oxigraph = { version = "0.4.0-alpha.3-dev", path = "lib/oxigraph" }
oxrdf = { version = "0.2.0-alpha.2", path = "lib/oxrdf" } oxrdf = { version = "0.2.0-alpha.2", path = "lib/oxrdf" }
oxrdfio = { version = "0.1.0-alpha.2", path = "lib/oxrdfio" } oxrdfio = { version = "0.1.0-alpha.3-dev", path = "lib/oxrdfio" }
oxrdfxml = { version = "0.1.0-alpha.2", path = "lib/oxrdfxml" } oxrdfxml = { version = "0.1.0-alpha.3-dev", path = "lib/oxrdfxml" }
oxrocksdb-sys = { version = "0.4.0-alpha.3-dev", path = "./oxrocksdb-sys" } oxrocksdb-sys = { version = "0.4.0-alpha.3-dev", path = "./oxrocksdb-sys" }
oxsdatatypes = { version = "0.2.0-alpha.1", path = "lib/oxsdatatypes" } 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" } sparesults = { version = "0.2.0-alpha.2", path = "lib/sparesults" }
spargebra = { version = "0.3.0-alpha.2", path = "lib/spargebra" } spargebra = { version = "0.3.0-alpha.2", path = "lib/spargebra" }
sparopt = { version = "0.1.0-alpha.2", path = "lib/sparopt" } sparopt = { version = "0.1.0-alpha.2", path = "lib/sparopt" }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -17,7 +17,7 @@ pub mod turtle;
pub use crate::n3::N3Parser; pub use crate::n3::N3Parser;
pub use crate::nquads::{NQuadsParser, NQuadsSerializer}; pub use crate::nquads::{NQuadsParser, NQuadsSerializer};
pub use crate::ntriples::{NTriplesParser, NTriplesSerializer}; 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::trig::{TriGParser, TriGSerializer};
pub use crate::turtle::{TurtleParser, TurtleSerializer}; pub use crate::turtle::{TurtleParser, TurtleSerializer};

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

@ -4,7 +4,7 @@
use crate::line_formats::NQuadsRecognizer; use crate::line_formats::NQuadsRecognizer;
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator; use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError}; use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
use oxrdf::{Quad, QuadRef}; use oxrdf::{Quad, QuadRef};
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
@ -106,7 +106,7 @@ impl NQuadsParser {
/// use oxttl::NQuadsParser; /// use oxttl::NQuadsParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[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> . /// 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/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> . /// <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> { impl<R: Read> Iterator for FromReadNQuadsReader<R> {
type Item = Result<Quad, ParseError>; type Item = Result<Quad, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.inner.next() self.inner.next()
@ -228,7 +228,7 @@ impl<R: Read> Iterator for FromReadNQuadsReader<R> {
/// use oxttl::NQuadsParser; /// use oxttl::NQuadsParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[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> . /// 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/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> . /// <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")] #[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadNQuadsReader<R> { impl<R: AsyncRead + Unpin> FromTokioAsyncReadNQuadsReader<R> {
/// Reads the next triple or returns `None` if the file is finished. /// 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)) 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. /// 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). /// 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() self.parser.read_next()
} }
} }

@ -4,7 +4,7 @@
use crate::line_formats::NQuadsRecognizer; use crate::line_formats::NQuadsRecognizer;
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator; use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError}; use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
use oxrdf::{Triple, TripleRef}; use oxrdf::{Triple, TripleRef};
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
@ -106,7 +106,7 @@ impl NTriplesParser {
/// use oxttl::NTriplesParser; /// use oxttl::NTriplesParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[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> . /// 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/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> . /// <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> { impl<R: Read> Iterator for FromReadNTriplesReader<R> {
type Item = Result<Triple, ParseError>; type Item = Result<Triple, TurtleParseError>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.map(Into::into)) Some(self.inner.next()?.map(Into::into))
@ -228,7 +228,7 @@ impl<R: Read> Iterator for FromReadNTriplesReader<R> {
/// use oxttl::NTriplesParser; /// use oxttl::NTriplesParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[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> . /// 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/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> . /// <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")] #[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadNTriplesReader<R> { impl<R: AsyncRead + Unpin> FromTokioAsyncReadNTriplesReader<R> {
/// Reads the next triple or returns `None` if the file is finished. /// 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)) 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. /// 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). /// 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)) 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. /// It is composed of a message and a byte range in the input.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub struct SyntaxError { pub struct TurtleSyntaxError {
pub(super) location: Range<TextPosition>, pub(super) location: Range<TextPosition>,
pub(super) message: String, pub(super) message: String,
} }
impl SyntaxError { impl TurtleSyntaxError {
/// The location of the error inside of the file. /// The location of the error inside of the file.
#[inline] #[inline]
pub fn location(&self) -> Range<TextPosition> { pub fn location(&self) -> Range<TextPosition> {
@ -32,7 +32,7 @@ impl SyntaxError {
} }
} }
impl fmt::Display for SyntaxError { impl fmt::Display for TurtleSyntaxError {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.location.start.offset + 1 >= self.location.end.offset { 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] #[inline]
fn from(error: SyntaxError) -> Self { fn from(error: TurtleSyntaxError) -> Self {
Self::new(io::ErrorKind::InvalidData, error) Self::new(io::ErrorKind::InvalidData, error)
} }
} }
/// A parsing 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)] #[derive(Debug, thiserror::Error)]
pub enum ParseError { pub enum TurtleParseError {
/// I/O error during parsing (file not found...). /// I/O error during parsing (file not found...).
#[error(transparent)] #[error(transparent)]
Io(#[from] io::Error), Io(#[from] io::Error),
/// An error in the file syntax. /// An error in the file syntax.
#[error(transparent)] #[error(transparent)]
Syntax(#[from] SyntaxError), Syntax(#[from] TurtleSyntaxError),
} }
impl From<ParseError> for io::Error { impl From<TurtleParseError> for io::Error {
#[inline] #[inline]
fn from(error: ParseError) -> Self { fn from(error: TurtleParseError) -> Self {
match error { match error {
ParseError::Syntax(e) => e.into(), TurtleParseError::Syntax(e) => e.into(),
ParseError::Io(e) => e, 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 memchr::{memchr2, memchr2_iter};
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp::min; use std::cmp::min;
@ -163,7 +163,10 @@ impl<R: TokenRecognizer> Lexer<R> {
} }
#[allow(clippy::unwrap_in_result)] #[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.skip_whitespaces_and_comments()?;
self.previous_position = self.position; self.previous_position = self.position;
let Some((consumed, result)) = self.parser.recognize_next_token( let Some((consumed, result)) = self.parser.recognize_next_token(
@ -194,7 +197,7 @@ impl<R: TokenRecognizer> Lexer<R> {
), ),
offset: self.position.global_offset, offset: self.position.global_offset,
}; };
let error = SyntaxError { let error = TurtleSyntaxError {
location: new_position..new_position, location: new_position..new_position,
message: "Unexpected end of file".into(), message: "Unexpected end of file".into(),
}; };
@ -224,7 +227,7 @@ impl<R: TokenRecognizer> Lexer<R> {
self.position.buffer_offset += consumed; self.position.buffer_offset += consumed;
self.position.global_offset += u64::try_from(consumed).unwrap(); self.position.global_offset += u64::try_from(consumed).unwrap();
self.position.global_line += new_line_jumps; 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), location: self.location_from_buffer_offset_range(e.location),
message: e.message, message: e.message,
})) }))

@ -6,7 +6,7 @@ mod error;
mod lexer; mod lexer;
mod parser; mod parser;
pub use self::error::{ParseError, SyntaxError, TextPosition}; pub use self::error::{TextPosition, TurtleParseError, TurtleSyntaxError};
pub use self::lexer::{Lexer, TokenRecognizer, TokenRecognizerError}; pub use self::lexer::{Lexer, TokenRecognizer, TokenRecognizerError};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
pub use self::parser::FromTokioAsyncReadIterator; 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 crate::toolkit::lexer::{Lexer, TokenRecognizer};
use std::io::Read; use std::io::Read;
#[cfg(feature = "async-tokio")] #[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() 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 { loop {
if let Some(error) = self.errors.pop() { if let Some(error) = self.errors.pop() {
return Some(Err(SyntaxError { return Some(Err(TurtleSyntaxError {
location: self.lexer.last_token_location(), location: self.lexer.last_token_location(),
message: error message: error
.message .message
@ -141,12 +141,12 @@ pub struct FromReadIterator<R: Read, RR: RuleRecognizer> {
} }
impl<R: Read, RR: RuleRecognizer> Iterator for FromReadIterator<R, RR> { 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> { fn next(&mut self) -> Option<Self::Item> {
while !self.parser.is_end() { while !self.parser.is_end() {
if let Some(result) = self.parser.read_next() { 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) { if let Err(e) = self.parser.lexer.extend_from_read(&mut self.read) {
return Some(Err(e.into())); return Some(Err(e.into()));
@ -164,10 +164,10 @@ pub struct FromTokioAsyncReadIterator<R: AsyncRead + Unpin, RR: RuleRecognizer>
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin, RR: RuleRecognizer> FromTokioAsyncReadIterator<R, RR> { 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() { while !self.parser.is_end() {
if let Some(result) = self.parser.read_next() { 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 if let Err(e) = self
.parser .parser

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

@ -4,7 +4,7 @@
use crate::terse::TriGRecognizer; use crate::terse::TriGRecognizer;
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use crate::toolkit::FromTokioAsyncReadIterator; use crate::toolkit::FromTokioAsyncReadIterator;
use crate::toolkit::{FromReadIterator, ParseError, Parser, SyntaxError}; use crate::toolkit::{FromReadIterator, Parser, TurtleParseError, TurtleSyntaxError};
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
use crate::trig::ToTokioAsyncWriteTriGWriter; use crate::trig::ToTokioAsyncWriteTriGWriter;
use crate::trig::{LowLevelTriGWriter, ToWriteTriGWriter, TriGSerializer}; use crate::trig::{LowLevelTriGWriter, ToWriteTriGWriter, TriGSerializer};
@ -138,7 +138,7 @@ impl TurtleParser {
/// use oxttl::TurtleParser; /// use oxttl::TurtleParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> { /// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> . /// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> . /// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ; /// <foo> a schema:Person ;
@ -312,7 +312,7 @@ impl<R: Read> FromReadTurtleReader<R> {
} }
impl<R: Read> Iterator for 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> { fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.map(Into::into)) Some(self.inner.next()?.map(Into::into))
@ -328,7 +328,7 @@ impl<R: Read> Iterator for FromReadTurtleReader<R> {
/// use oxttl::TurtleParser; /// use oxttl::TurtleParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> { /// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> . /// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> . /// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ; /// <foo> a schema:Person ;
@ -358,7 +358,7 @@ pub struct FromTokioAsyncReadTurtleReader<R: AsyncRead + Unpin> {
#[cfg(feature = "async-tokio")] #[cfg(feature = "async-tokio")]
impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> { impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// Reads the next triple or returns `None` if the file is finished. /// 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)) Some(self.inner.next().await?.map(Into::into))
} }
@ -372,7 +372,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// use oxttl::TurtleParser; /// use oxttl::TurtleParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> { /// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> . /// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> . /// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ; /// <foo> a schema:Person ;
@ -401,7 +401,7 @@ impl<R: AsyncRead + Unpin> FromTokioAsyncReadTurtleReader<R> {
/// use oxttl::TurtleParser; /// use oxttl::TurtleParser;
/// ///
/// # #[tokio::main(flavor = "current_thread")] /// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() -> Result<(), oxttl::ParseError> { /// # async fn main() -> Result<(), oxttl::TurtleParseError> {
/// let file = br#"@base <http://example.com/> . /// let file = br#"@base <http://example.com/> .
/// @prefix schema: <http://schema.org/> . /// @prefix schema: <http://schema.org/> .
/// <foo> a schema:Person ; /// <foo> a schema:Person ;
@ -490,7 +490,7 @@ impl LowLevelTurtleReader {
/// ///
/// Returns [`None`] if the parsing is finished or more data is required. /// 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). /// 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)) 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/) //! 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 memchr::memchr;
use oxrdf::vocab::xsd; use oxrdf::vocab::xsd;
use oxrdf::*; use oxrdf::*;
@ -432,7 +434,7 @@ pub enum TsvQueryResultsReader<R: Read> {
} }
impl<R: Read> TsvQueryResultsReader<R> { 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 reader = LineReader::new();
let mut buffer = Vec::new(); let mut buffer = Vec::new();
@ -451,13 +453,13 @@ impl<R: Read> TsvQueryResultsReader<R> {
for v in line.split('\t') { for v in line.split('\t') {
let v = v.trim(); let v = v.trim();
if v.is_empty() { 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| { 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) { if variables.contains(&variable) {
return Err(SyntaxError::msg(format!( return Err(QueryResultsSyntaxError::msg(format!(
"The variable {variable} is declared twice" "The variable {variable} is declared twice"
)) ))
.into()); .into());
@ -487,7 +489,7 @@ pub struct TsvSolutionsReader<R: Read> {
impl<R: Read> TsvSolutionsReader<R> { impl<R: Read> TsvSolutionsReader<R> {
#[allow(clippy::unwrap_in_result)] #[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)?; let line = self.reader.next_line(&mut self.buffer, &mut self.read)?;
if line.is_empty() { if line.is_empty() {
return Ok(None); // EOF return Ok(None); // EOF
@ -508,35 +510,33 @@ impl<R: Read> TsvSolutionsReader<R> {
.sum::<usize>(); .sum::<usize>();
let start_position_bytes = let start_position_bytes =
line.split('\t').take(i).map(|c| c.len() + 1).sum::<usize>(); line.split('\t').take(i).map(|c| c.len() + 1).sum::<usize>();
SyntaxError { QueryResultsSyntaxError(SyntaxErrorKind::Term {
inner: SyntaxErrorKind::Term { error: e,
error: e, term: v.into(),
term: v.into(), location: TextPosition {
location: TextPosition { line: self.reader.line_count - 1,
line: self.reader.line_count - 1, column: start_position_char.try_into().unwrap(),
column: start_position_char.try_into().unwrap(), offset: self.reader.last_line_start
offset: self.reader.last_line_start + u64::try_from(start_position_bytes).unwrap(),
+ u64::try_from(start_position_bytes).unwrap(), }..TextPosition {
}..TextPosition { line: self.reader.line_count - 1,
line: self.reader.line_count - 1, column: (start_position_char + v.chars().count())
column: (start_position_char + v.chars().count()) .try_into()
.try_into() .unwrap(),
.unwrap(), offset: self.reader.last_line_start
offset: self.reader.last_line_start + u64::try_from(start_position_bytes + v.len()).unwrap(),
+ u64::try_from(start_position_bytes + v.len()).unwrap(),
},
}, },
} })
})?)) })?))
} }
}) })
.collect::<Result<Vec<_>, ParseError>>()?; .collect::<Result<Vec<_>, QueryResultsParseError>>()?;
if elements.len() == self.column_len { if elements.len() == self.column_len {
Ok(Some(elements)) Ok(Some(elements))
} else if self.column_len == 0 && elements == [None] { } else if self.column_len == 0 && elements == [None] {
Ok(Some(Vec::new())) // Zero columns case Ok(Some(Vec::new())) // Zero columns case
} else { } else {
Err(SyntaxError::located_message( Err(QueryResultsSyntaxError::located_message(
format!( format!(
"This TSV files has {} columns but we found a row on line {} with {} columns: {}", "This TSV files has {} columns but we found a row on line {} with {} columns: {}",
self.column_len, self.column_len,

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

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

@ -1,5 +1,5 @@
use crate::csv::{TsvQueryResultsReader, TsvSolutionsReader}; use crate::csv::{TsvQueryResultsReader, TsvSolutionsReader};
use crate::error::{ParseError, SyntaxError}; use crate::error::{QueryResultsParseError, QueryResultsSyntaxError};
use crate::format::QueryResultsFormat; use crate::format::QueryResultsFormat;
use crate::json::{JsonQueryResultsReader, JsonSolutionsReader}; use crate::json::{JsonQueryResultsReader, JsonSolutionsReader};
use crate::solution::QuerySolution; 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())]); /// 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 { pub struct QueryResultsParser {
format: QueryResultsFormat, format: QueryResultsFormat,
@ -68,12 +68,12 @@ impl QueryResultsParser {
/// assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new_unchecked("foo"), &Literal::from("test").into())]); /// 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>( pub fn parse_read<R: Read>(
&self, &self,
reader: R, reader: R,
) -> Result<FromReadQueryResultsReader<R>, ParseError> { ) -> Result<FromReadQueryResultsReader<R>, QueryResultsParseError> {
Ok(match self.format { Ok(match self.format {
QueryResultsFormat::Xml => match XmlQueryResultsReader::read(reader)? { QueryResultsFormat::Xml => match XmlQueryResultsReader::read(reader)? {
XmlQueryResultsReader::Boolean(r) => FromReadQueryResultsReader::Boolean(r), XmlQueryResultsReader::Boolean(r) => FromReadQueryResultsReader::Boolean(r),
@ -95,7 +95,7 @@ impl QueryResultsParser {
solutions: SolutionsReaderKind::Json(solutions), 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)? { QueryResultsFormat::Tsv => match TsvQueryResultsReader::read(reader)? {
TsvQueryResultsReader::Boolean(r) => FromReadQueryResultsReader::Boolean(r), TsvQueryResultsReader::Boolean(r) => FromReadQueryResultsReader::Boolean(r),
TsvQueryResultsReader::Solutions { TsvQueryResultsReader::Solutions {
@ -113,7 +113,7 @@ impl QueryResultsParser {
pub fn read_results<R: Read>( pub fn read_results<R: Read>(
&self, &self,
reader: R, reader: R,
) -> Result<FromReadQueryResultsReader<R>, ParseError> { ) -> Result<FromReadQueryResultsReader<R>, QueryResultsParseError> {
self.parse_read(reader) 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> { pub enum FromReadQueryResultsReader<R: Read> {
Solutions(FromReadSolutionsReader<R>), 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())]); /// 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> { pub struct FromReadSolutionsReader<R: Read> {
variables: Arc<[Variable]>, variables: Arc<[Variable]>,
@ -217,7 +217,7 @@ impl<R: Read> FromReadSolutionsReader<R> {
/// ] /// ]
/// ); /// );
/// } /// }
/// # Result::<(),sparesults::ParseError>::Ok(()) /// # Result::<(),sparesults::QueryResultsParseError>::Ok(())
/// ``` /// ```
#[inline] #[inline]
pub fn variables(&self) -> &[Variable] { pub fn variables(&self) -> &[Variable] {
@ -226,7 +226,7 @@ impl<R: Read> FromReadSolutionsReader<R> {
} }
impl<R: Read> Iterator for 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> { fn next(&mut self) -> Option<Self::Item> {
Some( Some(

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

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

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

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

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

@ -1,7 +1,7 @@
#![allow(clippy::needless_option_as_deref)] #![allow(clippy::needless_option_as_deref)]
use crate::model::{hash, PyQuad, PyTriple}; 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 oxigraph::model::QuadRef;
use pyo3::exceptions::{PyDeprecationWarning, PySyntaxError, PyValueError}; use pyo3::exceptions::{PyDeprecationWarning, PySyntaxError, PyValueError};
use pyo3::intern; use pyo3::intern;
@ -556,9 +556,9 @@ pub enum PyRdfFormatInput {
MediaType(String), 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 { match error {
ParseError::Syntax(error) => { RdfParseError::Syntax(error) => {
// Python 3.9 does not support end line and end column // Python 3.9 does not support end line and end column
if python_version() >= (3, 10) { if python_version() >= (3, 10) {
let params = if let Some(location) = error.location() { 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)) 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::io::RdfSerializer;
use oxigraph::model::Term; use oxigraph::model::Term;
use oxigraph::sparql::results::{ use oxigraph::sparql::results::{
FromReadQueryResultsReader, FromReadSolutionsReader, ParseError, QueryResultsFormat, FromReadQueryResultsReader, FromReadSolutionsReader, QueryResultsFormat,
QueryResultsParser, QueryResultsSerializer, QueryResultsParseError, QueryResultsParser, QueryResultsSerializer,
}; };
use oxigraph::sparql::{ use oxigraph::sparql::{
EvaluationError, Query, QueryResults, QuerySolution, QuerySolutionIter, QueryTripleIter, 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 { match error {
ParseError::Syntax(error) => { QueryResultsParseError::Syntax(error) => {
// Python 3.9 does not support end line and end column // Python 3.9 does not support end line and end column
if python_version() >= (3, 10) { if python_version() >= (3, 10) {
let params = if let Some(location) = error.location() { 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)) PySyntaxError::new_err((error.to_string(), params))
} }
} }
ParseError::Io(error) => error.into(), QueryResultsParseError::Io(error) => error.into(),
} }
} }

Loading…
Cancel
Save