///|
priv enum Slot {
Fixed(Term)
Variable(String)
}
///|
priv enum Path {
Predicate(Term)
PathVar(String)
Inverse(Path)
Sequence(Path, Path)
Alternative(Path, Path)
ZeroMore(Path)
OneMore(Path)
ZeroOne(Path)
}
///|
priv enum Expr {
Constant(Term)
Reference(String)
Unary(String, Expr)
Binary(String, Expr, Expr)
Call(String, Array[Expr])
Aggregate(String, Expr?, Bool)
}
///|
priv enum Pattern {
Triple(Slot, Path, Slot)
Optional(Group)
Union(Array[Group])
Nested(Group)
Filter(Expr)
Bind(Expr, String)
Values(Array[String], Array[Array[Term?]])
Graph(Slot, Group)
Minus(Group)
}
///|
priv struct Group {
patterns : Array[Pattern]
}
///|
priv enum QueryForm {
Select
Ask
Construct
} derive(Eq)
///|
priv struct Projection {
expression : Expr
variable : String
}
///|
priv struct Query {
form : QueryForm
projections : Array[Projection]
all : Bool
distinct : Bool
group : Group
group_by : Array[Expr]
having : Array[Expr]
order : Array[(Expr, Bool)]
offset : Int32
limit : Int32?
template : Array[(Slot, Path, Slot)]
}
///|
pub struct Binding {
priv values : Map[String, Term]
}
///|
fn Binding::empty() -> Binding {
{ values: Map([]), }
}
///|
fn Binding::copy(self : Binding) -> Binding {
{ values: self.values.copy(), }
}
///|
pub fn Binding::get(self : Binding, variable : String) -> Term? {
self.values.get(variable)
}
///|
pub fn Binding::variables(self : Binding) -> Array[String] {
let names = self.values.keys().to_array()
names.sort()
names
}
///|
pub fn Binding::length(self : Binding) -> Int32 {
self.values.length()
}
///|
fn Binding::key(self : Binding, variables : Array[String]) -> String {
let out = StringBuilder()
for name in variables {
match self.values.get(name) {
Some(t) => out.write_string("B" + key_part(t.key()))
None => out.write_string("U")
}
}
out.to_string()
}
///|
fn Binding::bind(self : Binding, slot : Slot, value : Term) -> Bool {
match slot {
Fixed(t) => t == value
Variable(name) =>
match self.values.get(name) {
Some(t) => t == value
None => {
self.values[name] = value
true
}
}
}
}
///|
fn Binding::resolve(self : Binding, slot : Slot) -> Term? {
match slot {
Fixed(t) => Some(t)
Variable(name) => self.get(name)
}
}
///|
fn Binding::merge(self : Binding, other : Binding) -> Binding? {
let result = self.copy()
for name, value in other.values {
if !result.bind(Variable(name), value) {
return None
}
}
Some(result)
}