pub(crate) use crate::stdlib;
pub(crate) use crate::stdlib::flat_cell;
pub(crate) use crate::syntax::ast::visit::{self, Visitor as _};
pub(crate) use crate::syntax::ast::{
Anchor, Arg, Axis, Branch, CmpOp, Command, FnCall, Group, InterpSeg, Matcher, Operand,
PathElem, PredExpr, Predicate, Projection, PushBody, Query, Reach, RefProp, RegRef, Step,
};
pub(crate) use crate::thread::{Attachment, Position, Reg, Thread};
pub(crate) use crate::value::{SortKey, Table, Value};
pub(crate) use std::cmp::Ordering;
pub(crate) use std::collections::{HashMap, HashSet};
mod commands;
mod context;
pub mod env;
mod environ;
#[cfg(feature = "kaiv")]
pub mod kaiv_out;
pub mod library;
mod machine;
mod operand;
mod register;
mod run;
#[cfg(test)]
pub(crate) use crate::stdlib::arith::*;
pub(crate) use crate::stdlib::compare::*;
pub(crate) use crate::stdlib::text::*;
pub use crate::thread::prov::*;
pub(crate) use commands::*;
pub(crate) use context::*;
pub(crate) use environ::*;
pub(crate) use machine::*;
pub(crate) use operand::*;
pub(crate) use register::*;
pub use run::*;
pub(crate) struct Peers<X: Attachment> {
pub(crate) caps: Vec<Thread<X>>,
pub(crate) by_key: std::cell::OnceCell<HashMap<X::Key, Vec<usize>>>,
}
impl<X: Attachment> Peers<X> {
fn new(caps: Vec<Thread<X>>) -> Peers<X> {
Peers {
caps,
by_key: std::cell::OnceCell::new(),
}
}
pub(crate) fn at(&self, key: &X::Key) -> &[usize] {
let index = self.by_key.get_or_init(|| {
let mut m: HashMap<X::Key, Vec<usize>> = HashMap::new();
for (i, c) in self.caps.iter().enumerate() {
m.entry(c.ext.key()).or_default().push(i);
}
m
});
index.get(key).map_or(&[], |v| v.as_slice())
}
}
impl<X: Attachment> Thread<X> {
pub(crate) fn scope<'a>(
&'a self,
ordinal: Option<usize>,
peers: Option<&'a Peers<X>>,
outer: Option<&'a Scope<'a, X>>,
) -> Scope<'a, X> {
Scope {
prov: Some(&self.prov),
register: &self.register,
members: &self.members,
topic: self.topic.as_ref(),
ordinal,
captures: &self.captures,
named: &self.named,
ext: &self.ext,
view: self.ext.view(),
crossing: None,
witness: None,
peers,
outer,
driver: None,
}
}
}
pub(crate) struct Scope<'a, X: Attachment> {
pub(crate) register: &'a [Reg],
pub(crate) topic: Option<&'a Value>,
pub(crate) prov: Option<&'a Prov>,
pub(crate) ordinal: Option<usize>,
pub(crate) captures: &'a [String],
pub(crate) named: &'a [(String, String)],
pub(crate) members: &'a [Thread<X>],
pub(crate) peers: Option<&'a Peers<X>>,
pub(crate) outer: Option<&'a Scope<'a, X>>,
pub(crate) driver: Option<&'a Scope<'a, X>>,
pub(crate) ext: &'a X,
pub(crate) view: X::View,
pub(crate) crossing: Option<&'a X::Crossing>,
pub(crate) witness: Option<&'a X::Witness>,
}
impl<'a, X: Attachment> Clone for Scope<'a, X> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, X: Attachment> Copy for Scope<'a, X> {}
impl<'a, X: Attachment> Scope<'a, X> {
pub(crate) fn at(ext: &'a X) -> Scope<'a, X> {
Scope {
prov: None,
register: &[],
members: &[],
topic: None,
ordinal: None,
captures: &[],
named: &[],
peers: None,
outer: None,
driver: None,
ext,
view: Default::default(),
crossing: None,
witness: None,
}
}
}
pub(crate) trait Host {
type Ext: Attachment;
type Trace: Default;
fn root_ext(&self) -> Self::Ext;
fn unplaced_ext(&self) -> Self::Ext;
fn placed(&self, ext: &Self::Ext) -> bool;
fn scale_of(&self, expr: &str) -> Option<(f64, String)>;
fn property_of(&self, ext: &Self::Ext, name: &str) -> Option<Value>;
fn properties_of(&self, ext: &Self::Ext) -> Vec<(String, Value)>;
fn property_names_of(&self, ext: &Self::Ext) -> Vec<String>;
fn prefetch(&self, threads: &[Thread<Self::Ext>], names: &[&str]);
fn prov_at(&self, ext: &Self::Ext) -> Prov;
fn origin_at(&self, ext: &Self::Ext) -> Origin;
fn quantifier_bound(&self) -> usize;
fn node_ref(&self, ext: &Self::Ext) -> Option<Value>;
fn witnessed(&self, ext: &Self::Ext) -> bool;
fn origins_at(&self, ext: &Self::Ext) -> Origins;
fn node_scalar(&self, ext: &Self::Ext) -> Value;
fn project(&self, ext: &Self::Ext, proj: &Projection) -> Value;
fn origins_meta(&self, o: &Origins, key: &str) -> Option<Value>;
fn rel(
&self,
ext: &Self::Ext,
steps: &[PathElem],
anchor: &Anchor,
projection: Option<&Projection>,
trace: &Self::Trace,
scope: Scope<'_, Self::Ext>,
) -> Vec<Value>;
fn rel_threads(
&self,
ext: &Self::Ext,
steps: &[PathElem],
anchor: &Anchor,
projection: Option<&Projection>,
trace: &Self::Trace,
scope: Scope<'_, Self::Ext>,
) -> Vec<(Self::Ext, Option<Value>, Prov)>;
fn ctx(
&self,
ext: &Self::Ext,
index: Option<usize>,
steps: &[PathElem],
projection: Option<&Projection>,
trace: &Self::Trace,
scope: Scope<'_, Self::Ext>,
) -> Vec<Value>;
fn edges(&self, scope: Scope<'_, Self::Ext>, projection: Option<&Projection>) -> Vec<Value>;
fn edge(&self, scope: Scope<'_, Self::Ext>, projection: Option<&Projection>) -> Vec<Value>;
fn capsae(&self, scope: Scope<'_, Self::Ext>, projection: Option<&Projection>) -> Vec<Value>;
fn positions(&self, scope: Scope<'_, Self::Ext>, projection: Option<&Projection>) -> Vec<Value>;
fn operand_keys(
&self,
ext: &Self::Ext,
at: &Operand,
trace: &Self::Trace,
scope: Scope<'_, Self::Ext>,
) -> Vec<<Self::Ext as Attachment>::Key>;
fn restate(&self, scope: &Scope<'_, Self::Ext>, at: &Self::Ext) -> Self::Ext;
fn exists_binding(
&self,
ext: &Self::Ext,
conds: &[&PredExpr],
trace: &Self::Trace,
scope: Scope<'_, Self::Ext>,
) -> bool;
fn subcontext_traced(
&self,
body: &Query,
ext: &Self::Ext,
trace: &Self::Trace,
outer: Option<&Scope<'_, Self::Ext>>,
) -> (Value, Prov);
fn navigate(
&self,
branch: &Branch,
threads: Vec<Thread<Self::Ext>>,
trace: &Self::Trace,
outer: Option<&Scope<'_, Self::Ext>>,
peers: Option<&Peers<Self::Ext>>,
) -> Vec<Thread<Self::Ext>>;
fn node_to_json(&self, ext: &Self::Ext) -> Value;
fn node_to_json_text(&self, ext: &Self::Ext) -> String;
fn node_to_xml(&self, ext: &Self::Ext) -> String;
fn node_table(&self, ext: &Self::Ext) -> Result<Table, String>;
fn render_node(&self, ext: &Self::Ext, kind: &str) -> String;
fn render_values(&self, values: &[Value], kind: &str) -> String;
fn render_tree(
&self,
starts: &[Self::Ext],
spec: &crate::graph::tree::TreeSpec,
column: &dyn Fn(&Self::Ext, &Operand) -> Value,
) -> Result<String, String>;
fn value_to_xml(&self, v: &Value, tag: &str) -> String;
}
pub(crate) fn split_fields(fields: Vec<(String, Value, Prov)>) -> (Vec<(String, Value)>, Prov) {
let mut vs = Vec::with_capacity(fields.len());
let mut ps = Vec::with_capacity(fields.len());
for (k, v, p) in fields {
vs.push((k.clone(), v));
ps.push((k, p));
}
(vs, Prov::record(ps))
}
pub(crate) fn positional<T>(items: Vec<T>, pred: &Predicate) -> Vec<T> {
if let Predicate::Positions(parts) = pred {
let len = items.len();
let mut keep = vec![false; len];
for part in parts {
let chosen: Vec<usize> = positional((0..len).collect(), part);
for i in chosen {
keep[i] = true;
}
}
return items
.into_iter()
.zip(keep)
.filter_map(|(it, k)| k.then_some(it))
.collect();
}
match pred {
Predicate::Index(n) => match resolve_pos(*n, items.len()) {
Some(idx) => items.into_iter().nth(idx).into_iter().collect(),
None => Vec::new(),
},
Predicate::Range(start, end) => {
let len = items.len();
let s = match start {
None | Some(0) => 0,
Some(v) if *v > 0 => (*v - 1) as usize,
Some(v) => (len as i64 + *v).max(0) as usize,
};
let e = match end {
None => len,
Some(0) => 0,
Some(v) if *v > 0 => (*v as usize).min(len),
Some(v) => (len as i64 + *v + 1).max(0) as usize,
};
if s < e {
items.into_iter().skip(s).take(e - s).collect()
} else {
Vec::new()
}
}
Predicate::Expr(_) | Predicate::Computed(_) | Predicate::Positions(_) => items,
}
}
pub(crate) fn positions_of(v: &Value) -> Option<Predicate> {
match v {
Value::Int(n) => Some(Predicate::Index(*n)),
Value::List(items) => {
let mut parts = Vec::with_capacity(items.len());
for it in items.iter() {
match it {
Value::Int(n) => parts.push(Predicate::Index(*n)),
_ => return None,
}
}
Some(Predicate::Positions(parts))
}
_ => None,
}
}
pub(crate) type Captured = (Vec<String>, Vec<(String, String)>);
pub(crate) fn resolve_pos(i: i64, len: usize) -> Option<usize> {
if i > 0 && i as usize <= len {
Some(i as usize - 1)
} else if i < 0 && len as i64 + i >= 0 {
Some((len as i64 + i) as usize)
} else {
None
}
}