preserves/implementations/rust/preserves-path/src/step.rs

468 lines
14 KiB
Rust

// Selectors operate on IOValues because the AST includes keys of IOValue type.
// If we could make Schemas produce generics...
use crate::CompilationError;
use crate::context::Context;
use crate::predicate::CompiledPredicate;
use crate::predicate::Predicate;
use crate::schemas::path;
use num::bigint::BigInt;
use num::traits::cast::ToPrimitive;
use num::traits::cast::FromPrimitive;
use preserves::value::AtomClass;
use preserves::value::CompoundClass;
use preserves::value::IOValue;
use preserves::value::NestedValue;
use preserves::value::Value;
use preserves::value::ValueClass;
use preserves_schema::support::interpret;
use std::cell::RefCell;
use std::iter::Iterator;
use std::rc::Rc;
pub trait StepMaker {
fn connect(&self, step: Node) -> Result<Node, CompilationError>;
}
pub trait Step: std::fmt::Debug {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue);
fn finish(&mut self);
fn reset(&mut self) -> Vec<IOValue>;
}
macro_rules! delegate_finish_and_reset {
($self:ident, $target:expr) => {
fn finish(&mut $self) { $target.finish() }
fn reset(&mut $self) -> Vec<IOValue> { $target.reset() }
}
}
#[derive(Clone, Debug)]
pub struct Node(pub Rc<RefCell<dyn Step>>);
#[derive(Debug)]
struct AxisStep {
step: Node,
axis: path::Axis,
}
#[derive(Debug)]
struct CompareStep {
op: path::Comparison,
literal: IOValue,
step: Node,
}
#[derive(Debug)]
struct RegexStep {
regex: regex::Regex,
step: Node,
}
#[derive(Debug)]
struct TestStep {
pred: CompiledPredicate,
step: Node,
}
#[derive(Debug)]
struct RealStep {
step: Node,
}
#[derive(Debug)]
struct IntStep {
step: Node,
}
#[derive(Debug)]
struct VecCollector {
accumulator: Vec<IOValue>,
}
#[derive(Debug)]
pub struct BoolCollector {
seen_value: bool,
}
#[derive(Debug)]
struct KindStep {
kind: ValueClass,
step: Node,
}
#[derive(Debug)]
pub struct CountCollector {
count: usize,
}
#[derive(Debug)]
struct CountStep {
step: Node,
counter: Node,
}
impl Node {
fn new<S: Step + 'static>(s: S) -> Self {
Node(Rc::new(RefCell::new(s)))
}
pub fn test(&self, ctxt: &mut Context, value: &IOValue) -> bool {
!self.exec(ctxt, value).is_empty()
}
pub fn accept(&self, ctxt: &mut Context, value: &IOValue) {
self.0.borrow_mut().accept(ctxt, value)
}
pub fn finish(&self) {
self.0.borrow_mut().finish()
}
pub fn reset(&self) -> Vec<IOValue> {
self.0.borrow_mut().reset()
}
pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Vec<IOValue> {
self.accept(ctxt, value);
self.finish();
self.reset()
}
}
impl StepMaker for path::Selector {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
self.0.connect(step)
}
}
impl<S: StepMaker> StepMaker for Vec<S> {
fn connect(&self, mut step: Node) -> Result<Node, CompilationError> {
for s in self.iter().rev() {
step = s.connect(step)?;
}
Ok(step)
}
}
impl StepMaker for path::Step {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
match self {
path::Step::Axis(b) => (&**b).connect(step),
path::Step::Filter(b) => (&**b).connect(step),
path::Step::Function(b) => (&**b).connect(step),
}
}
}
impl StepMaker for path::Axis {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
Ok(Node::new(AxisStep { step, axis: self.clone() }))
}
}
fn descendants(ctxt: &mut Context, step: &mut Node, v: &IOValue) {
step.accept(ctxt, v);
for c in v.value().children() {
ctxt.with_path_step(&c, |ctxt| descendants(ctxt, step, &c));
}
}
impl Step for AxisStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
ctxt.with_path_step(value, |ctxt| match &self.axis {
path::Axis::Values =>
for c in value.value().children() {
self.step.accept(ctxt, &c)
},
path::Axis::Descendants =>
descendants(ctxt, &mut self.step, value),
path::Axis::At { key } => match value.value() {
Value::String(s) | Value::Symbol(s) =>
step_index(ctxt, s.chars(), &key, |c| IOValue::new(String::from(c)), &mut self.step),
Value::Record(r) =>
step_index(ctxt, r.fields().iter(), &key, |v| v.clone(), &mut self.step),
Value::Sequence(vs) =>
step_index(ctxt, vs.iter(), &key, |v| v.clone(), &mut self.step),
Value::Dictionary(d) =>
if let Some(v) = d.get(&key) {
self.step.accept(ctxt, v)
},
_ =>
(),
},
path::Axis::Label => if let Some(r) = value.value().as_record(None) {
self.step.accept(ctxt, r.label())
},
path::Axis::Keys => match value.value() {
Value::String(s) | Value::Symbol(s) =>
step_keys(ctxt, s.len(), &mut self.step),
Value::ByteString(bs) => step_keys(ctxt, bs.len(), &mut self.step),
Value::Record(r) => step_keys(ctxt, r.arity(), &mut self.step),
Value::Sequence(vs) => step_keys(ctxt, vs.len(), &mut self.step),
Value::Dictionary(d) =>
for k in d.keys() {
self.step.accept(ctxt, k)
},
_ => (),
},
path::Axis::Length => match value.value() {
Value::String(s) | Value::Symbol(s) =>
self.step.accept(ctxt, &IOValue::new(s.len())),
Value::ByteString(bs) => self.step.accept(ctxt, &IOValue::new(bs.len())),
Value::Record(r) => self.step.accept(ctxt, &IOValue::new(r.arity())),
Value::Sequence(vs) => self.step.accept(ctxt, &IOValue::new(vs.len())),
Value::Dictionary(d) => self.step.accept(ctxt, &IOValue::new(d.len())),
_ => self.step.accept(ctxt, &IOValue::new(0)),
},
path::Axis::Annotations =>
for c in value.annotations().slice() {
self.step.accept(ctxt, &c)
},
path::Axis::Embedded => if let Some(d) = value.value().as_embedded() {
self.step.accept(ctxt, d)
},
path::Axis::Parse { module, name } => {
if let Some(p) = interpret::Context::new(&ctxt.env.0).dynamic_parse(module, name, value) {
self.step.accept(ctxt, &p)
}
}
path::Axis::Unparse { module, name } => {
if let Some(p) = interpret::Context::new(&ctxt.env.0).dynamic_unparse(module, name, value) {
self.step.accept(ctxt, &p)
}
}
})
}
delegate_finish_and_reset!(self, self.step);
}
fn step_index<T, Ts: Iterator<Item = T>, F: FnOnce(T) -> IOValue>(
ctxt: &mut Context,
mut vs: Ts,
key: &IOValue,
f: F,
step: &mut Node,
) {
if let Some(i) = key.value().as_usize() {
match vs.nth(i) {
None => (),
Some(v) => step.accept(ctxt, &f(v)),
}
}
}
fn step_keys(ctxt: &mut Context, count: usize, step: &mut Node) {
for i in 0 .. count {
step.accept(ctxt, &IOValue::new(i))
}
}
impl StepMaker for path::Filter {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
match self {
path::Filter::Nop => Ok(step),
path::Filter::Compare { op, literal } => Ok(Node::new(CompareStep {
op: (**op).clone(),
literal: literal.clone(),
step,
})),
path::Filter::Regex { regex } => Ok(Node::new(RegexStep { regex: regex::Regex::new(regex)?, step })),
path::Filter::Test { pred } => Ok(Node::new(TestStep { pred: (&**pred).compile()?, step })),
path::Filter::Real => Ok(Node::new(RealStep { step })),
path::Filter::Int => Ok(Node::new(IntStep { step })),
path::Filter::Kind { kind } => Ok(Node::new(KindStep {
kind: match &**kind {
path::ValueKind::Boolean => ValueClass::Atomic(AtomClass::Boolean),
path::ValueKind::Float => ValueClass::Atomic(AtomClass::Float),
path::ValueKind::Double => ValueClass::Atomic(AtomClass::Double),
path::ValueKind::SignedInteger => ValueClass::Atomic(AtomClass::SignedInteger),
path::ValueKind::String => ValueClass::Atomic(AtomClass::String),
path::ValueKind::ByteString => ValueClass::Atomic(AtomClass::ByteString),
path::ValueKind::Symbol => ValueClass::Atomic(AtomClass::Symbol),
path::ValueKind::Record => ValueClass::Compound(CompoundClass::Record),
path::ValueKind::Sequence => ValueClass::Compound(CompoundClass::Sequence),
path::ValueKind::Set => ValueClass::Compound(CompoundClass::Set),
path::ValueKind::Dictionary => ValueClass::Compound(CompoundClass::Dictionary),
path::ValueKind::Embedded => ValueClass::Embedded,
},
step,
})),
}
}
}
impl Step for CompareStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
if match self.op {
path::Comparison::Eq => value == &self.literal,
path::Comparison::Ne => value != &self.literal,
path::Comparison::Lt => value < &self.literal,
path::Comparison::Ge => value >= &self.literal,
path::Comparison::Gt => value > &self.literal,
path::Comparison::Le => value <= &self.literal,
} {
self.step.accept(ctxt, value)
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for RegexStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
match value.value() {
Value::String(s) | Value::Symbol(s) =>
if self.regex.is_match(s) { self.step.accept(ctxt, value) },
_ =>
(),
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for TestStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
if self.pred.test(ctxt, value) {
self.step.accept(ctxt, value)
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for RealStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
match value.value() {
Value::SignedInteger(i) => if let Some(r) = BigInt::from(i).to_f64() {
self.step.accept(ctxt, &IOValue::new(r))
},
Value::Float(f) => self.step.accept(ctxt, &IOValue::new(f32::from(*f) as f64)),
Value::Double(_) => self.step.accept(ctxt, value),
_ => (),
}
}
delegate_finish_and_reset!(self, self.step);
}
impl Step for IntStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
match value.value() {
Value::SignedInteger(_) => self.step.accept(ctxt, value),
Value::Float(f) => if let Some(i) = BigInt::from_f32(f32::from(*f)) {
self.step.accept(ctxt, &IOValue::new(i))
},
Value::Double(d) => if let Some(i) = BigInt::from_f64(f64::from(*d)) {
self.step.accept(ctxt, &IOValue::new(i))
},
_ => (),
}
}
delegate_finish_and_reset!(self, self.step);
}
impl VecCollector {
fn new() -> Node {
Node::new(VecCollector { accumulator: Vec::new() })
}
}
impl Step for VecCollector {
fn accept(&mut self, _ctxt: &mut Context, value: &IOValue) {
self.accumulator.push(value.clone())
}
fn finish(&mut self) {
}
fn reset(&mut self) -> Vec<IOValue> {
std::mem::take(&mut self.accumulator)
}
}
impl BoolCollector {
pub fn new() -> Node {
Node::new(BoolCollector { seen_value: false })
}
}
impl Step for BoolCollector {
fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
self.seen_value = true
}
fn finish(&mut self) {
}
fn reset(&mut self) -> Vec<IOValue> {
let result = if self.seen_value { vec![IOValue::new(true)] } else { vec![] };
self.seen_value = false;
result
}
}
impl Step for KindStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
if value.value_class() == self.kind {
self.step.accept(ctxt, value)
}
}
delegate_finish_and_reset!(self, self.step);
}
impl path::Selector {
pub fn compile(&self) -> Result<Node, CompilationError> {
self.connect(VecCollector::new())
}
pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Result<Vec<IOValue>, CompilationError> {
Ok(self.compile()?.exec(ctxt, value))
}
}
impl StepMaker for path::Function {
fn connect(&self, step: Node) -> Result<Node, CompilationError> {
// For now, there's just one function: `count`.
Ok(Node::new(CountStep { step, counter: self.selector.connect(CountCollector::new())? }))
}
}
impl CountCollector {
pub fn new() -> Node {
Node::new(CountCollector { count: 0 })
}
}
impl Step for CountCollector {
fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
self.count += 1
}
fn finish(&mut self) {
}
fn reset(&mut self) -> Vec<IOValue> {
let result = vec![IOValue::new(self.count)];
self.count = 0;
result
}
}
impl Step for CountStep {
fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
let count = &self.counter.exec(ctxt, value)[0];
self.step.accept(ctxt, count)
}
delegate_finish_and_reset!(self, self.step);
}