|
|
|
//See https://www.w3.org/TR/turtle/#sec-grammar
|
|
|
|
|
|
|
|
use std::char;
|
|
|
|
use model::vocab::rdf;
|
|
|
|
use model::vocab::xsd;
|
|
|
|
use std::iter;
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
#![arguments(state: &mut ParserState)]
|
|
|
|
|
|
|
|
|
|
|
|
//[1]
|
|
|
|
pub QueryUnit -> Query = Query
|
|
|
|
|
|
|
|
//[2]
|
|
|
|
Query -> Query = _ Prologue _ q:(SelectQuery / ConstructQuery / DescribeQuery / AskQuery) _ { //TODO: ValuesClause
|
|
|
|
q
|
|
|
|
}
|
|
|
|
|
|
|
|
//[4]
|
|
|
|
Prologue -> () = (BaseDecl _ / PrefixDecl _)*
|
|
|
|
|
|
|
|
//[5]
|
|
|
|
BaseDecl -> () = "BASE"i _ i:IRIREF {?
|
|
|
|
match state.url_parser().parse(&i) {
|
|
|
|
Ok(url) => {
|
|
|
|
state.base_uri = Some(url);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
Err(error) => Err("IRI parsing failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[6]
|
|
|
|
PrefixDecl -> () = "PREFIX"i _ ns:PNAME_NS _ i:IRIREF {
|
|
|
|
state.namespaces.insert(ns.into(), i);
|
|
|
|
}
|
|
|
|
|
|
|
|
//[7]
|
|
|
|
SelectQuery -> Query = s:SelectClause _ d:DatasetClauses _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifier
|
|
|
|
Query::SelectQuery {
|
|
|
|
dataset: d,
|
|
|
|
algebra: build_select(s, w, g, h, o, l, v, state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[8]
|
|
|
|
SubSelect -> GraphPattern = s:SelectClause _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause { //TODO: Modifiers
|
|
|
|
build_select(s, w, g, h, o, l, v, state)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[9]
|
|
|
|
SelectClause -> Selection = "SELECT"i _ o:SelectClause_option _ v:SelectClause_variables {
|
|
|
|
Selection {
|
|
|
|
option: o,
|
|
|
|
variables: v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SelectClause_option -> SelectionOption =
|
|
|
|
"DISTINCT"i { SelectionOption::Distinct } /
|
|
|
|
"REDUCED"i { SelectionOption::Reduced } /
|
|
|
|
{ SelectionOption::Default }
|
|
|
|
SelectClause_variables -> Option<Vec<SelectionMember>> =
|
|
|
|
'*' { None } /
|
|
|
|
p:SelectClause_member+ { Some(p) }
|
|
|
|
SelectClause_member -> SelectionMember =
|
|
|
|
v:Var _ { SelectionMember::Variable(v) } /
|
|
|
|
'(' _ e:Expression _ "AS"i _ v:Var _ ')' _ { SelectionMember::Expression(e, v) }
|
|
|
|
|
|
|
|
//[10]
|
|
|
|
ConstructQuery -> Query =
|
|
|
|
"CONSTRUCT"i _ c:ConstructTemplate _ d:DatasetClauses _ w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause {
|
|
|
|
Query::ConstructQuery {
|
|
|
|
construct: c,
|
|
|
|
dataset: d,
|
|
|
|
algebra: build_select(Selection::default(), w, g, h, o, l, v, state)
|
|
|
|
}
|
|
|
|
} /
|
|
|
|
"CONSTRUCT"i _ d:DatasetClauses _ "WHERE"i _ '{' _ c:ConstructQuery_optional_triple_template _ '}' _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause {
|
|
|
|
Query::ConstructQuery {
|
|
|
|
construct: c.clone(),
|
|
|
|
dataset: d,
|
|
|
|
algebra: build_select(
|
|
|
|
Selection::default(),
|
|
|
|
GraphPattern::BGP(c.into_iter().map(TripleOrPathPattern::from).collect()),
|
|
|
|
g, h, o, l, v, state
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstructQuery_optional_triple_template -> Vec<TriplePattern> = TriplesTemplate / { Vec::default() }
|
|
|
|
|
|
|
|
//[11]
|
|
|
|
DescribeQuery -> Query =
|
|
|
|
"DESCRIBE"i _ '*' _ d:DatasetClauses w:WhereClause? _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause {
|
|
|
|
Query::DescribeQuery {
|
|
|
|
dataset: d,
|
|
|
|
algebra: build_select(Selection::default(), w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state)
|
|
|
|
}
|
|
|
|
} /
|
|
|
|
"DESCRIBE"i _ p:DescribeQuery_item+ _ d:DatasetClauses w:WhereClause? _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause {
|
|
|
|
Query::DescribeQuery {
|
|
|
|
dataset: d,
|
|
|
|
algebra: build_select(Selection {
|
|
|
|
option: SelectionOption::Default,
|
|
|
|
variables: Some(p.into_iter().map(|var_or_iri| match var_or_iri {
|
|
|
|
NamedNodeOrVariable::NamedNode(n) => SelectionMember::Expression(n.into(), Variable::default()),
|
|
|
|
NamedNodeOrVariable::Variable(v) => SelectionMember::Variable(v)
|
|
|
|
}).collect())
|
|
|
|
}, w.unwrap_or_else(GraphPattern::default), g, h, o, l, v, state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DescribeQuery_item -> NamedNodeOrVariable = i:VarOrIri _ { i }
|
|
|
|
|
|
|
|
//[12]
|
|
|
|
AskQuery -> Query = "ASK"i _ d:DatasetClauses w:WhereClause _ g:GroupClause? _ h:HavingClause? _ o:OrderClause? _ l:LimitOffsetClauses? _ v:ValuesClause {
|
|
|
|
Query::AskQuery {
|
|
|
|
dataset: d,
|
|
|
|
algebra: build_select(Selection::default(), w, g, h, o, l, v, state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[13]
|
|
|
|
DatasetClause -> DatasetSpec = "FROM"i _ d:(DefaultGraphClause / NamedGraphClause) { d }
|
|
|
|
DatasetClauses -> DatasetSpec = d:DatasetClauses_item* {
|
|
|
|
d.into_iter().fold(DatasetSpec::default(), |mut a, b| a + b)
|
|
|
|
}
|
|
|
|
DatasetClauses_item -> DatasetSpec = d:DatasetClause _ { d }
|
|
|
|
//[14]
|
|
|
|
DefaultGraphClause -> DatasetSpec = s:SourceSelector {
|
|
|
|
DatasetSpec::new_with_default(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[15]
|
|
|
|
NamedGraphClause -> DatasetSpec = "NAMED"i _ s:SourceSelector {
|
|
|
|
DatasetSpec::new_with_named(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[16]
|
|
|
|
SourceSelector -> NamedNode = iri
|
|
|
|
|
|
|
|
//[17]
|
|
|
|
WhereClause -> GraphPattern = "WHERE"i? _ p:GroupGraphPattern {
|
|
|
|
p
|
|
|
|
}
|
|
|
|
|
|
|
|
//[19]
|
|
|
|
GroupClause -> (Vec<Expression>, Vec<(Expression,Variable)>) = "GROUP"i _ "BY"i _ c:GroupCondition_item+ {
|
|
|
|
let mut projections: Vec<(Expression,Variable)> = Vec::default();
|
|
|
|
let clauses = c.into_iter().map(|(e, vo)| {
|
|
|
|
match vo {
|
|
|
|
Some(v) => {
|
|
|
|
projections.push((e, v.clone()));
|
|
|
|
v.into()
|
|
|
|
},
|
|
|
|
None => e
|
|
|
|
}
|
|
|
|
}).collect();
|
|
|
|
(clauses, projections)
|
|
|
|
}
|
|
|
|
GroupCondition_item -> (Expression, Option<Variable>) = c:GroupCondition _ { c }
|
|
|
|
|
|
|
|
//[20]
|
|
|
|
GroupCondition -> (Expression, Option<Variable>) =
|
|
|
|
e:BuiltInCall { (e, None) } /
|
|
|
|
e:FunctionCall { (e, None) } /
|
|
|
|
'(' _ e:Expression _ v:GroupCondition_as? ')' { (e, v) } /
|
|
|
|
e:Var { (e.into(), None) }
|
|
|
|
GroupCondition_as -> Variable = "AS"i _ v:Var _ { v }
|
|
|
|
|
|
|
|
//[21]
|
|
|
|
HavingClause -> Expression = "HAVING"i _ e:HavingCondition+ {?
|
|
|
|
not_empty_fold(e.into_iter(), |a, b| Expression::AndExpression(Box::new(a), Box::new(b)))
|
|
|
|
}
|
|
|
|
|
|
|
|
//[22]
|
|
|
|
HavingCondition -> Expression = Constraint
|
|
|
|
|
|
|
|
//[23]
|
|
|
|
OrderClause -> Vec<OrderComparator> = "ORDER"i _ "BY"i _ c:OrderClause_item+ { c }
|
|
|
|
OrderClause_item -> OrderComparator = c:OrderCondition _ { c }
|
|
|
|
|
|
|
|
//[24]
|
|
|
|
OrderCondition -> OrderComparator =
|
|
|
|
"ASC"i _ e: BrackettedExpression { OrderComparator::Asc(e) } /
|
|
|
|
"DESC"i _ e: BrackettedExpression { OrderComparator::Desc(e) } /
|
|
|
|
e: Constraint { e.into() } /
|
|
|
|
v: Var { Expression::from(v).into() }
|
|
|
|
|
|
|
|
//[25]
|
|
|
|
LimitOffsetClauses -> (usize, Option<usize>) =
|
|
|
|
l:LimitClause _ o:OffsetClause? { (o.unwrap_or(0), Some(l)) } /
|
|
|
|
o:OffsetClause _ l:LimitClause? { (o, l) }
|
|
|
|
|
|
|
|
//[26]
|
|
|
|
LimitClause -> usize = "LIMIT"i _ l:$(INTEGER) {?
|
|
|
|
usize::from_str(l).map_err(|_| "The query limit should be a non negative integer")
|
|
|
|
}
|
|
|
|
|
|
|
|
//[27]
|
|
|
|
OffsetClause -> usize = "OFFSET"i _ o:$(INTEGER) {?
|
|
|
|
usize::from_str(o).map_err(|_| "The query offset should be a non negative integer")
|
|
|
|
}
|
|
|
|
|
|
|
|
//[28]
|
|
|
|
ValuesClause -> Option<GraphPattern> =
|
|
|
|
"VALUES"i _ p:DataBlock { Some(p) } /
|
|
|
|
{ None }
|
|
|
|
|
|
|
|
//[52]
|
|
|
|
TriplesTemplate -> Vec<TriplePattern> = h:TriplesSameSubject _ t:TriplesTemplate_tail? {
|
|
|
|
let mut triples = h;
|
|
|
|
if let Some(l) = t {
|
|
|
|
triples.extend_from_slice(&l)
|
|
|
|
}
|
|
|
|
triples
|
|
|
|
}
|
|
|
|
TriplesTemplate_tail -> Vec<TriplePattern> = '.' _ t:TriplesTemplate? _ {
|
|
|
|
t.unwrap_or_else(Vec::default)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[53]
|
|
|
|
GroupGraphPattern -> GraphPattern =
|
|
|
|
'{' _ p:GroupGraphPatternSub _ '}' { p } /
|
|
|
|
'{' _ p:SubSelect _ '}' { p }
|
|
|
|
|
|
|
|
//[54]
|
|
|
|
GroupGraphPatternSub -> GraphPattern = a:TriplesBlock? _ b:GroupGraphPatternSub_item* {
|
|
|
|
let mut p = a.map(|v| vec![PartialGraphPattern::Other(GraphPattern::BGP(v))]).unwrap_or_else(|| vec![]);
|
|
|
|
for v in b {
|
|
|
|
p.extend_from_slice(&v)
|
|
|
|
}
|
|
|
|
let mut filter: Option<Expression> = None;
|
|
|
|
let mut g = GraphPattern::default();
|
|
|
|
for e in p {
|
|
|
|
match e {
|
|
|
|
PartialGraphPattern::Optional(p) => match p {
|
|
|
|
GraphPattern::Filter(f, a2) => {
|
|
|
|
g = GraphPattern::LeftJoin(Box::new(g), a2, f)
|
|
|
|
}
|
|
|
|
a => {
|
|
|
|
g = GraphPattern::LeftJoin(Box::new(g), Box::new(a), Literal::from(true).into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PartialGraphPattern::Minus(p) => {
|
|
|
|
g = GraphPattern::Minus(Box::new(g), Box::new(p))
|
|
|
|
}
|
|
|
|
PartialGraphPattern::Bind(expr, var) => {
|
|
|
|
g = GraphPattern::Extend(Box::new(g), var, expr)
|
|
|
|
}
|
|
|
|
PartialGraphPattern::Filter(expr) => match filter {
|
|
|
|
Some(f) => { filter = Some(Expression::AndExpression(Box::new(f), Box::new(expr))) },
|
|
|
|
None => { filter = Some(expr) }
|
|
|
|
},
|
|
|
|
PartialGraphPattern::Other(e) => g = new_join(g, e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match filter {
|
|
|
|
Some(filter) => GraphPattern::Filter(filter, Box::new(g)),
|
|
|
|
None => g
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GroupGraphPatternSub_item -> Vec<PartialGraphPattern> = a:GraphPatternNotTriples _ ('.' _)? b:TriplesBlock? _ {
|
|
|
|
let mut result = vec![a];
|
|
|
|
if let Some(v) = b {
|
|
|
|
result.push(PartialGraphPattern::Other(GraphPattern::BGP(v)));
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
//[55]
|
|
|
|
TriplesBlock -> Vec<TripleOrPathPattern> = h:TriplesSameSubjectPath _ t:TriplesBlock_tail? {
|
|
|
|
let mut triples = h;
|
|
|
|
if let Some(l) = t {
|
|
|
|
triples.extend_from_slice(&l)
|
|
|
|
}
|
|
|
|
triples
|
|
|
|
}
|
|
|
|
TriplesBlock_tail -> Vec<TripleOrPathPattern> = '.' _ t:TriplesBlock? _ {
|
|
|
|
t.unwrap_or_else(Vec::default)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[56]
|
|
|
|
GraphPatternNotTriples -> PartialGraphPattern = GroupOrUnionGraphPattern / OptionalGraphPattern / MinusGraphPattern / GraphGraphPattern / ServiceGraphPattern / Filter / Bind / InlineData
|
|
|
|
|
|
|
|
//[57]
|
|
|
|
OptionalGraphPattern -> PartialGraphPattern = "OPTIONAL"i _ p:GroupGraphPattern {
|
|
|
|
PartialGraphPattern::Optional(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[58]
|
|
|
|
GraphGraphPattern -> PartialGraphPattern = "GRAPH"i _ g:VarOrIri _ p:GroupGraphPattern {
|
|
|
|
PartialGraphPattern::Other(GraphPattern::Graph(g, Box::new(p)))
|
|
|
|
}
|
|
|
|
|
|
|
|
//[59]
|
|
|
|
ServiceGraphPattern -> PartialGraphPattern =
|
|
|
|
"SERVICE"i _ "SILENT"i _ s:VarOrIri _ p:GroupGraphPattern { PartialGraphPattern::Other(GraphPattern::Service(s, Box::new(p), true)) } /
|
|
|
|
"SERVICE"i _ s:VarOrIri _ p:GroupGraphPattern { PartialGraphPattern::Other(GraphPattern::Service(s, Box::new(p), false)) }
|
|
|
|
|
|
|
|
//[60]
|
|
|
|
Bind -> PartialGraphPattern = "BIND"i _ '(' _ e:Expression _ "AS"i _ v:Var _ ')' {
|
|
|
|
PartialGraphPattern::Bind(e, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[61]
|
|
|
|
InlineData -> PartialGraphPattern = "VALUES"i _ p:DataBlock { PartialGraphPattern::Other(p) }
|
|
|
|
|
|
|
|
//[62]
|
|
|
|
DataBlock -> GraphPattern = l:(InlineDataOneVar / InlineDataFull) {
|
|
|
|
GraphPattern::Data(l)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[63]
|
|
|
|
InlineDataOneVar -> StaticBindings = var:Var _ '{' _ d:InlineDataOneVar_value* '}' {
|
|
|
|
StaticBindings::new(vec![var], d)
|
|
|
|
}
|
|
|
|
InlineDataOneVar_value -> Vec<Option<Term>> = t:DataBlockValue { vec![t] }
|
|
|
|
|
|
|
|
//[64]
|
|
|
|
InlineDataFull -> StaticBindings = '(' _ vars:InlineDataFull_var* _ ')' _ '{' _ val:InlineDataFull_values* '}' {
|
|
|
|
StaticBindings::new(vars, val)
|
|
|
|
}
|
|
|
|
InlineDataFull_var -> Variable = v:Var _ { v }
|
|
|
|
InlineDataFull_values -> Vec<Option<Term>> = '(' _ v:InlineDataFull_value* _ ')' _ { v }
|
|
|
|
InlineDataFull_value -> Option<Term> = v:DataBlockValue _ { v }
|
|
|
|
|
|
|
|
//[65]
|
|
|
|
DataBlockValue -> Option<Term> =
|
|
|
|
i:iri { Some(i.into()) } /
|
|
|
|
l:RDFLiteral { Some(l.into()) } /
|
|
|
|
l:NumericLiteral { Some(l.into()) } /
|
|
|
|
l:BooleanLiteral { Some(l.into()) } /
|
|
|
|
"UNDEF"i { None }
|
|
|
|
|
|
|
|
//[66]
|
|
|
|
MinusGraphPattern -> PartialGraphPattern = "MINUS"i _ p: GroupGraphPattern {
|
|
|
|
PartialGraphPattern::Minus(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[67]
|
|
|
|
GroupOrUnionGraphPattern -> PartialGraphPattern = p:GroupOrUnionGraphPattern_item **<1,> ("UNION"i _) {?
|
|
|
|
not_empty_fold(p.into_iter(), |a, b| {
|
|
|
|
GraphPattern::Union(Box::new(a), Box::new(b))
|
|
|
|
}).map(PartialGraphPattern::Other)
|
|
|
|
}
|
|
|
|
GroupOrUnionGraphPattern_item -> GraphPattern = p:GroupGraphPattern _ { p }
|
|
|
|
|
|
|
|
//[68]
|
|
|
|
Filter -> PartialGraphPattern = "FILTER"i _ c:Constraint {
|
|
|
|
PartialGraphPattern::Filter(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[69]
|
|
|
|
Constraint -> Expression = BrackettedExpression / BuiltInCall / FunctionCall
|
|
|
|
|
|
|
|
//[70]
|
|
|
|
FunctionCall -> Expression = f: iri _ a: ArgList {
|
|
|
|
Expression::CustomFunctionCall(f, a)
|
|
|
|
}
|
|
|
|
|
|
|
|
//[71]
|
|
|
|
ArgList -> Vec<Expression> = //TODO: support DISTINCT
|
|
|
|
'(' _ 'DISTINCT'? _ e:ArgList_item **<1,> (',' _) _ ')' { e } /
|
|
|
|
NIL { Vec::new() }
|
|
|
|
ArgList_item -> Expression = e:Expression _ { e }
|
|
|
|
|
|
|
|
//[72]
|
|
|
|
ExpressionList -> Vec<Expression> =
|
|
|
|
'(' _ e:ExpressionList_item **<1,> (',' _) ')' { e } /
|
|
|
|
NIL { Vec::default() }
|
|
|
|
ExpressionList_item -> Expression = e:Expression _ { e }
|
|
|
|
|
|
|
|
//[73]
|
|
|
|
ConstructTemplate -> Vec<TriplePattern> = '{' _ t:ConstructTriples _ '}' { t }
|
|
|
|
|
|
|
|
//[74]
|
|
|
|
ConstructTriples -> Vec<TriplePattern> = p:ConstructTriples_item ** ('.' _) {
|
|
|
|
p.into_iter().flat_map(|c| c.into_iter()).collect()
|
|
|
|
}
|
|
|
|
ConstructTriples_item -> Vec<TriplePattern> = t:TriplesSameSubject _ { t }
|
|
|
|
|
|
|
|
//[75]
|
|
|
|
TriplesSameSubject -> Vec<TriplePattern> =
|
|
|
|
s:VarOrTerm _ po:PropertyListNotEmpty {
|
|
|
|
let mut patterns = po.patterns;
|
|
|
|
for (p, os) in po.focus {
|
|
|
|
for o in os {
|
|
|
|
patterns.push(TriplePattern::new(s.clone(), p.clone(), o))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patterns
|
|
|
|
} /
|
|
|
|
s:TriplesNode _ po:PropertyList {
|
|
|
|
let mut patterns = s.patterns;
|
|
|
|
patterns.extend_from_slice(&po.patterns);
|
|
|
|
for (p, os) in po.focus {
|
|
|
|
for o in os {
|
|
|
|
patterns.push(TriplePattern::new(s.focus.clone(), p.clone(), o))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patterns
|
|
|
|
}
|
|
|
|
|
|
|
|
//[76]
|
|
|
|
PropertyList -> FocusedTriplePattern<Vec<(NamedNodeOrVariable,Vec<TermOrVariable>)>> =
|
|
|
|
PropertyListNotEmpty /
|
|
|
|
{ FocusedTriplePattern::default() }
|
|
|
|
|
|
|
|
//[77]
|
|
|
|
PropertyListNotEmpty -> FocusedTriplePattern<Vec<(NamedNodeOrVariable,Vec<TermOrVariable>)>> = l:PropertyListNotEmpty_item **<1,> (';' _) {
|
|
|
|
l.into_iter().fold(FocusedTriplePattern::<Vec<(NamedNodeOrVariable,Vec<TermOrVariable>)>>::default(), |mut a, b| {
|
|
|
|
a.focus.push(b.focus);
|
|
|
|
a.patterns.extend_from_slice(&b.patterns);
|
|
|
|
a
|
|
|
|
})
|
|
|
|
}
|
|
|
|
PropertyListNotEmpty_item -> FocusedTriplePattern<(NamedNodeOrVariable,Vec<TermOrVariable>)> = p:Verb _ o:ObjectList _ {
|
|
|
|
FocusedTriplePattern {
|
|
|
|
focus: (p, o.focus),
|
|
|
|
patterns: o.patterns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[78]
|
|
|
|
Verb -> NamedNodeOrVariable = 'a' { rdf::TYPE.clone().into() } / VarOrIri
|
|
|
|
|
|
|
|
//[79]
|
|
|
|
ObjectList -> FocusedTriplePattern<Vec<TermOrVariable>> = o:ObjectList_item **<1,> (',' _) {
|
|
|
|
o.into_iter().fold(FocusedTriplePattern::<Vec<TermOrVariable>>::default(), |mut a, b| {
|
|
|
|
a.focus.push(b.focus);
|
|
|
|
a.patterns.extend_from_slice(&b.patterns);
|
|
|
|
a
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ObjectList_item -> FocusedTriplePattern<TermOrVariable> = o:Object _ { o }
|
|
|
|
|
|
|
|
//[80]
|
|
|
|
Object -> FocusedTriplePattern<TermOrVariable> = GraphNode
|
|
|
|
|
|
|
|
//[81]
|
|
|
|
TriplesSameSubjectPath -> Vec<TripleOrPathPattern> =
|
|
|
|
s:VarOrTerm _ po:PropertyListPathNotEmpty {
|
|
|
|
let mut patterns = po.patterns;
|
|
|
|
for (p, os) in po.focus {
|
|
|
|
for o in os {
|
|
|
|
add_to_triple_or_path_patterns(s.clone(), p.clone(), o, &mut patterns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patterns
|
|
|
|
} /
|
|
|
|
s:TriplesNodePath _ po:PropertyListPath {
|
|
|
|
let mut patterns = s.patterns;
|
|
|
|
patterns.extend_from_slice(&po.patterns);
|
|
|
|
for (p, os) in po.focus {
|
|
|
|
for o in os {
|
|
|
|
add_to_triple_or_path_patterns(s.focus.clone(), p.clone(), o, &mut patterns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patterns
|
|
|
|
}
|
|
|
|
|
|
|
|
//[82]
|
|
|
|
PropertyListPath -> FocusedTripleOrPathPattern<Vec<(VariableOrPropertyPath,Vec<TermOrVariable>)>> =
|
|
|
|
PropertyListPathNotEmpty /
|
|
|
|
{ FocusedTripleOrPathPattern::default() }
|
|
|
|
|
|
|
|
//[83]
|
|
|
|
PropertyListPathNotEmpty -> FocusedTripleOrPathPattern<Vec<(VariableOrPropertyPath,Vec<TermOrVariable>)>> = hp:(VerbPath / VerbSimple) _ ho:ObjectListPath _ t:PropertyListPathNotEmpty_item* {
|
|
|
|
t.into_iter().flat_map(|e| e.into_iter()).fold(FocusedTripleOrPathPattern {
|
|
|
|
focus: vec![(hp, ho.focus)],
|
|
|
|
patterns: ho.patterns
|
|
|
|
}, |mut a, b| {
|
|
|
|
a.focus.push(b.focus);
|
|
|
|
a.patterns.extend(b.patterns.into_iter().map(|v| v.into()));
|
|
|
|
a
|
|
|
|
})
|
|
|
|
}
|
|
|
|
PropertyListPathNotEmpty_item -> Option<FocusedTriplePattern<(VariableOrPropertyPath,Vec<TermOrVariable>)>> = ';' _ c:PropertyListPathNotEmpty_item_content? {
|
|
|
|
c
|
|
|
|
}
|
|
|
|
PropertyListPathNotEmpty_item_content -> FocusedTriplePattern<(VariableOrPropertyPath,Vec<TermOrVariable>)> = p:(VerbPath / VerbSimple) _ o:ObjectList _ {
|
|
|
|
FocusedTriplePattern {
|
|
|
|
focus: (p, o.focus),
|
|
|
|
patterns: o.patterns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[84]
|
|
|
|
VerbPath -> VariableOrPropertyPath = p:Path {
|
|
|
|
p.into()
|
|
|
|
}
|
|
|
|
|
|
|
|
//[85]
|
|
|
|
VerbSimple -> VariableOrPropertyPath = v:Var {
|
|
|
|
v.into()
|
|
|
|
}
|
|
|
|
|
|
|
|
//[86]
|
|
|
|
ObjectListPath -> FocusedTripleOrPathPattern<Vec<TermOrVariable>> = o:ObjectPath_item **<1,> (',' _) {
|
|
|
|
o.into_iter().fold(FocusedTripleOrPathPattern::<Vec<TermOrVariable>>::default(), |mut a, b| {
|
|
|
|
a.focus.push(b.focus);
|
|
|
|
a.patterns.extend_from_slice(&b.patterns);
|
|
|
|
a
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ObjectPath_item -> FocusedTripleOrPathPattern<TermOrVariable> = o:ObjectPath _ { o }
|
|
|
|
|
|
|
|
//[87]
|
|
|
|
ObjectPath -> FocusedTripleOrPathPattern<TermOrVariable> = GraphNodePath
|
|
|
|
|
|
|
|
//[88]
|
|
|
|
Path -> PropertyPath = PathAlternative
|
|
|
|
|
|
|
|
//[89]
|
|
|
|
PathAlternative -> PropertyPath = p:PathAlternative_item **<1,> ('|' _) {?
|
|
|
|
not_empty_fold(p.into_iter(), |a, b| {
|
|
|
|
PropertyPath::AlternativePath(Box::new(a), Box::new(b))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
PathAlternative_item -> PropertyPath = p:PathSequence _ { p }
|
|
|
|
|
|
|
|
//[90]
|
|
|
|
PathSequence -> PropertyPath = p:PathSequence_item **<1,> ('/' _) {?
|
|
|
|
not_empty_fold(p.into_iter(), |a, b| {
|
|
|
|
PropertyPath::SequencePath(Box::new(a), Box::new(b))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
PathSequence_item -> PropertyPath = p:PathEltOrInverse _ { p }
|
|
|
|
|
|
|
|
//[91]
|
|
|
|
PathElt -> PropertyPath =
|
|
|
|
p:PathPrimary '?' { PropertyPath::ZeroOrOnePath(Box::new(p)) } / //TODO: allow space before "?"
|
|
|
|
p:PathPrimary _ '*' { PropertyPath::ZeroOrMorePath(Box::new(p)) } /
|
|
|
|
p:PathPrimary _ '+' { PropertyPath::OneOrMorePath(Box::new(p)) } /
|
|
|
|
PathPrimary
|
|
|
|
|
|
|
|
//[92]
|
|
|
|
PathEltOrInverse -> PropertyPath =
|
|
|
|
'^' _ p:PathElt { PropertyPath::InversePath(Box::new(p)) } /
|
|
|
|
PathElt
|
|
|
|
|
|
|
|
//[94]
|
|
|
|
PathPrimary -> PropertyPath =
|
|
|
|
'a' { rdf::TYPE.clone().into() } /
|
|
|
|
v:iri { v.into() } /
|
|
|
|
'!' _ p:PathNegatedPropertySet { p } /
|
|
|
|
'(' _ p:Path _ ')' { p }
|
|
|
|
|
|
|
|
//[95]
|
|
|
|
PathNegatedPropertySet -> PropertyPath =
|
|
|
|
'(' _ p:PathNegatedPropertySet_item **<1,> ('|' _) ')' {
|
|
|
|
let mut direct = Vec::default();
|
|
|
|
let mut inverse = Vec::default();
|
|
|
|
for e in p {
|
|
|
|
match e {
|
|
|
|
Either::Left(a) => direct.push(a),
|
|
|
|
Either::Right(b) => inverse.push(b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if inverse.is_empty() {
|
|
|
|
PropertyPath::NegatedPropertySet(direct)
|
|
|
|
} else if direct.is_empty() {
|
|
|
|
PropertyPath::InversePath(Box::new(PropertyPath::NegatedPropertySet(inverse)))
|
|
|
|
} else {
|
|
|
|
PropertyPath::AlternativePath(
|
|
|
|
Box::new(PropertyPath::NegatedPropertySet(direct)),
|
|
|
|
Box::new(PropertyPath::InversePath(Box::new(PropertyPath::NegatedPropertySet(inverse))))
|
|
|
|
)
|
|
|
|
}
|
|
|
|
} /
|
|
|
|
p:PathOneInPropertySet {
|
|
|
|
match p {
|
|
|
|
Either::Left(a) => PropertyPath::NegatedPropertySet(vec![a]),
|
|
|
|
Either::Right(b) => PropertyPath::InversePath(Box::new(PropertyPath::NegatedPropertySet(vec![b]))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PathNegatedPropertySet_item -> Either<NamedNode,NamedNode> = p:PathOneInPropertySet _ { p }
|
|
|
|
|
|
|
|
//[96]
|
|
|
|
PathOneInPropertySet -> Either<NamedNode,NamedNode> =
|
|
|
|
'^' _ 'a' { Either::Right(rdf::TYPE.clone()) } /
|
|
|
|
'^' _ v:iri { Either::Right(v) } /
|
|
|
|
'a' { Either::Left(rdf::TYPE.clone()) } /
|
|
|
|
v:iri { Either::Left(v) }
|
|
|
|
|
|
|
|
//[98]
|
|
|
|
TriplesNode -> FocusedTriplePattern<TermOrVariable> = Collection / BlankNodePropertyList
|
|
|
|
|
|
|
|
//[99]
|
|
|
|
BlankNodePropertyList -> FocusedTriplePattern<TermOrVariable> = '[' _ po:PropertyListNotEmpty _ ']' {
|
|
|
|
let mut patterns: Vec<TriplePattern> = Vec::default();
|
|
|
|
let mut bnode = TermOrVariable::from(BlankNode::default());
|
|
|
|
for (p, os) in po.focus {
|
|
|
|
for o in os {
|
|
|
|
patterns.push(TriplePattern::new(bnode.clone(), p.clone(), o));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FocusedTriplePattern {
|
|
|
|
focus: bnode,
|
|
|
|
patterns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[100]
|
|
|
|
TriplesNodePath -> FocusedTripleOrPathPattern<TermOrVariable> = CollectionPath / BlankNodePropertyListPath
|
|
|
|
|
|
|
|
//[101]
|
|
|
|
BlankNodePropertyListPath -> FocusedTripleOrPathPattern<TermOrVariable> = '[' _ po:PropertyListPathNotEmpty _ ']' {
|
|
|
|
let mut patterns: Vec<TripleOrPathPattern> = Vec::default();
|
|
|
|
let mut bnode = TermOrVariable::from(BlankNode::default());
|
|
|
|
for (p, os) in po.focus {
|
|
|
|
for o in os {
|
|
|
|
add_to_triple_or_path_patterns(bnode.clone(), p.clone(), o, &mut patterns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FocusedTripleOrPathPattern {
|
|
|
|
focus: bnode,
|
|
|
|
patterns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[102]
|
|
|
|
Collection -> FocusedTriplePattern<TermOrVariable> = '(' _ o:Collection_item+ ')' {
|
|
|
|
let mut patterns: Vec<TriplePattern> = Vec::default();
|
|
|
|
let mut current_list_node = TermOrVariable::from(rdf::NIL.clone());
|
|
|
|
for objWithPatterns in o.into_iter().rev() {
|
|
|
|
let new_blank_node = TermOrVariable::from(BlankNode::default());
|
|
|
|
patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::FIRST.clone(), objWithPatterns.focus.clone()));
|
|
|
|
patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::REST.clone(), current_list_node));
|
|
|
|
current_list_node = new_blank_node;
|
|
|
|
patterns.extend_from_slice(&objWithPatterns.patterns);
|
|
|
|
}
|
|
|
|
FocusedTriplePattern {
|
|
|
|
focus: current_list_node,
|
|
|
|
patterns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Collection_item -> FocusedTriplePattern<TermOrVariable> = o:GraphNode _ { o }
|
|
|
|
|
|
|
|
//[103]
|
|
|
|
CollectionPath -> FocusedTripleOrPathPattern<TermOrVariable> = '(' _ o:CollectionPath_item+ _ ')' {
|
|
|
|
let mut patterns: Vec<TripleOrPathPattern> = Vec::default();
|
|
|
|
let mut current_list_node = TermOrVariable::from(rdf::NIL.clone());
|
|
|
|
for objWithPatterns in o.into_iter().rev() {
|
|
|
|
let new_blank_node = TermOrVariable::from(BlankNode::default());
|
|
|
|
patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::FIRST.clone(), objWithPatterns.focus.clone()).into());
|
|
|
|
patterns.push(TriplePattern::new(new_blank_node.clone(), rdf::REST.clone(), current_list_node).into());
|
|
|
|
current_list_node = new_blank_node;
|
|
|
|
patterns.extend_from_slice(&objWithPatterns.patterns);
|
|
|
|
}
|
|
|
|
FocusedTripleOrPathPattern {
|
|
|
|
focus: current_list_node,
|
|
|
|
patterns
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CollectionPath_item -> FocusedTripleOrPathPattern<TermOrVariable> = p:GraphNodePath _ { p }
|
|
|
|
|
|
|
|
//[104]
|
|
|
|
GraphNode -> FocusedTriplePattern<TermOrVariable> =
|
|
|
|
t:VarOrTerm { FocusedTriplePattern::new(t) } /
|
|
|
|
TriplesNode
|
|
|
|
|
|
|
|
//[105]
|
|
|
|
GraphNodePath -> FocusedTripleOrPathPattern<TermOrVariable> =
|
|
|
|
t:VarOrTerm { FocusedTripleOrPathPattern::new(t) } /
|
|
|
|
TriplesNodePath
|
|
|
|
|
|
|
|
//[106]
|
|
|
|
VarOrTerm -> TermOrVariable =
|
|
|
|
v:Var { v.into() } /
|
|
|
|
t:GraphTerm { t.into() }
|
|
|
|
|
|
|
|
//[107]
|
|
|
|
VarOrIri -> NamedNodeOrVariable =
|
|
|
|
v:Var { v.into() } /
|
|
|
|
i:iri { i.into() }
|
|
|
|
|
|
|
|
//[108]
|
|
|
|
Var -> Variable = v:(VAR1 / VAR2) { Variable::new(v) }
|
|
|
|
|
|
|
|
//[109]
|
|
|
|
GraphTerm -> Term =
|
|
|
|
i:iri { i.into() } /
|
|
|
|
l:RDFLiteral { l.into() } /
|
|
|
|
l:NumericLiteral { l.into() } /
|
|
|
|
l:BooleanLiteral { l.into() } /
|
|
|
|
b:BlankNode { b.into() } /
|
|
|
|
NIL { rdf::NIL.clone().into() }
|
|
|
|
|
|
|
|
//[110]
|
|
|
|
Expression -> Expression = e:ConditionalOrExpression {e}
|
|
|
|
|
|
|
|
//[111]
|
|
|
|
ConditionalOrExpression -> Expression = e:ConditionalOrExpression_item **<1,> ("||" _) {?
|
|
|
|
not_empty_fold(e.into_iter(), |a, b| Expression::OrExpression(Box::new(a), Box::new(b)))
|
|
|
|
}
|
|
|
|
ConditionalOrExpression_item -> Expression = e:ConditionalAndExpression _ { e }
|
|
|
|
|
|
|
|
//[112]
|
|
|
|
ConditionalAndExpression -> Expression = e:ConditionalAndExpression_item **<1,> ("&&" _) {?
|
|
|
|
not_empty_fold(e.into_iter(), |a, b| Expression::AndExpression(Box::new(a), Box::new(b)))
|
|
|
|
}
|
|
|
|
ConditionalAndExpression_item -> Expression = e:ValueLogical _ { e }
|
|
|
|
|
|
|
|
//[113]
|
|
|
|
ValueLogical -> Expression = RelationalExpression
|
|
|
|
|
|
|
|
//[114]
|
|
|
|
RelationalExpression -> Expression =
|
|
|
|
a:NumericExpression _ "=" _ b:NumericExpression { Expression::EqualExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:NumericExpression _ "!=" _ b:NumericExpression { Expression::NotEqualExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:NumericExpression _ ">" _ b:NumericExpression { Expression::GreaterExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:NumericExpression _ ">=" _ b:NumericExpression { Expression::GreaterOrEqExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:NumericExpression _ "<" _ b:NumericExpression { Expression::LowerExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:NumericExpression _ "<=" _ b:NumericExpression { Expression::LowerOrEqExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:NumericExpression _ "IN"i _ b:ExpressionList { Expression::InExpression(Box::new(a), b) } /
|
|
|
|
a:NumericExpression _ "NOT"i _ "IN"i _ b:ExpressionList { Expression::NotInExpression(Box::new(a), b) } /
|
|
|
|
NumericExpression
|
|
|
|
|
|
|
|
//[115]
|
|
|
|
NumericExpression -> Expression = AdditiveExpression
|
|
|
|
|
|
|
|
//[116]
|
|
|
|
AdditiveExpression -> Expression =
|
|
|
|
a:MultiplicativeExpression _ '+' _ b:AdditiveExpression { Expression::AddExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:MultiplicativeExpression _ '-' _ b:AdditiveExpression { Expression::SubExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
MultiplicativeExpression
|
|
|
|
|
|
|
|
//[117]
|
|
|
|
MultiplicativeExpression -> Expression =
|
|
|
|
a:UnaryExpression _ '*' _ b:MultiplicativeExpression { Expression::MulExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
a:UnaryExpression _ '/' _ b:MultiplicativeExpression { Expression::DivExpression(Box::new(a), Box::new(b)) } /
|
|
|
|
UnaryExpression
|
|
|
|
|
|
|
|
//[118]
|
|
|
|
UnaryExpression -> Expression =
|
|
|
|
'!' _ e:PrimaryExpression { Expression::UnaryNotExpression(Box::new(e)) } /
|
|
|
|
'+' _ e:PrimaryExpression { Expression::UnaryPlusExpression(Box::new(e)) } /
|
|
|
|
'-' _ e:PrimaryExpression { Expression::UnaryMinusExpression(Box::new(e)) } /
|
|
|
|
PrimaryExpression
|
|
|
|
|
|
|
|
//[119]
|
|
|
|
PrimaryExpression -> Expression =
|
|
|
|
BrackettedExpression /
|
|
|
|
BuiltInCall /
|
|
|
|
iriOrFunction /
|
|
|
|
l:RDFLiteral { Expression::ConstantExpression(l.into()) } /
|
|
|
|
l:NumericLiteral { Expression::ConstantExpression(l.into()) } /
|
|
|
|
l:BooleanLiteral { Expression::ConstantExpression(l.into()) } /
|
|
|
|
v:Var { Expression::ConstantExpression(v.into()) }
|
|
|
|
|
|
|
|
//[120]
|
|
|
|
BrackettedExpression -> Expression = '(' _ e:Expression _ ')' { e }
|
|
|
|
|
|
|
|
//[121]
|
|
|
|
BuiltInCall -> Expression =
|
|
|
|
a:Aggregate { state.new_aggregation(a).into() } /
|
|
|
|
"STR"i _ '(' _ e:Expression _ ')' { Expression::StrFunctionCall(Box::new(e)) } /
|
|
|
|
"LANG"i _ '(' _ e:Expression _ ')' { Expression::LangFunctionCall(Box::new(e)) } /
|
|
|
|
"LANGMATCHES"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::LangMatchesFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"DATATYPE"i _ '(' _ e:Expression _ ')' { Expression::DatatypeFunctionCall(Box::new(e)) } /
|
|
|
|
"BOUND"i _ '(' _ v:Var _ ')' { Expression::BoundFunctionCall(v) } /
|
|
|
|
("IRI"i / "URI"i) _ '(' _ e:Expression _ ')' { Expression::IRIFunctionCall(Box::new(e)) } /
|
|
|
|
"BNODE"i '(' _ e:Expression _ ')' { Expression::BNodeFunctionCall(Some(Box::new(e))) } /
|
|
|
|
"BNODE"i NIL { Expression::BNodeFunctionCall(None) } /
|
|
|
|
"RAND"i _ NIL { Expression::RandFunctionCall() } /
|
|
|
|
"ABS"i _ '(' _ e:Expression _ ')' { Expression::AbsFunctionCall(Box::new(e)) } /
|
|
|
|
"CEIL"i _ '(' _ e:Expression _ ')' { Expression::CeilFunctionCall(Box::new(e)) } /
|
|
|
|
"FLOOR"i _ '(' _ e:Expression _ ')' { Expression::FloorFunctionCall(Box::new(e)) } /
|
|
|
|
"ROUND"i _ '(' _ e:Expression _ ')' { Expression::RoundFunctionCall(Box::new(e)) } /
|
|
|
|
"CONCAT"i e:ExpressionList { Expression::ConcatFunctionCall(e) } /
|
|
|
|
SubstringExpression /
|
|
|
|
"STRLEN"i _ '(' _ e: Expression _ ')' { Expression::StrLenFunctionCall(Box::new(e)) } /
|
|
|
|
StrReplaceExpression /
|
|
|
|
"UCASE"i _ '(' _ e:Expression _ ')' { Expression::UCaseFunctionCall(Box::new(e)) } /
|
|
|
|
"LCASE"i _ '(' _ e:Expression _ ')' { Expression::LCaseFunctionCall(Box::new(e)) } /
|
|
|
|
'ENCODE_FOR_URI' '(' _ e: Expression _ ')' { Expression::EncodeForURIFunctionCall(Box::new(e)) } /
|
|
|
|
"CONTAINS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::ContainsFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"STRSTARTS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrStartsFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"STRENDS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrEndsFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"STRBEFORE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrBeforeFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"STRAFTER"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrAfterFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"YEAR"i _ '(' _ e:Expression _ ')' { Expression::YearFunctionCall(Box::new(e)) } /
|
|
|
|
"MONTH"i _ '(' _ e:Expression _ ')' { Expression::MonthFunctionCall(Box::new(e)) } /
|
|
|
|
"DAY"i _ '(' _ e:Expression _ ')' { Expression::DayFunctionCall(Box::new(e)) } /
|
|
|
|
"HOURS"i _ '(' _ e:Expression _ ')' { Expression::HoursFunctionCall(Box::new(e)) } /
|
|
|
|
"MINUTES"i _ '(' _ e:Expression _ ')' { Expression::MinutesFunctionCall(Box::new(e)) } /
|
|
|
|
"SECONDS"i _ '(' _ e:Expression _ ')' { Expression::SecondsFunctionCall(Box::new(e)) } /
|
|
|
|
("TIMEZONE"i / "TZ"i) _ '(' _ e:Expression _ ')' { Expression::TimezoneFunctionCall(Box::new(e)) } /
|
|
|
|
"NOW"i _ NIL { Expression::NowFunctionCall() } /
|
|
|
|
"UUID"i _ NIL { Expression::UUIDFunctionCall() }/
|
|
|
|
"STRUUID"i _ NIL { Expression::StrUUIDFunctionCall() } /
|
|
|
|
"MD5"i '(' _ e:Expression _ ')' { Expression::MD5FunctionCall(Box::new(e)) } /
|
|
|
|
"SHA1"i '(' _ e:Expression _ ')' { Expression::SHA1FunctionCall(Box::new(e)) } /
|
|
|
|
"SHA256"i '(' _ e:Expression _ ')' { Expression::SHA256FunctionCall(Box::new(e)) } /
|
|
|
|
"SHA384"i '(' _ e:Expression _ ')' { Expression::SHA384FunctionCall(Box::new(e)) } /
|
|
|
|
"SHA512"i '(' _ e:Expression _ ')' { Expression::SHA512FunctionCall(Box::new(e)) } /
|
|
|
|
"COALESCE"i e:ExpressionList { Expression::CoalesceFunctionCall(e) } /
|
|
|
|
"IF"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::IfFunctionCall(Box::new(a), Box::new(b), Box::new(c)) } /
|
|
|
|
"STRLANG"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrLangFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"STRDT"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrDTFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
"sameTerm"i '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::SameTermFunctionCall(Box::new(a), Box::new(b)) } /
|
|
|
|
("isIRI"i / "isURI"i) _ '(' _ e:Expression _ ')' { Expression::IsIRIFunctionCall(Box::new(e)) } /
|
|
|
|
"isBLANK"i '(' _ e:Expression _ ')' { Expression::IsBlankFunctionCall(Box::new(e)) } /
|
|
|
|
"isLITERAL"i '(' _ e:Expression _ ')' { Expression::IsLiteralFunctionCall(Box::new(e)) } /
|
|
|
|
"isNUMERIC"i '(' _ e:Expression _ ')' { Expression::IsNumericFunctionCall(Box::new(e)) } /
|
|
|
|
RegexExpression /
|
|
|
|
ExistsFunc /
|
|
|
|
NotExistsFunc
|
|
|
|
|
|
|
|
//[122]
|
|
|
|
RegexExpression -> Expression =
|
|
|
|
"REGEX"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::RegexFunctionCall(Box::new(a), Box::new(b), Some(Box::new(c))) } /
|
|
|
|
"REGEX"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::RegexFunctionCall(Box::new(a), Box::new(b), None) }
|
|
|
|
|
|
|
|
|
|
|
|
SubstringExpression -> Expression =
|
|
|
|
"SUBSTR"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::SubStrFunctionCall(Box::new(a), Box::new(b), Some(Box::new(c))) } /
|
|
|
|
"SUBSTR"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::SubStrFunctionCall(Box::new(a), Box::new(b), None) }
|
|
|
|
|
|
|
|
|
|
|
|
//[124]
|
|
|
|
StrReplaceExpression -> Expression =
|
|
|
|
"REPLACE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ',' _ d:Expression _ ')' { Expression::ReplaceFunctionCall(Box::new(a), Box::new(b), Box::new(c), Some(Box::new(d))) } /
|
|
|
|
"REPLACE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::ReplaceFunctionCall(Box::new(a), Box::new(b), Box::new(c), None) }
|
|
|
|
|
|
|
|
//[125]
|
|
|
|
ExistsFunc -> Expression = "EXISTS"i _ p:GroupGraphPattern { Expression::ExistsFunctionCall(Box::new(p)) }
|
|
|
|
|
|
|
|
//[126]
|
|
|
|
NotExistsFunc -> Expression = "NOT"i _ "EXISTS"i _ p:GroupGraphPattern { Expression::UnaryNotExpression(Box::new(Expression::ExistsFunctionCall(Box::new(p)))) }
|
|
|
|
|
|
|
|
//[127]
|
|
|
|
Aggregate -> Aggregation =
|
|
|
|
"COUNT"i _ '(' _ "DISTINCT"i _ '*' _ ')' { Aggregation::Count(None, true) } /
|
|
|
|
"COUNT"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Count(Some(Box::new(e)), true) } /
|
|
|
|
"COUNT"i _ '(' _ '*' _ ')' { Aggregation::Count(None, false) } /
|
|
|
|
"COUNT"i _ '(' _ e:Expression _ ')' { Aggregation::Count(Some(Box::new(e)), false) } /
|
|
|
|
"SUM"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Sum(Box::new(e), true) } /
|
|
|
|
"SUM"i _ '(' _ e:Expression _ ')' { Aggregation::Sum(Box::new(e), false) } /
|
|
|
|
"MIN"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Min(Box::new(e), true) } /
|
|
|
|
"MIN"i _ '(' _ e:Expression _ ')' { Aggregation::Min(Box::new(e), false) } /
|
|
|
|
"MAX"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Max(Box::new(e), true) } /
|
|
|
|
"MAX"i _ '(' _ e:Expression _ ')' { Aggregation::Max(Box::new(e), false) } /
|
|
|
|
"AVG"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Avg(Box::new(e), true) } /
|
|
|
|
"AVG"i _ '(' _ e:Expression _ ')' { Aggregation::Avg(Box::new(e), false) } /
|
|
|
|
"SAMPLE"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::Sample(Box::new(e), true) } /
|
|
|
|
"SAMPLE"i _ '(' _ e:Expression _ ')' { Aggregation::Sample(Box::new(e), false) } /
|
|
|
|
"GROUP_CONCAT"i _ '(' _ "DISTINCT"i _ e:Expression _ ';' _ 'SEPARATOR'i _ '=' _ s:String _ ')' { Aggregation::GroupConcat(Box::new(e), true, Some(s)) } /
|
|
|
|
"GROUP_CONCAT"i _ '(' _ "DISTINCT"i _ e:Expression _ ')' { Aggregation::GroupConcat(Box::new(e), true, None) } /
|
|
|
|
"GROUP_CONCAT"i _ '(' _ e:Expression _ ';' _ 'SEPARATOR'i _ '=' _ s:String _ ')' { Aggregation::GroupConcat(Box::new(e), true, Some(s)) } /
|
|
|
|
"GROUP_CONCAT"i _ '(' _ e:Expression _ ')' { Aggregation::GroupConcat(Box::new(e), false, None) }
|
|
|
|
|
|
|
|
//[128]
|
|
|
|
iriOrFunction -> Expression = i: iri _ a: ArgList? {
|
|
|
|
match a {
|
|
|
|
Some(a) => Expression::CustomFunctionCall(i, a),
|
|
|
|
None => Expression::ConstantExpression(i.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[129]
|
|
|
|
RDFLiteral -> Literal =
|
|
|
|
v:String _ "^^" _ t:iri { Literal::new_typed_literal(v, t) } /
|
|
|
|
v:String _ l:LANGTAG { Literal::new_language_tagged_literal(v, l) } /
|
|
|
|
v:String { Literal::new_simple_literal(v) }
|
|
|
|
|
|
|
|
//[130]
|
|
|
|
NumericLiteral -> Literal = NumericLiteralUnsigned / NumericLiteralPositive / NumericLiteralNegative
|
|
|
|
|
|
|
|
//[131]
|
|
|
|
NumericLiteralUnsigned -> Literal =
|
|
|
|
d:$(DOUBLE) {? match f64::from_str(d) {
|
|
|
|
Ok(value) => Ok(value.into()),
|
|
|
|
Err(_) => Err("Invalid xsd:double")
|
|
|
|
} } /
|
|
|
|
d:$(DECIMAL) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
|
|
|
|
i:$(INTEGER) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }
|
|
|
|
|
|
|
|
//[132]
|
|
|
|
NumericLiteralPositive -> Literal =
|
|
|
|
d:$(DOUBLE_POSITIVE) {? match f64::from_str(d) {
|
|
|
|
Ok(value) => Ok(value.into()),
|
|
|
|
Err(_) => Err("Invalid xsd:double")
|
|
|
|
} } /
|
|
|
|
d:$(DECIMAL_POSITIVE) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
|
|
|
|
i:$(INTEGER_POSITIVE) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }
|
|
|
|
|
|
|
|
|
|
|
|
//[133]
|
|
|
|
NumericLiteralNegative -> Literal =
|
|
|
|
d:$(DOUBLE_NEGATIVE) {? match f64::from_str(d) {
|
|
|
|
Ok(value) => Ok(value.into()),
|
|
|
|
Err(_) => Err("Invalid xsd:double")
|
|
|
|
} } /
|
|
|
|
d:$(DECIMAL_NEGATIVE) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
|
|
|
|
i:$(INTEGER_NEGATIVE) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }
|
|
|
|
|
|
|
|
//[134]
|
|
|
|
BooleanLiteral -> Literal =
|
|
|
|
"true" { true.into() } /
|
|
|
|
"false" { false.into() }
|
|
|
|
|
|
|
|
//[135]
|
|
|
|
String -> String = STRING_LITERAL_LONG1 / STRING_LITERAL_LONG2 / STRING_LITERAL1 / STRING_LITERAL2
|
|
|
|
|
|
|
|
//[136]
|
|
|
|
iri -> NamedNode = i:(IRIREF / PrefixedName) {?
|
|
|
|
match state.url_parser().parse(&i) {
|
|
|
|
Ok(url) => Ok(NamedNode::new(url)),
|
|
|
|
Err(error) => Err("IRI parsing failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//[137]
|
|
|
|
PrefixedName -> String = PNAME_LN /
|
|
|
|
ns:PNAME_NS {? state.namespaces.get(ns).cloned().ok_or("Prefix not found") }
|
|
|
|
|
|
|
|
//[138]
|
|
|
|
BlankNode -> BlankNode =
|
|
|
|
b:BLANK_NODE_LABEL { state.bnodes_map.entry(b.to_string()).or_insert_with(BlankNode::default).clone() } /
|
|
|
|
ANON { BlankNode::default() }
|
|
|
|
|
|
|
|
//[139]
|
|
|
|
IRIREF -> String = "<" i:$(([^\u{00}-\u{20}<>"{}|^\u{60}\u{5c}])*) ">" {
|
|
|
|
i.to_owned()
|
|
|
|
}
|
|
|
|
|
|
|
|
//[140]
|
|
|
|
PNAME_NS -> &'input str = ns:$(PN_PREFIX? ":") {
|
|
|
|
ns
|
|
|
|
}
|
|
|
|
|
|
|
|
//[141]
|
|
|
|
PNAME_LN -> String = ns:$(PNAME_NS) local:PN_LOCAL {?
|
|
|
|
state.namespaces.get(ns).map(|v| v.clone() + &local).ok_or("Prefix not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
//[142]
|
|
|
|
BLANK_NODE_LABEL -> &'input str = "_:" b:$(([0-9] / PN_CHARS_U) PN_CHARS* ("."+ PN_CHARS+)*) {
|
|
|
|
b
|
|
|
|
}
|
|
|
|
|
|
|
|
//[143]
|
|
|
|
VAR1 -> &'input str = '?' v:$(VARNAME) { v }
|
|
|
|
|
|
|
|
//[144]
|
|
|
|
VAR2 -> &'input str = '$' v:$(VARNAME) { v }
|
|
|
|
|
|
|
|
//[145]
|
|
|
|
LANGTAG -> &'input str = "@" l:$([a-zA-Z]+ ("-" [a-zA-Z0-9]+)*) {
|
|
|
|
l
|
|
|
|
}
|
|
|
|
|
|
|
|
//[146]
|
|
|
|
INTEGER -> () = [0-9]+
|
|
|
|
|
|
|
|
//[147]
|
|
|
|
DECIMAL -> () = ([0-9]+ "." [0-9]* / [0-9]* "." [0-9]+)
|
|
|
|
|
|
|
|
//[148]
|
|
|
|
DOUBLE -> () = ([0-9]+ "." [0-9]* / "." [0-9]+ / [0-9]+) EXPONENT
|
|
|
|
|
|
|
|
//[149]
|
|
|
|
INTEGER_POSITIVE -> () = "+" _ INTEGER
|
|
|
|
|
|
|
|
//[150]
|
|
|
|
DECIMAL_POSITIVE -> () = "+" _ DECIMAL
|
|
|
|
|
|
|
|
//[151]
|
|
|
|
DOUBLE_POSITIVE -> () = "+" _ DOUBLE
|
|
|
|
|
|
|
|
//[152]
|
|
|
|
INTEGER_NEGATIVE -> () = "-" _ INTEGER
|
|
|
|
|
|
|
|
//[153]
|
|
|
|
DECIMAL_NEGATIVE -> () = "-" _ DECIMAL
|
|
|
|
|
|
|
|
//[154]
|
|
|
|
DOUBLE_NEGATIVE -> () = "-" _ DOUBLE
|
|
|
|
|
|
|
|
//[155]
|
|
|
|
EXPONENT -> () = [eE] [+-]? [0-9]+
|
|
|
|
|
|
|
|
//[156]
|
|
|
|
STRING_LITERAL1 -> String = "'" l:$((STRING_LITERAL1_simple_char / ECHAR)*) "'" {
|
|
|
|
unescape_echars(l).to_string()
|
|
|
|
}
|
|
|
|
STRING_LITERAL1_simple_char -> () = [^'\u{005c}\u{000a}\u{000d}]
|
|
|
|
|
|
|
|
|
|
|
|
//[157]
|
|
|
|
STRING_LITERAL2 -> String = "\"" l:$((STRING_LITERAL2_simple_char / ECHAR)*) "\"" {
|
|
|
|
unescape_echars(l).to_string()
|
|
|
|
}
|
|
|
|
STRING_LITERAL2_simple_char -> () = [^"\u{005c}\u{000a}\u{000d}]
|
|
|
|
|
|
|
|
//[158]
|
|
|
|
STRING_LITERAL_LONG1 -> String = "'''" l:$(STRING_LITERAL_LONG1_inner*) "'''" {
|
|
|
|
unescape_echars(l).to_string()
|
|
|
|
}
|
|
|
|
STRING_LITERAL_LONG1_inner -> () = ("''" / "'")? (STRING_LITERAL_LONG1_simple_char / ECHAR)
|
|
|
|
STRING_LITERAL_LONG1_simple_char -> () = [^'\u{005c}]
|
|
|
|
|
|
|
|
//[159]
|
|
|
|
STRING_LITERAL_LONG2 -> String = "\"\"\"" l:$(STRING_LITERAL_LONG2_inner*) "\"\"\"" {
|
|
|
|
unescape_echars(l).to_string()
|
|
|
|
}
|
|
|
|
STRING_LITERAL_LONG2_inner -> () = ("\"\"" / "\"")? (STRING_LITERAL_LONG2_simple_char / ECHAR)
|
|
|
|
STRING_LITERAL_LONG2_simple_char -> () = [^"\u{005c}]
|
|
|
|
|
|
|
|
//[160]
|
|
|
|
ECHAR -> () = "\\" [tbnrf"'\\]
|
|
|
|
|
|
|
|
//[161]
|
|
|
|
NIL -> () = "(" WS* ")"
|
|
|
|
|
|
|
|
//[162]
|
|
|
|
WS -> () = #quiet<[\u{20}\u{9}\u{D}\u{A}]>
|
|
|
|
|
|
|
|
//[163]
|
|
|
|
ANON -> () = '[' WS* ']'
|
|
|
|
|
|
|
|
//[164]
|
|
|
|
PN_CHARS_BASE -> () = [A-Za-z\u{00C0}-\u{00D6}\u{00D8}-\u{00F6}\u{00F8}-\u{02FF}\u{0370}-\u{037D}\u{037F}-\u{1FFF}\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFFD}]
|
|
|
|
|
|
|
|
//[165]
|
|
|
|
PN_CHARS_U -> () = '_' / PN_CHARS_BASE
|
|
|
|
|
|
|
|
//[166]
|
|
|
|
VARNAME -> () = ([0-9] / PN_CHARS_U) ([0-9\u{00B7}\u{0300}-\u{036F}\u{203F}-\u{2040}] / PN_CHARS_U)*
|
|
|
|
|
|
|
|
//[167]
|
|
|
|
PN_CHARS -> () = [\-0-9\u{00B7}\u{0300}-\u{036F}\u{203F}-\u{2040}] / PN_CHARS_U
|
|
|
|
|
|
|
|
//[168]
|
|
|
|
PN_PREFIX -> () = PN_CHARS_BASE PN_CHARS* ("."+ PN_CHARS+)*
|
|
|
|
|
|
|
|
//[169]
|
|
|
|
PN_LOCAL -> String = f:PN_LOCAL_first c:(PN_LOCAL_next*) e:(PN_LOCAL_next_dot*) {
|
|
|
|
f.to_string() + &c.concat() + &e.concat()
|
|
|
|
}
|
|
|
|
PN_LOCAL_first -> String =
|
|
|
|
c:$(":" / [0-9] / PN_CHARS_U) { c.into() } /
|
|
|
|
PLX
|
|
|
|
PN_LOCAL_next -> String =
|
|
|
|
c:$(":" / PN_CHARS) { c.into() } /
|
|
|
|
PLX
|
|
|
|
PN_LOCAL_next_dot -> String = d:$('.'+) f:PN_LOCAL_next* { d.to_string() + &f.concat()}
|
|
|
|
|
|
|
|
//[170]
|
|
|
|
PLX -> String =
|
|
|
|
p:$(PERCENT) { p.into() } /
|
|
|
|
e:PN_LOCAL_ESC { iter::once(e).collect() }
|
|
|
|
|
|
|
|
//[171]
|
|
|
|
PERCENT -> () = "%" HEX HEX
|
|
|
|
|
|
|
|
//[172]
|
|
|
|
HEX -> () = ([0-9A-Fa-f])
|
|
|
|
|
|
|
|
//[173]
|
|
|
|
PN_LOCAL_ESC -> char = "\\" c:$([_~\.\-!$&'()*+,;=/?#@%]) { c.chars().next().unwrap() } //TODO: added '/' to make tests pass but is it valid?
|
|
|
|
|
|
|
|
//space
|
|
|
|
_ = #quiet<([ \t\n\r] / comment)*>
|
|
|
|
//comment
|
|
|
|
comment = #quiet<"#" [^\r\n]*>
|