diff --git a/Cargo.lock b/Cargo.lock index 7ffb70aa..6c0309fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,15 @@ version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +[[package]] +name = "arbitrary" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "assert_cmd" version = "2.0.6" @@ -414,6 +423,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_arbitrary" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "difflib" version = "0.4.0" @@ -1587,6 +1607,13 @@ dependencies = [ "rand", ] +[[package]] +name = "sparql-smith" +version = "0.1.0-alpha.1" +dependencies = [ + "arbitrary", +] + [[package]] name = "spin" version = "0.5.2" diff --git a/Cargo.toml b/Cargo.toml index 0d4beeeb..f7e74791 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "lib/oxrdf", "lib/spargebra", "lib/sparesults", + "lib/sparql-smith", "python", "oxrocksdb-sys", "server", diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 18ca4657..2518ec4c 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -9,12 +9,19 @@ edition = "2021" cargo-fuzz = true [dependencies] +lazy_static = "1" libfuzzer-sys = "0.4" spargebra = { path = "../lib/spargebra", features = ["rdf-star"] } sparesults = { path = "../lib/sparesults", features = ["rdf-star"] } +sparql-smith = { path = "../lib/sparql-smith" } +oxigraph = { path = "../lib" } [workspace] +[[bin]] +name = "sparql_eval" +path = "fuzz_targets/sparql_eval.rs" + [[bin]] name = "sparql_query" path = "fuzz_targets/sparql_query.rs" diff --git a/fuzz/fuzz_targets/sparql_eval.rs b/fuzz/fuzz_targets/sparql_eval.rs new file mode 100644 index 00000000..40c32d15 --- /dev/null +++ b/fuzz/fuzz_targets/sparql_eval.rs @@ -0,0 +1,26 @@ +#![no_main] +use lazy_static::lazy_static; +use libfuzzer_sys::fuzz_target; +use oxigraph::io::DatasetFormat; +use oxigraph::sparql::Query; +use oxigraph::store::Store; + +lazy_static! { + static ref STORE: Store = { + let store = Store::new().unwrap(); + store + .load_dataset( + sparql_smith::DATA_TRIG.as_bytes(), + DatasetFormat::TriG, + None, + ) + .unwrap(); + store + }; +} + +fuzz_target!(|data: sparql_smith::Query| { + if let Ok(q) = Query::parse(&data.to_string(), None) { + STORE.query(q).unwrap(); + } +}); diff --git a/fuzz/fuzz_targets/sparql_query.rs b/fuzz/fuzz_targets/sparql_query.rs index b0286f6a..889d3e79 100644 --- a/fuzz/fuzz_targets/sparql_query.rs +++ b/fuzz/fuzz_targets/sparql_query.rs @@ -1,10 +1,7 @@ #![no_main] use libfuzzer_sys::fuzz_target; use spargebra::Query; -use std::str; -fuzz_target!(|data: &[u8]| { - if let Ok(data) = str::from_utf8(data) { - Query::parse(data, None); - } +fuzz_target!(|data: &str| { + Query::parse(data, None); }); diff --git a/fuzz/fuzz_targets/sparql_update.rs b/fuzz/fuzz_targets/sparql_update.rs index 252bf493..15c0a995 100644 --- a/fuzz/fuzz_targets/sparql_update.rs +++ b/fuzz/fuzz_targets/sparql_update.rs @@ -3,8 +3,6 @@ use libfuzzer_sys::fuzz_target; use spargebra::Update; use std::str; -fuzz_target!(|data: &[u8]| { - if let Ok(data) = str::from_utf8(data) { - Update::parse(data, None); - } +fuzz_target!(|data: &str| { + Update::parse(data, None); }); diff --git a/lib/sparql-smith/Cargo.toml b/lib/sparql-smith/Cargo.toml new file mode 100644 index 00000000..68acc44b --- /dev/null +++ b/lib/sparql-smith/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "sparql-smith" +version = "0.1.0-alpha.1" +authors = ["Tpt "] +license = "MIT OR Apache-2.0" +readme = "README.md" +keywords = ["SPARQL"] +repository = "https://github.com/oxigraph/oxigraph/tree/main/lib/sparql-smith" +homepage = "https://oxigraph.org/" +description = """ +A SPARQL test cases generator +""" +edition = "2021" + +[dependencies] +arbitrary = { version = "1", features = ["derive"] } diff --git a/lib/sparql-smith/README.md b/lib/sparql-smith/README.md new file mode 100644 index 00000000..a02586b4 --- /dev/null +++ b/lib/sparql-smith/README.md @@ -0,0 +1,44 @@ +SPARQL smith +============ + +[![Latest Version](https://img.shields.io/crates/v/sparql-smith.svg)](https://crates.io/crates/sparql-smith) +[![Released API docs](https://docs.rs/sparql-smith/badge.svg)](https://docs.rs/sparql-smith) +[![Crates.io downloads](https://img.shields.io/crates/d/sparql-smith)](https://crates.io/crates/sparql-smith) +[![actions status](https://github.com/oxigraph/oxigraph/workflows/build/badge.svg)](https://github.com/oxigraph/oxigraph/actions) +[![Gitter](https://badges.gitter.im/oxigraph/community.svg)](https://gitter.im/oxigraph/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +sparql-smith is a test case generator for the [SPARQL](https://www.w3.org/TR/sparql11-overview/) language. + +It provides a single struct, `Query` that could be serialized to a SPARQL query using `to_string()`. + +The queries generated are sadly not always valid. Variables scopes are not properly handled yet. +All SPARQL features are not supported yet. + +The `DATA_TRIG` constant is provided as an example dataset on which queries could be evaluated. + +Usage example with [libfuzzer-sys](https://docs.rs/libfuzzer-sys) and [spargebra](https://docs.rs/spargebra): + +```rust +#![no_main] +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: sparql_smith::Query| { + spargebra::Query::parse(&data.to_string(), None).unwrap() +}); +``` + +## License + +This project is licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or + ``) +* MIT license ([LICENSE-MIT](../LICENSE-MIT) or + ``) + +at your option. + + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Oxigraph by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/lib/sparql-smith/src/lib.rs b/lib/sparql-smith/src/lib.rs new file mode 100644 index 00000000..95913fd4 --- /dev/null +++ b/lib/sparql-smith/src/lib.rs @@ -0,0 +1,1522 @@ +use arbitrary::{Arbitrary, Result, Unstructured}; +use std::fmt; +use std::fmt::Debug; +use std::iter::once; +use std::ops::ControlFlow; + +pub const DATA_TRIG: &str = " +@prefix : . + +:1 :2 :3 , :4 ; + :5 true , 1 , 1.0 , 1e0 . + +:3 :2 :4 ; + :5 false , 0 , 0.0 , 0e0 . +"; + +const NUMBER_OF_NAMED_NODES: u8 = 5; +const NUMBER_OF_VARIABLES: u8 = 4; + +#[derive(Arbitrary)] +pub struct Query { + // [1] QueryUnit ::= Query + // [2] Query ::= Prologue ( SelectQuery | ConstructQuery | DescribeQuery | AskQuery ) ValuesClause + variant: QueryVariant, + values_clause: ValuesClause, +} + +#[derive(Debug, Arbitrary)] +enum QueryVariant { + Select(SelectQuery), + //TODO: Other variants! +} + +impl fmt::Display for Query { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.variant { + QueryVariant::Select(s) => write!(f, "{}", s), + }?; + write!(f, "{}", self.values_clause) + } +} + +impl Debug for Query { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +#[derive(Debug, Arbitrary)] +struct SelectQuery { + // [7] SelectQuery ::= SelectClause DatasetClause* WhereClause SolutionModifier + select_clause: SelectClause, + where_clause: WhereClause, + solution_modifier: SolutionModifier, +} + +impl fmt::Display for SelectQuery { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}{}{}", + self.select_clause, self.where_clause, self.solution_modifier + ) + } +} + +#[derive(Debug, Arbitrary)] +struct SubSelect { + // [8] SubSelect ::= SelectClause WhereClause SolutionModifier ValuesClause + select_clause: SelectClause, + where_clause: WhereClause, + solution_modifier: SolutionModifier, + values_clause: ValuesClause, +} + +impl fmt::Display for SubSelect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}{}{}{}", + self.select_clause, self.where_clause, self.solution_modifier, self.values_clause + ) + } +} + +#[derive(Debug, Arbitrary)] +struct SelectClause { + // [9] SelectClause ::= 'SELECT' ( 'DISTINCT' | 'REDUCED' )? ( ( Var | ( '(' Expression 'AS' Var ')' ) )+ | '*' ) + option: Option, + values: SelectValues, +} + +#[derive(Debug, Arbitrary)] +enum SelectOption { + Distinct, + Reduced, +} + +#[derive(Debug, Arbitrary)] +enum SelectValues { + Star, + Projection { + start: SelectProjection, + others: Vec, + }, +} + +#[derive(Debug, Arbitrary)] +enum SelectProjection { + Variable(Var), + Projection(Expression, Var), +} + +impl fmt::Display for SelectClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SELECT")?; + if let Some(option) = &self.option { + match option { + SelectOption::Distinct => write!(f, " DISTINCT"), + SelectOption::Reduced => write!(f, " REDUCED"), + }?; + } + match &self.values { + SelectValues::Star => write!(f, " *"), + SelectValues::Projection { start, others } => { + for e in once(start).chain(others) { + match e { + SelectProjection::Variable(v) => write!(f, " {}", v), + SelectProjection::Projection(e, v) => write!(f, " ({} AS {})", e, v), + }?; + } + Ok(()) + } + } + } +} + +#[derive(Debug, Arbitrary)] +struct WhereClause { + // [17] WhereClause ::= 'WHERE'? GroupGraphPattern + with_where: bool, + group_graph_pattern: GroupGraphPattern, +} + +impl fmt::Display for WhereClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.with_where { + write!(f, " WHERE ")?; + } + write!(f, "{}", self.group_graph_pattern) + } +} + +#[derive(Debug, Arbitrary)] +struct SolutionModifier { + // [18] SolutionModifier ::= GroupClause? HavingClause? OrderClause? LimitOffsetClauses? + group: Option, + having: Option, + order: Option, + limit_offset: Option, +} + +impl fmt::Display for SolutionModifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(group) = &self.group { + write!(f, " {}", group)?; + } + if let Some(having) = &self.having { + write!(f, " {}", having)?; + } + if let Some(order) = &self.order { + write!(f, " {}", order)?; + } + if let Some(limit_offset) = &self.limit_offset { + write!(f, " {}", limit_offset)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct GroupClause { + // [19] GroupClause ::= 'GROUP' 'BY' GroupCondition+ + start: GroupCondition, + others: Vec, +} + +impl fmt::Display for GroupClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "GROUP BY {}", self.start)?; + for o in &self.others { + write!(f, " {}", o)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +enum GroupCondition { + // [20] GroupCondition ::= BuiltInCall | FunctionCall | '(' Expression ( 'AS' Var )? ')' | Var + BuiltInCall(BuiltInCall), + // TODO FunctionCall(FunctionCall) + Projection(Expression, Option), + Var(Var), +} + +impl fmt::Display for GroupCondition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::BuiltInCall(c) => write!(f, "{}", c), + //Self::FunctionCall(c) => write!(f, "{}", c), + Self::Projection(e, v) => { + if let Some(v) = v { + write!(f, "({} AS {})", e, v) + } else { + write!(f, "({})", e) + } + } + Self::Var(v) => write!(f, "{}", v), + } + } +} + +#[derive(Debug, Arbitrary)] +struct HavingClause { + // [21] HavingClause ::= 'HAVING' HavingCondition+ + start: HavingCondition, + others: Vec, +} + +impl fmt::Display for HavingClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "HAVING {}", self.start)?; + for o in &self.others { + write!(f, " {}", o)?; + } + Ok(()) + } +} + +// [22] HavingCondition ::= Constraint +type HavingCondition = Constraint; + +#[derive(Debug, Arbitrary)] +struct OrderClause { + // [23] OrderClause ::= 'ORDER' 'BY' OrderCondition+ + start: OrderCondition, + others: Vec, +} + +impl fmt::Display for OrderClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ORDER BY {}", self.start)?; + for other in &self.others { + write!(f, " {}", other)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +enum OrderCondition { + // [24] OrderCondition ::= ( ( 'ASC' | 'DESC' ) BrackettedExpression ) | ( Constraint | Var ) + BrackettedExpression { + is_asc: bool, + inner: BrackettedExpression, + }, + Constraint(Constraint), + Var(Var), +} + +impl fmt::Display for OrderCondition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::BrackettedExpression { is_asc, inner } => { + if *is_asc { + write!(f, "ASC{}", inner) + } else { + write!(f, "DESC{}", inner) + } + } + Self::Constraint(c) => write!(f, "{}", c), + Self::Var(v) => write!(f, "{}", v), + } + } +} + +#[derive(Debug, Arbitrary)] +enum LimitOffsetClauses { + // [25] LimitOffsetClauses ::= LimitClause OffsetClause? | OffsetClause LimitClause? + LimitOffset(LimitClause, Option), + OffsetLimit(OffsetClause, Option), +} + +impl fmt::Display for LimitOffsetClauses { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::LimitOffset(l, Some(o)) => write!(f, "{} {}", l, o), + Self::LimitOffset(l, None) => write!(f, "{}", l), + Self::OffsetLimit(o, Some(l)) => write!(f, "{} {}", o, l), + Self::OffsetLimit(o, None) => write!(f, "{}", o), + } + } +} + +#[derive(Debug, Arbitrary)] +struct LimitClause { + // [26] LimitClause ::= 'LIMIT' INTEGER + value: u8, +} + +impl fmt::Display for LimitClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "LIMIT {}", self.value) + } +} + +#[derive(Debug, Arbitrary)] +struct OffsetClause { + // [27] OffsetClause ::= 'OFFSET' INTEGER + value: u8, +} + +impl fmt::Display for OffsetClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "OFFSET {}", self.value) + } +} + +#[derive(Debug, Arbitrary)] +struct ValuesClause { + // [28] ValuesClause ::= ( 'VALUES' DataBlock )? + value: Option, +} + +impl fmt::Display for ValuesClause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(value) = &self.value { + write!(f, " VALUES {}", value) + } else { + Ok(()) + } + } +} + +#[derive(Debug, Arbitrary)] +enum GroupGraphPattern { + // [53] GroupGraphPattern ::= '{' ( SubSelect | GroupGraphPatternSub ) '}' + GroupGraphPatternSub(GroupGraphPatternSub), + SubSelect(Box), +} + +impl fmt::Display for GroupGraphPattern { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " {{ ")?; + match self { + Self::GroupGraphPatternSub(p) => write!(f, "{}", p), + Self::SubSelect(s) => write!(f, "{}", s), + }?; + write!(f, " }} ") + } +} + +#[derive(Debug, Arbitrary)] +struct GroupGraphPatternSub { + // [54] GroupGraphPatternSub ::= TriplesBlock? ( GraphPatternNotTriples '.'? TriplesBlock? )* + start: Option, + others: Vec, +} + +#[derive(Debug, Arbitrary)] +struct GroupGraphPatternSubOtherBlock { + start: GraphPatternNotTriples, + with_dot: bool, + end: Option, +} + +impl fmt::Display for GroupGraphPatternSub { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(start) = &self.start { + write!(f, "{}", start)?; + } + for other in &self.others { + write!(f, "{}", other.start)?; + if other.with_dot { + write!(f, " . ")?; + } + if let Some(end) = &other.end { + write!(f, "{}", end)?; + } + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct TriplesBlock { + // [55] TriplesBlock ::= TriplesSameSubjectPath ( '.' TriplesBlock? )? + start: TriplesSameSubjectPath, + end: Option>>, +} + +impl fmt::Display for TriplesBlock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + if let Some(end) = &self.end { + write!(f, " . ")?; + if let Some(end) = end { + write!(f, "{}", end)?; + } + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +enum GraphPatternNotTriples { + // [56] GraphPatternNotTriples ::= GroupOrUnionGraphPattern | OptionalGraphPattern | MinusGraphPattern | GraphGraphPattern | ServiceGraphPattern | Filter | Bind | InlineData + GroupOrUnion(GroupOrUnionGraphPattern), + Optional(OptionalGraphPattern), + Minus(MinusGraphPattern), + Graph(GraphGraphPattern), + Filter(Filter), + Bind(Bind), + InlineData(InlineData), // TODO: ServiceGraphPattern +} + +impl fmt::Display for GraphPatternNotTriples { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::GroupOrUnion(p) => write!(f, "{}", p), + Self::Optional(p) => write!(f, "{}", p), + Self::Minus(p) => write!(f, "{}", p), + Self::Graph(p) => write!(f, "{}", p), + Self::Filter(p) => write!(f, "{}", p), + Self::Bind(p) => write!(f, "{}", p), + Self::InlineData(p) => write!(f, "{}", p), + } + } +} + +#[derive(Debug, Arbitrary)] +struct OptionalGraphPattern { + // [57] OptionalGraphPattern ::= 'OPTIONAL' GroupGraphPattern + inner: GroupGraphPattern, +} + +impl fmt::Display for OptionalGraphPattern { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " OPTIONAL {}", self.inner) + } +} + +#[derive(Debug, Arbitrary)] +struct GraphGraphPattern { + // [58] GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern + graph: VarOrIri, + inner: GroupGraphPattern, +} + +impl fmt::Display for GraphGraphPattern { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " GRAPH {} {}", self.graph, self.inner) + } +} + +#[derive(Debug, Arbitrary)] +struct Bind { + // [60] Bind ::= 'BIND' '(' Expression 'AS' Var ')' + expression: Expression, + var: Var, +} + +impl fmt::Display for Bind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " BIND({} AS {})", self.expression, self.var) + } +} + +#[derive(Debug, Arbitrary)] +struct InlineData { + // [61] InlineData ::= 'VALUES' DataBlock + inner: DataBlock, +} + +impl fmt::Display for InlineData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VALUES {}", &self.inner) + } +} + +#[derive(Debug, Arbitrary)] +enum DataBlock { + // [62] DataBlock ::= InlineDataOneVar | InlineDataFull + OneVar(InlineDataOneVar), + Full(InlineDataFull), +} + +impl fmt::Display for DataBlock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::OneVar(e) => write!(f, "{}", e), + Self::Full(c) => write!(f, "{}", c), + } + } +} + +#[derive(Debug, Arbitrary)] +struct InlineDataOneVar { + // [63] InlineDataOneVar ::= Var '{' DataBlockValue* '}' + var: Var, + values: Vec, +} + +impl fmt::Display for InlineDataOneVar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} {{", self.var)?; + for v in &self.values { + write!(f, " {}", v)?; + } + write!(f, " }}") + } +} + +#[derive(Debug)] +struct InlineDataFull { + // [64] InlineDataFull ::= ( NIL | '(' Var* ')' ) '{' ( '(' DataBlockValue* ')' | NIL )* '}' + vars: Vec, + values: Vec>, +} + +impl<'a> Arbitrary<'a> for InlineDataFull { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let vars = u.arbitrary_iter()?.collect::>>()?; + + let mut values = Vec::new(); + u.arbitrary_loop(Some(0), Some(3), |u| { + let mut row = Vec::with_capacity(vars.len()); + u.arbitrary_loop( + Some(vars.len().try_into().unwrap()), + Some(vars.len().try_into().unwrap()), + |u| { + row.push(u.arbitrary()?); + Ok(ControlFlow::Continue(())) + }, + )?; + values.push(row); + Ok(ControlFlow::Continue(())) + })?; + + Ok(Self { vars, values }) + } +} + +impl fmt::Display for InlineDataFull { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "( ")?; + for v in &self.vars { + write!(f, " {}", v)?; + } + write!(f, " ) {{")?; + for vs in &self.values { + write!(f, " (")?; + for v in vs { + write!(f, " {}", v)?; + } + write!(f, " )")?; + } + write!(f, " }}") + } +} + +#[derive(Debug, Arbitrary)] +enum DataBlockValue { + // [65] DataBlockValue ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | 'UNDEF' + Iri(Iri), + Literal(Literal), + Undef, +} + +impl fmt::Display for DataBlockValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Iri(i) => write!(f, "{}", i), + Self::Literal(l) => write!(f, "{}", l), + Self::Undef => write!(f, "UNDEF"), + } + } +} + +#[derive(Debug, Arbitrary)] +struct MinusGraphPattern { + // [66] MinusGraphPattern ::= 'MINUS' GroupGraphPattern + inner: GroupGraphPattern, +} + +impl fmt::Display for MinusGraphPattern { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " MINUS {}", self.inner) + } +} + +#[derive(Debug, Arbitrary)] +struct GroupOrUnionGraphPattern { + // [67] GroupOrUnionGraphPattern ::= GroupGraphPattern ( 'UNION' GroupGraphPattern )* + start: GroupGraphPattern, + others: Vec, +} + +impl fmt::Display for GroupOrUnionGraphPattern { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for other in &self.others { + write!(f, " UNION {}", other)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct Filter { + // [68] Filter ::= 'FILTER' Constraint + constraint: Constraint, +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "FILTER {}", self.constraint) + } +} + +#[derive(Debug, Arbitrary)] +enum Constraint { + // [69] Constraint ::= BrackettedExpression | BuiltInCall | FunctionCall + BrackettedExpression(BrackettedExpression), + BuiltInCall(BuiltInCall), + // TODO FunctionCall(FunctionCall), +} + +impl fmt::Display for Constraint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::BrackettedExpression(e) => write!(f, "{}", e), + Self::BuiltInCall(c) => write!(f, "{}", c), + //Self::FunctionCall(c) => write!(f, "{}", c), + } + } +} + +#[derive(Debug, Arbitrary)] +struct FunctionCall { + // [70] FunctionCall ::= iri ArgList + iri: Iri, + args: ArgList, +} + +impl fmt::Display for FunctionCall { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}{}", self.iri, self.args) + } +} + +#[derive(Debug, Arbitrary)] +enum ArgList { + // [71] ArgList ::= NIL | '(' 'DISTINCT'? Expression ( ',' Expression )* ')' + Nil, + NotNil { + // TODO: DISTINCT + start: Box, + others: Vec, + }, +} + +impl fmt::Display for ArgList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(")?; + if let Self::NotNil { start, others } = self { + write!(f, "{}", start)?; + for e in others { + write!(f, ", {}", e)?; + } + } + write!(f, ")") + } +} + +#[derive(Debug, Arbitrary)] +struct ExpressionList { + // [72] ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')' + inner: Vec, +} + +impl fmt::Display for ExpressionList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(")?; + for (i, e) in self.inner.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", e)?; + } + write!(f, ")") + } +} + +#[derive(Debug, Arbitrary)] +struct PropertyListNotEmpty { + // [77] PropertyListNotEmpty ::= Verb ObjectList ( ';' ( Verb ObjectList )? )* + start_predicate: Verb, + start_object: Box, + others: Vec>, +} + +#[derive(Debug, Arbitrary)] +struct PropertyListElement { + predicate: Verb, + object: ObjectList, +} + +impl fmt::Display for PropertyListNotEmpty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} {}", self.start_predicate, self.start_object)?; + for other in &self.others { + write!(f, " ; ")?; + if let Some(e) = other { + write!(f, "{} {}", e.predicate, e.object)?; + } + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +enum Verb { + // [78] Verb ::= VarOrIri | 'a' + VarOrIri(VarOrIri), + A, +} + +impl fmt::Display for Verb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::VarOrIri(iri) => write!(f, "{}", iri), + Self::A => write!(f, " a "), + } + } +} + +#[derive(Debug, Arbitrary)] +struct ObjectList { + // [79] ObjectList ::= Object ( ',' Object )* + start: Object, + others: Vec, +} + +impl fmt::Display for ObjectList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for other in &self.others { + write!(f, " , ")?; + write!(f, "{}", other)?; + } + Ok(()) + } +} + +// [80] Object ::= GraphNode +type Object = GraphNode; + +#[derive(Debug, Arbitrary)] +enum TriplesSameSubjectPath { + // [81] TriplesSameSubjectPath ::= VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath + Atomic { + subject: VarOrTerm, + predicate_object: PropertyListPathNotEmpty, + }, + Other { + subject: TriplesNodePath, + predicate_object: PropertyListPath, + }, +} + +impl fmt::Display for TriplesSameSubjectPath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Atomic { + subject, + predicate_object, + } => { + write!(f, "{}{}", subject, predicate_object) + } + Self::Other { + subject, + predicate_object, + } => { + write!(f, "{} {}", subject, predicate_object) + } + } + } +} + +#[derive(Debug, Arbitrary)] +struct PropertyListPath { + // [82] PropertyListPath ::= PropertyListPathNotEmpty? + inner: Option, +} + +impl fmt::Display for PropertyListPath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(p) = &self.inner { + write!(f, "{}", p) + } else { + Ok(()) + } + } +} + +#[derive(Debug, Arbitrary)] +struct PropertyListPathNotEmpty { + // [83] PropertyListPathNotEmpty ::= ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectList )? )* + start_predicate: PropertyListPathNotEmptyVerb, + start_object: Box, + others: Vec>, +} + +#[derive(Debug, Arbitrary)] +enum PropertyListPathNotEmptyVerb { + VerbPath(VerbPath), + VerbSimple(VerbSimple), +} + +#[derive(Debug, Arbitrary)] +struct PropertyListPathElement { + predicate: PropertyListPathNotEmptyVerb, + object: ObjectList, +} + +impl fmt::Display for PropertyListPathNotEmpty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.start_predicate { + PropertyListPathNotEmptyVerb::VerbPath(p) => write!(f, "{}", p), + PropertyListPathNotEmptyVerb::VerbSimple(s) => write!(f, "{}", s), + }?; + write!(f, "{}", self.start_object)?; + for other in &self.others { + write!(f, " ; ")?; + if let Some(e) = other { + match &e.predicate { + PropertyListPathNotEmptyVerb::VerbPath(p) => write!(f, "{}", p), + PropertyListPathNotEmptyVerb::VerbSimple(s) => write!(f, "{}", s), + }?; + write!(f, "{}", e.object)?; + } + } + Ok(()) + } +} + +// [84] VerbPath ::= Path +type VerbPath = Path; + +// [85] VerbSimple ::= Var +type VerbSimple = Var; + +#[derive(Debug, Arbitrary)] +struct ObjectListPath { + // [86] ObjectListPath ::= ObjectPath ( ',' ObjectPath )* + start: ObjectPath, + others: Vec, +} + +impl fmt::Display for ObjectListPath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for other in &self.others { + write!(f, " , {}", other)?; + } + Ok(()) + } +} + +// [87] ObjectPath ::= GraphNodePath +type ObjectPath = GraphNodePath; + +// [88] Path ::= PathAlternative +type Path = PathAlternative; + +#[derive(Debug, Arbitrary)] +struct PathAlternative { + // [89] PathAlternative ::= PathSequence ( '|' PathSequence )* + start: PathSequence, + others: Vec, +} + +impl fmt::Display for PathAlternative { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for other in &self.others { + write!(f, " | {}", other)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct PathSequence { + // [90] PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )* + start: PathEltOrInverse, + others: Vec, +} + +impl fmt::Display for PathSequence { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for other in &self.others { + write!(f, " / {}", other)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct PathElt { + // [91] PathElt ::= PathPrimary PathMod? + path: PathPrimary, + mode: Option, +} + +impl fmt::Display for PathElt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.path)?; + if let Some(mode) = &self.mode { + write!(f, "{}", mode)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +enum PathEltOrInverse { + // [92] PathEltOrInverse ::= PathElt | '^' PathElt + PathElt(PathElt), + Inverse(PathElt), +} + +impl fmt::Display for PathEltOrInverse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::PathElt(e) => write!(f, "{}", e), + Self::Inverse(e) => write!(f, " ^{}", e), + } + } +} + +#[derive(Debug, Arbitrary)] +enum PathMod { + // [93] PathMod ::= '?' | '*' | '+' + ZeroOrOne, + ZeroOrMore, + OneOrMore, +} + +impl fmt::Display for PathMod { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::ZeroOrOne => write!(f, " ? "), + Self::ZeroOrMore => write!(f, " * "), + Self::OneOrMore => write!(f, " + "), + } + } +} + +#[derive(Debug, Arbitrary)] +enum PathPrimary { + // [94] PathPrimary ::= iri | 'a' | '!' PathNegatedPropertySet | '(' Path ')' + Iri(Iri), + A, + Negated(PathNegatedPropertySet), + Child(Box), +} + +impl fmt::Display for PathPrimary { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Iri(iri) => write!(f, "{}", iri), + Self::A => write!(f, " a "), + Self::Negated(n) => write!(f, "!{}", n), + Self::Child(c) => write!(f, "({})", c), + } + } +} + +#[derive(Debug, Arbitrary)] +enum PathNegatedPropertySet { + // [95] PathNegatedPropertySet ::= PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')' + Single(PathOneInPropertySet), + Multiple { + start: PathOneInPropertySet, + others: Vec, + }, +} + +impl fmt::Display for PathNegatedPropertySet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Single(p) => write!(f, "{}", p), + Self::Multiple { start, others } => { + write!(f, " ( {}", start)?; + for other in others { + write!(f, " | {}", other)?; + } + write!(f, " ) ") + } + } + } +} + +#[derive(Debug, Arbitrary)] +enum PathOneInPropertySet { + // [96] PathOneInPropertySet ::= iri | 'a' | '^' ( iri | 'a' ) + Iri(Iri), + A, + NegatedIri(Iri), + NegatedA, +} + +impl fmt::Display for PathOneInPropertySet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Iri(iri) => write!(f, "{}", iri), + Self::A => write!(f, " a "), + Self::NegatedIri(iri) => write!(f, "^{}", iri), + Self::NegatedA => write!(f, " ^a "), + } + } +} + +#[derive(Debug, Arbitrary)] +enum TriplesNode { + // [98] TriplesNode ::= Collection | BlankNodePropertyList + Collection(Collection), + BlankNodePropertyList(BlankNodePropertyList), +} + +impl fmt::Display for TriplesNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Collection(p) => write!(f, "{}", p), + Self::BlankNodePropertyList(p) => write!(f, "{}", p), + } + } +} + +#[derive(Debug, Arbitrary)] +struct BlankNodePropertyList { + // [99] BlankNodePropertyList ::= '[' PropertyListNotEmpty ']' + inner: PropertyListNotEmpty, +} + +impl fmt::Display for BlankNodePropertyList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[ {} ]", self.inner) + } +} + +#[derive(Debug, Arbitrary)] +enum TriplesNodePath { + // [100] TriplesNodePath ::= CollectionPath | BlankNodePropertyListPath + CollectionPath(CollectionPath), + BlankNodePropertyListPath(BlankNodePropertyListPath), +} + +impl fmt::Display for TriplesNodePath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::CollectionPath(p) => write!(f, "{}", p), + Self::BlankNodePropertyListPath(p) => write!(f, "{}", p), + } + } +} + +#[derive(Debug, Arbitrary)] +struct BlankNodePropertyListPath { + // [101] BlankNodePropertyListPath ::= '[' PropertyListPathNotEmpty ']' + inner: PropertyListPathNotEmpty, +} + +impl fmt::Display for BlankNodePropertyListPath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[ {} ]", self.inner) + } +} + +#[derive(Debug, Arbitrary)] +struct Collection { + // [102] Collection ::= '(' GraphNode+ ')' + start: Box, + others: Vec, +} + +impl fmt::Display for Collection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "( {}", self.start)?; + for e in &self.others { + write!(f, " {}", e)?; + } + write!(f, " )") + } +} + +#[derive(Debug, Arbitrary)] +struct CollectionPath { + // [103] CollectionPath ::= '(' GraphNodePath+ ')' + start: Box, + others: Vec, +} + +impl fmt::Display for CollectionPath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "( {}", self.start)?; + for e in &self.others { + write!(f, " {}", e)?; + } + write!(f, " )") + } +} + +#[derive(Debug, Arbitrary)] +enum GraphNode { + // [104] GraphNode ::= VarOrTerm | TriplesNode + VarOrTerm(VarOrTerm), + TriplesNode(TriplesNode), +} + +impl fmt::Display for GraphNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::VarOrTerm(t) => write!(f, "{}", t), + Self::TriplesNode(t) => write!(f, "{}", t), + } + } +} + +#[derive(Debug, Arbitrary)] +enum GraphNodePath { + // [105] GraphNodePath ::= VarOrTerm | TriplesNodePath + VarOrTerm(VarOrTerm), + TriplesNodePath(TriplesNodePath), +} + +impl fmt::Display for GraphNodePath { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::VarOrTerm(t) => write!(f, "{}", t), + Self::TriplesNodePath(p) => write!(f, "{}", p), + } + } +} + +#[derive(Debug, Arbitrary)] +enum VarOrTerm { + // [106] VarOrTerm ::= Var | GraphTerm + Var(Var), + GraphTerm(GraphTerm), +} + +impl fmt::Display for VarOrTerm { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Var(v) => write!(f, "{}", v), + Self::GraphTerm(t) => write!(f, "{}", t), + } + } +} + +#[derive(Debug, Arbitrary)] +enum VarOrIri { + // [107] VarOrIri ::= Var | iri + Var(Var), + Iri(Iri), +} + +impl fmt::Display for VarOrIri { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Var(v) => write!(f, "{}", v), + Self::Iri(t) => write!(f, "{}", t), + } + } +} + +#[derive(Debug)] +struct Var { + // [108] Var ::= VAR1 | VAR2 + value: u8, +} + +impl Arbitrary<'_> for Var { + fn arbitrary(u: &mut Unstructured<'_>) -> Result { + Ok(Self { + value: u.int_in_range(1..=NUMBER_OF_VARIABLES)?, + }) + } + + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +impl fmt::Display for Var { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " ?{} ", self.value) + } +} + +#[derive(Debug, Arbitrary)] +enum GraphTerm { + // [109] GraphTerm ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL + Iri(Iri), + Literal(Literal), + Nil, + // TODO: BlankNode +} + +impl fmt::Display for GraphTerm { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Iri(iri) => write!(f, "{}", iri), + Self::Literal(l) => write!(f, "{}", l), + Self::Nil => write!(f, " () "), + } + } +} + +// [110] Expression ::= ConditionalOrExpression +type Expression = ConditionalOrExpression; + +#[derive(Debug, Arbitrary)] +struct ConditionalOrExpression { + // [111] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )* + start: ConditionalAndExpression, + others: Vec, +} + +impl fmt::Display for ConditionalOrExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for e in &self.others { + write!(f, " || {}", e)?; + } + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct ConditionalAndExpression { + // [112] ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )* + start: ValueLogical, + others: Vec, +} + +impl fmt::Display for ConditionalAndExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.start)?; + for e in &self.others { + write!(f, " && {}", e)?; + } + Ok(()) + } +} + +// [113] ValueLogical ::= RelationalExpression +type ValueLogical = RelationalExpression; + +#[derive(Debug, Arbitrary)] +enum RelationalExpression { + // [114] RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )? + Base(NumericExpression), + Equal(NumericExpression, NumericExpression), + NotEqual(NumericExpression, NumericExpression), + Less(NumericExpression, NumericExpression), + LessOrEqual(NumericExpression, NumericExpression), + Greater(NumericExpression, NumericExpression), + GreaterOrEqual(NumericExpression, NumericExpression), + In(NumericExpression, ExpressionList), + NotIn(NumericExpression, ExpressionList), +} + +impl fmt::Display for RelationalExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Base(e) => write!(f, "{}", e), + Self::Equal(a, b) => write!(f, "{} = {}", a, b), + Self::NotEqual(a, b) => write!(f, "{} != {}", a, b), + Self::Less(a, b) => write!(f, "{} < {}", a, b), + Self::LessOrEqual(a, b) => write!(f, "{} <= {}", a, b), + Self::Greater(a, b) => write!(f, "{} > {}", a, b), + Self::GreaterOrEqual(a, b) => write!(f, "{} >= {}", a, b), + Self::In(a, b) => write!(f, "{} IN {}", a, b), + Self::NotIn(a, b) => write!(f, "{} NOT IN {}", a, b), + } + } +} + +// [115] NumericExpression ::= AdditiveExpression +type NumericExpression = AdditiveExpression; + +#[derive(Debug, Arbitrary)] +enum AdditiveExpression { + // [116] AdditiveExpression ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )* + Base(MultiplicativeExpression), + Plus(MultiplicativeExpression, MultiplicativeExpression), + Minus(MultiplicativeExpression, MultiplicativeExpression), // TODO: Prefix + and - +} + +impl fmt::Display for AdditiveExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Base(e) => write!(f, "{}", e), + Self::Plus(a, b) => write!(f, "{} + {}", a, b), + Self::Minus(a, b) => write!(f, "{} - {}", a, b), + } + } +} + +#[derive(Debug, Arbitrary)] +enum MultiplicativeExpression { + // [117] MultiplicativeExpression ::= UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )* + Base(UnaryExpression), + Mul(UnaryExpression, UnaryExpression), + Div(UnaryExpression, UnaryExpression), +} + +impl fmt::Display for MultiplicativeExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Base(e) => write!(f, "{}", e), + Self::Mul(a, b) => write!(f, "{} * {}", a, b), + Self::Div(a, b) => write!(f, "{} / {}", a, b), + } + } +} + +#[derive(Debug, Arbitrary)] +enum UnaryExpression { + // [118] UnaryExpression ::= '!' PrimaryExpression | '+' PrimaryExpression | '-' PrimaryExpression | PrimaryExpression + Not(PrimaryExpression), + Plus(PrimaryExpression), + Minus(PrimaryExpression), + Base(PrimaryExpression), +} + +impl fmt::Display for UnaryExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Not(e) => write!(f, "!{}", e), + Self::Plus(e) => write!(f, "+{}", e), + Self::Minus(e) => write!(f, "-{}", e), + Self::Base(e) => write!(f, "{}", e), + } + } +} + +#[derive(Debug, Arbitrary)] +enum PrimaryExpression { + // [119] PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var + Bracketted(BrackettedExpression), + BuiltInCall(BuiltInCall), + IriOrFunction(IriOrFunction), + Literal(Literal), + Var(Var), +} + +impl fmt::Display for PrimaryExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Bracketted(e) => write!(f, "{}", e), + Self::BuiltInCall(e) => write!(f, "{}", e), + Self::IriOrFunction(e) => write!(f, "{}", e), + Self::Literal(e) => write!(f, "{}", e), + Self::Var(e) => write!(f, "{}", e), + } + } +} + +#[derive(Debug, Arbitrary)] +struct BrackettedExpression { + // [120] BrackettedExpression ::= '(' Expression ')' + inner: Box, +} + +impl fmt::Display for BrackettedExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "({})", self.inner) + } +} + +#[derive(Debug, Arbitrary)] +enum BuiltInCall { + // [121] BuiltInCall ::= Aggregate + // | 'STR' '(' Expression ')' + // | 'LANG' '(' Expression ')' + // | 'LANGMATCHES' '(' Expression ',' Expression ')' + // | 'DATATYPE' '(' Expression ')' + // | 'BOUND' '(' Var ')' + // | 'IRI' '(' Expression ')' + // | 'URI' '(' Expression ')' + // | 'BNODE' ( '(' Expression ')' | NIL ) + // | 'RAND' NIL + // | 'ABS' '(' Expression ')' + // | 'CEIL' '(' Expression ')' + // | 'FLOOR' '(' Expression ')' + // | 'ROUND' '(' Expression ')' + // | 'CONCAT' ExpressionList + // | SubstringExpression + // | 'STRLEN' '(' Expression ')' + // | StrReplaceExpression + // | 'UCASE' '(' Expression ')' + // | 'LCASE' '(' Expression ')' + // | 'ENCODE_FOR_URI' '(' Expression ')' + // | 'CONTAINS' '(' Expression ',' Expression ')' + // | 'STRSTARTS' '(' Expression ',' Expression ')' + // | 'STRENDS' '(' Expression ',' Expression ')' + // | 'STRBEFORE' '(' Expression ',' Expression ')' + // | 'STRAFTER' '(' Expression ',' Expression ')' + // | 'YEAR' '(' Expression ')' + // | 'MONTH' '(' Expression ')' + // | 'DAY' '(' Expression ')' + // | 'HOURS' '(' Expression ')' + // | 'MINUTES' '(' Expression ')' + // | 'SECONDS' '(' Expression ')' + // | 'TIMEZONE' '(' Expression ')' + // | 'TZ' '(' Expression ')' + // | 'NOW' NIL + // | 'UUID' NIL + // | 'STRUUID' NIL + // | 'MD5' '(' Expression ')' + // | 'SHA1' '(' Expression ')' + // | 'SHA256' '(' Expression ')' + // | 'SHA384' '(' Expression ')' + // | 'SHA512' '(' Expression ')' + // | 'COALESCE' ExpressionList + // | 'IF' '(' Expression ',' Expression ',' Expression ')' + // | 'STRLANG' '(' Expression ',' Expression ')' + // | 'STRDT' '(' Expression ',' Expression ')' + // | 'sameTerm' '(' Expression ',' Expression ')' + // | 'isIRI' '(' Expression ')' + // | 'isURI' '(' Expression ')' + // | 'isBLANK' '(' Expression ')' + // | 'isLITERAL' '(' Expression ')' + // | 'isNUMERIC' '(' Expression ')' + // | RegexExpression + // | ExistsFunc + // | NotExistsFunc + Bound(Var), //TODO: Other functions +} + +impl fmt::Display for BuiltInCall { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Bound(v) => write!(f, "BOUND({})", v), + } + } +} + +#[derive(Debug, Arbitrary)] +struct IriOrFunction { + // [128] iriOrFunction ::= iri ArgList? + iri: Iri, + //TODO args: Option, +} + +impl fmt::Display for IriOrFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.iri)?; + /*if let Some(args) = &self.args { + write!(f, "{}", args)?; + }*/ + Ok(()) + } +} + +#[derive(Debug, Arbitrary)] +struct Literal { + // [129] RDFLiteral ::= String ( LANGTAG | ( '^^' iri ) )? + // [130] NumericLiteral ::= NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative + // [131] NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE + // [132] NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE + // [133] NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE + // [134] BooleanLiteral ::= 'true' | 'false' + //TODO: Implement! +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " 123 ") + } +} + +#[derive(Debug)] +struct Iri { + // [136] iri ::= IRIREF | PrefixedName + value: u8, +} + +impl Arbitrary<'_> for Iri { + fn arbitrary(u: &mut Unstructured<'_>) -> Result { + Ok(Self { + value: u.int_in_range(1..=NUMBER_OF_NAMED_NODES)?, + }) + } + + fn size_hint(depth: usize) -> (usize, Option) { + ::size_hint(depth) + } +} + +impl fmt::Display for Iri { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, " ", self.value) + } +}