Makes SPARQL-star optional in the SPARQL parser

pull/171/head
Tpt 3 years ago
parent 2067be1a0e
commit 25e192095e
  1. 2
      lib/Cargo.toml
  2. 7
      spargebra/Cargo.toml
  3. 4
      spargebra/README.md
  4. 26
      spargebra/src/algebra.rs
  5. 2
      spargebra/src/lib.rs
  6. 89
      spargebra/src/parser.rs
  7. 26
      spargebra/src/term.rs

@ -44,7 +44,7 @@ http = "0.2"
httparse = { version = "1", optional = true }
native-tls = { version = "0.2", optional = true }
json-event-parser = "0.1"
spargebra = { version = "0.1", path="../spargebra" }
spargebra = { version = "0.1", path="../spargebra", features = ["rdf-star"] }
[dev-dependencies]

@ -12,8 +12,15 @@ A SPARQL parser
"""
edition = "2018"
[features]
default = []
rdf-star = []
[dependencies]
peg = "0.7"
rand = "0.8"
oxiri = "0.1"
oxilangtag = "0.1"
[package.metadata.docs.rs]
all-features = true

@ -9,7 +9,9 @@ Spargebra
Spargebra is a [SPARQL](https://www.w3.org/TR/sparql11-overview/) parser.
It supports [SPARQL 1.1 Query](https://www.w3.org/TR/sparql11-query/), [SPARQL 1.1 Update](https://www.w3.org/TR/sparql11-update/) and [SPARQL-star](https://w3c.github.io/rdf-star/cg-spec/).
It supports [SPARQL 1.1 Query](https://www.w3.org/TR/sparql11-query/) and [SPARQL 1.1 Update](https://www.w3.org/TR/sparql11-update/).
Support for [SPARQL-star](https://w3c.github.io/rdf-star/cg-spec/#sparql-star) is also available behind the `rdf-star` feature.
This crate is intended to be a building piece for SPARQL implementations in Rust like [Oxigraph](https://oxigraph.org).

@ -361,10 +361,15 @@ pub enum Function {
IsLiteral,
IsNumeric,
Regex,
#[cfg(feature = "rdf-star")]
Triple,
#[cfg(feature = "rdf-star")]
Subject,
#[cfg(feature = "rdf-star")]
Predicate,
#[cfg(feature = "rdf-star")]
Object,
#[cfg(feature = "rdf-star")]
IsTriple,
Custom(NamedNode),
}
@ -418,10 +423,15 @@ impl fmt::Display for Function {
Function::IsLiteral => write!(f, "isLITERAL"),
Function::IsNumeric => write!(f, "isNUMERIC"),
Function::Regex => write!(f, "REGEX"),
#[cfg(feature = "rdf-star")]
Function::Triple => write!(f, "TRIPLE"),
#[cfg(feature = "rdf-star")]
Function::Subject => write!(f, "SUBJECT"),
#[cfg(feature = "rdf-star")]
Function::Predicate => write!(f, "PREDICATE"),
#[cfg(feature = "rdf-star")]
Function::Object => write!(f, "OBJECT"),
#[cfg(feature = "rdf-star")]
Function::IsTriple => write!(f, "isTRIPLE"),
Function::Custom(iri) => iri.fmt(f),
}
@ -656,12 +666,16 @@ impl GraphPattern {
} => {
if let TermPattern::Variable(s) = subject {
vars.insert(s);
} else if let TermPattern::Triple(s) = subject {
}
#[cfg(feature = "rdf-star")]
if let TermPattern::Triple(s) = subject {
add_triple_pattern_variables(s, vars)
}
if let TermPattern::Variable(o) = object {
vars.insert(o);
} else if let TermPattern::Triple(o) = object {
}
#[cfg(feature = "rdf-star")]
if let TermPattern::Triple(o) = object {
add_triple_pattern_variables(o, vars)
}
}
@ -703,7 +717,9 @@ impl GraphPattern {
fn add_triple_pattern_variables<'a>(pattern: &'a TriplePattern, vars: &mut BTreeSet<&'a Variable>) {
if let TermPattern::Variable(s) = &pattern.subject {
vars.insert(s);
} else if let TermPattern::Triple(s) = &pattern.subject {
}
#[cfg(feature = "rdf-star")]
if let TermPattern::Triple(s) = &pattern.subject {
add_triple_pattern_variables(s, vars)
}
if let NamedNodePattern::Variable(p) = &pattern.predicate {
@ -711,7 +727,9 @@ fn add_triple_pattern_variables<'a>(pattern: &'a TriplePattern, vars: &mut BTree
}
if let TermPattern::Variable(o) = &pattern.object {
vars.insert(o);
} else if let TermPattern::Triple(o) = &pattern.object {
}
#[cfg(feature = "rdf-star")]
if let TermPattern::Triple(o) = &pattern.object {
add_triple_pattern_variables(o, vars)
}
}

@ -5,6 +5,8 @@
//!
//! This crate is intended to be a building piece for SPARQL implementations in Rust like [Oxigraph](https://oxigraph.org).
//!
//! Support for [SPARQL-star](https://w3c.github.io/rdf-star/cg-spec/) is available behind the `rdf-star` feature.
//!
//! Usage example:
//! ```
//! use spargebra::Query;

@ -150,14 +150,20 @@ fn add_to_triple_patterns(
predicate: NamedNodePattern,
object: AnnotatedTerm,
patterns: &mut Vec<TriplePattern>,
) {
) -> Result<(), &'static str> {
let triple = TriplePattern::new(subject, predicate, object.term);
#[cfg(feature = "rdf-star")]
for (p, os) in object.annotations {
for o in os {
add_to_triple_patterns(triple.clone().into(), p.clone(), o, patterns)
add_to_triple_patterns(triple.clone().into(), p.clone(), o, patterns)?
}
}
patterns.push(triple)
#[cfg(not(feature = "rdf-star"))]
if !object.annotations.is_empty() {
return Err("Embedded triples are only available in SPARQL-star");
}
patterns.push(triple);
Ok(())
}
fn add_to_triple_or_path_patterns(
@ -229,11 +235,16 @@ fn add_triple_to_triple_or_path_patterns(
patterns: &mut Vec<TripleOrPathPattern>,
) -> Result<(), &'static str> {
let triple = TriplePattern::new(subject, predicate, object.term);
#[cfg(feature = "rdf-star")]
for (p, os) in object.annotations {
for o in os {
add_to_triple_or_path_patterns(triple.clone().into(), p.clone(), o, patterns)?
}
}
#[cfg(not(feature = "rdf-star"))]
if !object.annotations.is_empty() {
return Err("Embedded triples are only available in SPARQL-star");
}
patterns.push(triple.into());
Ok(())
}
@ -1115,7 +1126,7 @@ parser! {
//[40]
rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadPattern() {?
let pattern = d.iter().map(|q| {
let pattern = d.iter().map(|q| {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]);
match &q.graph_name {
GraphNamePattern::NamedNode(graph_name) => GraphPattern::Graph { graph_name: graph_name.clone().into(), inner: Box::new(bgp) },
@ -1384,7 +1395,10 @@ parser! {
//[65]
rule DataBlockValue() -> Option<GroundTerm> =
t:EmbTriple() { Some(t.into()) } /
t:EmbTriple() {?
#[cfg(feature = "rdf-star")]{Ok(Some(t.into()))}
#[cfg(not(feature = "rdf-star"))]{Err("Embedded triples are only available in SPARQL-star")}
} /
i:iri() { Some(i.into()) } /
l:RDFLiteral() { Some(l.into()) } /
l:NumericLiteral() { Some(l.into()) } /
@ -1440,24 +1454,24 @@ parser! {
//[75]
rule TriplesSameSubject() -> Vec<TriplePattern> =
s:VarOrTermOrEmbTP() _ po:PropertyListNotEmpty() {
s:VarOrTermOrEmbTP() _ po:PropertyListNotEmpty() {?
let mut patterns = po.patterns;
for (p, os) in po.focus {
for o in os {
add_to_triple_patterns(s.clone(), p.clone(), o, &mut patterns)
add_to_triple_patterns(s.clone(), p.clone(), o, &mut patterns)?
}
}
patterns
Ok(patterns)
} /
s:TriplesNode() _ po:PropertyList() {
s:TriplesNode() _ po:PropertyList() {?
let mut patterns = s.patterns;
patterns.extend(po.patterns);
for (p, os) in po.focus {
for o in os {
add_to_triple_patterns(s.focus.clone(), p.clone(), o, &mut patterns)
add_to_triple_patterns(s.focus.clone(), p.clone(), o, &mut patterns)?
}
}
patterns
Ok(patterns)
}
//[76]
@ -1686,18 +1700,18 @@ parser! {
rule TriplesNode() -> FocusedTriplePattern<TermPattern> = Collection() / BlankNodePropertyList()
//[99]
rule BlankNodePropertyList() -> FocusedTriplePattern<TermPattern> = "[" _ po:PropertyListNotEmpty() _ "]" {
rule BlankNodePropertyList() -> FocusedTriplePattern<TermPattern> = "[" _ po:PropertyListNotEmpty() _ "]" {?
let mut patterns = po.patterns;
let mut bnode = TermPattern::from(bnode());
for (p, os) in po.focus {
for o in os {
add_to_triple_patterns(bnode.clone(), p.clone(), o, &mut patterns)
add_to_triple_patterns(bnode.clone(), p.clone(), o, &mut patterns)?;
}
}
FocusedTriplePattern {
Ok(FocusedTriplePattern {
focus: bnode,
patterns
}
})
}
//[100]
@ -1926,11 +1940,26 @@ parser! {
RegexExpression() /
ExistsFunc() /
NotExistsFunc() /
i("TRIPLE") "(" _ s:Expression() _ "," _ p:Expression() "," _ o:Expression() ")" { Expression::FunctionCall(Function::Triple, vec![s, p, o]) } /
i("SUBJECT") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::Subject, vec![e]) } /
i("PREDICATE") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::Predicate, vec![e]) } /
i("OBJECT") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::Object, vec![e]) } /
i("isTriple") "(" _ e:Expression() _ ")" { Expression::FunctionCall(Function::IsTriple, vec![e]) }
i("TRIPLE") "(" _ s:Expression() _ "," _ p:Expression() "," _ o:Expression() ")" {?
#[cfg(feature = "rdf-star")]{Ok(Expression::FunctionCall(Function::Triple, vec![s, p, o]))}
#[cfg(not(feature = "rdf-star"))]{Err("The TRIPLE function is only available in SPARQL-star")}
} /
i("SUBJECT") "(" _ e:Expression() _ ")" {?
#[cfg(feature = "rdf-star")]{Ok(Expression::FunctionCall(Function::Subject, vec![e]))}
#[cfg(not(feature = "rdf-star"))]{Err("The SUBJECT function is only available in SPARQL-star")}
} /
i("PREDICATE") "(" _ e:Expression() _ ")" {?
#[cfg(feature = "rdf-star")]{Ok(Expression::FunctionCall(Function::Predicate, vec![e]))}
#[cfg(not(feature = "rdf-star"))]{Err("The PREDICATE function is only available in SPARQL-star")}
} /
i("OBJECT") "(" _ e:Expression() _ ")" {?
#[cfg(feature = "rdf-star")]{Ok(Expression::FunctionCall(Function::Object, vec![e]))}
#[cfg(not(feature = "rdf-star"))]{Err("The OBJECT function is only available in SPARQL-star")}
} /
i("isTriple") "(" _ e:Expression() _ ")" {?
#[cfg(feature = "rdf-star")]{Ok(Expression::FunctionCall(Function::IsTriple, vec![e]))}
#[cfg(not(feature = "rdf-star"))]{Err("The isTriple function is only available in SPARQL-star")}
}
//[122]
rule RegexExpression() -> Expression =
@ -2198,7 +2227,10 @@ parser! {
//[176]
rule EmbSubjectOrObject() -> TermPattern =
t:EmbTP() { t.into() } /
t:EmbTP() {?
#[cfg(feature = "rdf-star")]{Ok(t.into())}
#[cfg(not(feature = "rdf-star"))]{Err("Embedded triple patterns are only available in SPARQL-star")}
} /
v:Var() { v.into() } /
b:BlankNode() { b.into() } /
i:iri() { i.into() } /
@ -2211,11 +2243,17 @@ parser! {
l:RDFLiteral() { l.into() } /
l:NumericLiteral() { l.into() } /
l:BooleanLiteral() { l.into() } /
t:EmbTriple() { t.into() }
t:EmbTriple() {?
#[cfg(feature = "rdf-star")]{Ok(t.into())}
#[cfg(not(feature = "rdf-star"))]{Err("Embedded triples are only available in SPARQL-star")}
}
//[178]
rule VarOrTermOrEmbTP() -> TermPattern =
t:EmbTP() { t.into() } /
t:EmbTP() {?
#[cfg(feature = "rdf-star")]{Ok(t.into())}
#[cfg(not(feature = "rdf-star"))]{Err("Embedded triple patterns are only available in SPARQL-star")}
} /
v:Var() { v.into() } /
t:GraphTerm() { t.into() }
@ -2226,8 +2264,9 @@ parser! {
rule AnnotationPatternPath() -> FocusedTripleOrPathPattern<Vec<(VariableOrPropertyPath,Vec<AnnotatedTermPath>)>> = "{|" _ a: PropertyListPathNotEmpty() _ "|}" { a }
//[181]
rule ExprEmbTP() -> Expression = "<<" _ s:ExprVarOrTerm() _ p:Verb() _ o:ExprVarOrTerm() _ ">>" {
Expression::FunctionCall(Function::Triple, vec![s, p.into(), o])
rule ExprEmbTP() -> Expression = "<<" _ s:ExprVarOrTerm() _ p:Verb() _ o:ExprVarOrTerm() _ ">>" {?
#[cfg(feature = "rdf-star")]{Ok(Expression::FunctionCall(Function::Triple, vec![s, p.into(), o]))}
#[cfg(not(feature = "rdf-star"))]{Err("Embedded triples are only available in SPARQL-star")}
}
//[182]

@ -139,6 +139,7 @@ impl fmt::Display for Literal {
pub enum Subject {
NamedNode(NamedNode),
BlankNode(BlankNode),
#[cfg(feature = "rdf-star")]
Triple(Box<Triple>),
}
@ -148,6 +149,7 @@ impl fmt::Display for Subject {
match self {
Self::NamedNode(node) => node.fmt(f),
Self::BlankNode(node) => node.fmt(f),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => write!(
f,
"<<{} {} {}>>",
@ -171,6 +173,7 @@ impl From<BlankNode> for Subject {
}
}
#[cfg(feature = "rdf-star")]
impl From<Triple> for Subject {
#[inline]
fn from(triple: Triple) -> Self {
@ -186,6 +189,7 @@ impl TryFrom<TermPattern> for Subject {
match term {
TermPattern::NamedNode(t) => Ok(t.into()),
TermPattern::BlankNode(t) => Ok(t.into()),
#[cfg(feature = "rdf-star")]
TermPattern::Triple(t) => Ok(Triple::try_from(*t)?.into()),
TermPattern::Literal(_) | TermPattern::Variable(_) => Err(()),
}
@ -198,6 +202,7 @@ impl TryFrom<TermPattern> for Subject {
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GroundSubject {
NamedNode(NamedNode),
#[cfg(feature = "rdf-star")]
Triple(Box<GroundTriple>),
}
@ -206,6 +211,7 @@ impl fmt::Display for GroundSubject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NamedNode(node) => node.fmt(f),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => write!(
f,
"<<{} {} {}>>",
@ -222,6 +228,7 @@ impl From<NamedNode> for GroundSubject {
}
}
#[cfg(feature = "rdf-star")]
impl From<GroundTriple> for GroundSubject {
#[inline]
fn from(triple: GroundTriple) -> Self {
@ -237,6 +244,7 @@ impl TryFrom<Subject> for GroundSubject {
match subject {
Subject::NamedNode(t) => Ok(t.into()),
Subject::BlankNode(_) => Err(()),
#[cfg(feature = "rdf-star")]
Subject::Triple(t) => Ok(GroundTriple::try_from(*t)?.into()),
}
}
@ -250,6 +258,7 @@ impl TryFrom<GroundTerm> for GroundSubject {
match term {
GroundTerm::NamedNode(t) => Ok(t.into()),
GroundTerm::Literal(_) => Err(()),
#[cfg(feature = "rdf-star")]
GroundTerm::Triple(t) => Ok((*t).into()),
}
}
@ -265,6 +274,7 @@ pub enum Term {
NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
#[cfg(feature = "rdf-star")]
Triple(Box<Triple>),
}
@ -275,6 +285,7 @@ impl fmt::Display for Term {
Self::NamedNode(node) => node.fmt(f),
Self::BlankNode(node) => node.fmt(f),
Self::Literal(literal) => literal.fmt(f),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => write!(
f,
"<<{} {} {}>>",
@ -305,6 +316,7 @@ impl From<Literal> for Term {
}
}
#[cfg(feature = "rdf-star")]
impl From<Triple> for Term {
#[inline]
fn from(triple: Triple) -> Self {
@ -318,6 +330,7 @@ impl From<Subject> for Term {
match resource {
Subject::NamedNode(node) => node.into(),
Subject::BlankNode(node) => node.into(),
#[cfg(feature = "rdf-star")]
Subject::Triple(t) => (*t).into(),
}
}
@ -332,6 +345,7 @@ impl TryFrom<TermPattern> for Term {
TermPattern::NamedNode(t) => Ok(t.into()),
TermPattern::BlankNode(t) => Ok(t.into()),
TermPattern::Literal(t) => Ok(t.into()),
#[cfg(feature = "rdf-star")]
TermPattern::Triple(t) => Ok(Triple::try_from(*t)?.into()),
TermPattern::Variable(_) => Err(()),
}
@ -345,6 +359,7 @@ impl TryFrom<TermPattern> for Term {
pub enum GroundTerm {
NamedNode(NamedNode),
Literal(Literal),
#[cfg(feature = "rdf-star")]
Triple(Box<GroundTriple>),
}
@ -354,6 +369,7 @@ impl fmt::Display for GroundTerm {
match self {
Self::NamedNode(node) => node.fmt(f),
Self::Literal(literal) => literal.fmt(f),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => write!(
f,
"<<{} {} {}>>",
@ -377,6 +393,7 @@ impl From<Literal> for GroundTerm {
}
}
#[cfg(feature = "rdf-star")]
impl From<GroundTriple> for GroundTerm {
#[inline]
fn from(triple: GroundTriple) -> Self {
@ -393,6 +410,7 @@ impl TryFrom<Term> for GroundTerm {
Term::NamedNode(t) => Ok(t.into()),
Term::BlankNode(_) => Err(()),
Term::Literal(t) => Ok(t.into()),
#[cfg(feature = "rdf-star")]
Term::Triple(t) => Ok(GroundTriple::try_from(*t)?.into()),
}
}
@ -694,6 +712,7 @@ pub enum TermPattern {
NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
#[cfg(feature = "rdf-star")]
Triple(Box<TriplePattern>),
Variable(Variable),
}
@ -705,6 +724,7 @@ impl fmt::Display for TermPattern {
Self::NamedNode(term) => term.fmt(f),
Self::BlankNode(term) => term.fmt(f),
Self::Literal(term) => term.fmt(f),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => write!(f, "<<{}>>", triple),
Self::Variable(var) => var.fmt(f),
}
@ -732,6 +752,7 @@ impl From<Literal> for TermPattern {
}
}
#[cfg(feature = "rdf-star")]
impl From<TriplePattern> for TermPattern {
#[inline]
fn from(triple: TriplePattern) -> Self {
@ -751,6 +772,7 @@ impl From<Subject> for TermPattern {
match subject {
Subject::NamedNode(node) => node.into(),
Subject::BlankNode(node) => node.into(),
#[cfg(feature = "rdf-star")]
Subject::Triple(t) => TriplePattern::from(*t).into(),
}
}
@ -763,6 +785,7 @@ impl From<Term> for TermPattern {
Term::NamedNode(node) => node.into(),
Term::BlankNode(node) => node.into(),
Term::Literal(literal) => literal.into(),
#[cfg(feature = "rdf-star")]
Term::Triple(t) => TriplePattern::from(*t).into(),
}
}
@ -832,6 +855,7 @@ impl From<GroundSubject> for GroundTermPattern {
fn from(term: GroundSubject) -> Self {
match term {
GroundSubject::NamedNode(node) => node.into(),
#[cfg(feature = "rdf-star")]
GroundSubject::Triple(triple) => GroundTriplePattern::from(*triple).into(),
}
}
@ -842,6 +866,7 @@ impl From<GroundTerm> for GroundTermPattern {
match term {
GroundTerm::NamedNode(node) => node.into(),
GroundTerm::Literal(literal) => literal.into(),
#[cfg(feature = "rdf-star")]
GroundTerm::Triple(triple) => GroundTriplePattern::from(*triple).into(),
}
}
@ -866,6 +891,7 @@ impl TryFrom<TermPattern> for GroundTermPattern {
TermPattern::NamedNode(named_node) => named_node.into(),
TermPattern::BlankNode(_) => return Err(()),
TermPattern::Literal(literal) => literal.into(),
#[cfg(feature = "rdf-star")]
TermPattern::Triple(triple) => GroundTriplePattern::try_from(*triple)?.into(),
TermPattern::Variable(variable) => variable.into(),
})

Loading…
Cancel
Save