Rule set parser

rules
Tpt 2 years ago
parent 1a4adfc02a
commit 8f94baedf6
  1. 1
      lib/spargebra/Cargo.toml
  2. 3
      lib/spargebra/src/lib.rs
  3. 37
      lib/spargebra/src/parser.rs
  4. 123
      lib/spargebra/src/rule.rs

@ -18,6 +18,7 @@ default = []
rdf-star = ["oxrdf/rdf-star"]
sep-0002 = []
sep-0006 = []
rules = []
[dependencies]
peg = "0.8"

@ -8,9 +8,12 @@
pub mod algebra;
mod parser;
mod query;
mod rule;
pub mod term;
mod update;
pub use parser::ParseError;
pub use query::*;
#[cfg(feature = "rules")]
pub use rule::*;
pub use update::*;

@ -1,5 +1,6 @@
use crate::algebra::*;
use crate::query::*;
use crate::rule::*;
use crate::term::*;
use crate::update::*;
use oxilangtag::LanguageTag;
@ -54,7 +55,7 @@ pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, Pars
};
let operations =
parser::UpdateInit(&unescape_unicode_codepoints(update), &mut state).map_err(|e| {
parser::UpdateUnit(&unescape_unicode_codepoints(update), &mut state).map_err(|e| {
ParseError {
inner: ParseErrorKind::Parser(e),
}
@ -65,6 +66,27 @@ pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, Pars
})
}
/// Parses a set of if/then rules with an optional base IRI to resolve relative IRIs in the rule.
pub fn parse_rule_set(rules: &str, base_iri: Option<&str>) -> Result<RuleSet, ParseError> {
let mut state = ParserState {
base_iri: if let Some(base_iri) = base_iri {
Some(Iri::parse(base_iri.to_owned()).map_err(|e| ParseError {
inner: ParseErrorKind::InvalidBaseIri(e),
})?)
} else {
None
},
namespaces: HashMap::default(),
used_bnodes: HashSet::default(),
currently_used_bnodes: HashSet::default(),
aggregates: Vec::new(),
};
parser::RuleSetUnit(&unescape_unicode_codepoints(rules), &mut state).map_err(|e| ParseError {
inner: ParseErrorKind::Parser(e),
})
}
/// Error returned during SPARQL parsing.
#[derive(Debug)]
pub struct ParseError {
@ -966,7 +988,7 @@ parser! {
}
//[3]
pub rule UpdateInit() -> Vec<GraphUpdateOperation> = Update()
pub rule UpdateUnit() -> Vec<GraphUpdateOperation> = Update()
//[4]
rule Prologue() = (BaseDecl() _ / PrefixDecl() _)* {}
@ -2445,5 +2467,16 @@ parser! {
Err(literal)
}
}
pub rule RuleSetUnit() -> RuleSet = RuleSet()
rule RuleSet() -> RuleSet = _ Prologue() _ rules:(Rule() ** (_ ";" _)) _ ( ";" _)? { RuleSet { rules } }
rule Rule() -> Rule = i("IF") _ body:ConstructTemplate() _ i("THEN") _ head:ConstructTemplate() {?
Ok(Rule {
body: GraphPattern::Bgp { patterns: body },
head: head.into_iter().map(GroundTriplePattern::try_from).collect::<Result<_, ()>>().map_err(|_| "Blank nodes are not allowed in rules head")?
})
}
}
}

@ -0,0 +1,123 @@
#![cfg_attr(not(feature = "rules"), allow(dead_code))]
use crate::algebra::*;
use crate::parser::{parse_rule_set, ParseError};
use crate::term::*;
use std::fmt;
use std::str::FromStr;
/// A parsed if/then rule set.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct RuleSet {
pub rules: Vec<Rule>,
}
impl RuleSet {
/// Parses a set of rules with an optional base IRI to resolve relative IRIs in the rules.
/// Note that this base IRI will not be used during execution.
pub fn parse(rules: &str, base_iri: Option<&str>) -> Result<Self, ParseError> {
parse_rule_set(rules, base_iri)
}
/// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
pub fn to_sse(&self) -> String {
let mut buffer = String::new();
self.fmt_sse(&mut buffer)
.expect("Unexpected error during SSE formatting");
buffer
}
/// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
write!(f, "(")?;
for (i, r) in self.rules.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
r.fmt_sse(f)?;
}
write!(f, ") ")
}
}
impl fmt::Display for RuleSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for r in &self.rules {
writeln!(f, "{r} ;")?;
}
Ok(())
}
}
impl FromStr for RuleSet {
type Err = ParseError;
fn from_str(rules: &str) -> Result<Self, ParseError> {
Self::parse(rules, None)
}
}
impl<'a> TryFrom<&'a str> for RuleSet {
type Error = ParseError;
fn try_from(rules: &str) -> Result<Self, ParseError> {
Self::from_str(rules)
}
}
impl<'a> TryFrom<&'a String> for RuleSet {
type Error = ParseError;
fn try_from(rules: &String) -> Result<Self, ParseError> {
Self::from_str(rules)
}
}
/// A parsed if/then rule.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct Rule {
/// The construction template.
pub head: Vec<GroundTriplePattern>,
/// The rule body graph pattern.
pub body: GraphPattern,
}
impl Rule {
/// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
pub fn to_sse(&self) -> String {
let mut buffer = String::new();
self.fmt_sse(&mut buffer)
.expect("Unexpected error during SSE formatting");
buffer
}
/// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
write!(f, "(rule (")?;
for (i, t) in self.head.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
t.fmt_sse(f)?;
}
write!(f, ") ")?;
self.body.fmt_sse(f)?;
write!(f, ")")
}
}
impl fmt::Display for Rule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"IF {{ {} }} THEN {{ ",
SparqlGraphRootPattern {
pattern: &self.body,
dataset: None
}
)?;
for triple in self.head.iter() {
write!(f, "{triple} . ")?;
}
write!(f, "}}")
}
}
Loading…
Cancel
Save