// 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; } pub trait Step: std::fmt::Debug { fn accept(&mut self, ctxt: &mut Context, value: &IOValue); fn finish(&mut self); fn reset(&mut self) -> Vec; } macro_rules! delegate_finish_and_reset { ($self:ident, $target:expr) => { fn finish(&mut $self) { $target.finish() } fn reset(&mut $self) -> Vec { $target.reset() } } } #[derive(Clone, Debug)] pub struct Node(pub Rc>); #[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, } #[derive(Debug)] pub struct BoolCollector { seen_value: bool, } #[derive(Debug)] struct KindStep { kind: ValueClass, step: Node, } impl Node { fn new(s: S) -> Self { Node(Rc::new(RefCell::new(s))) } pub fn test(&self, ctxt: &mut Context, value: &IOValue) -> bool { self.accept(ctxt, value); self.finish(); !self.reset().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 { self.0.borrow_mut().reset() } pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Vec { self.accept(ctxt, value); self.finish(); self.reset() } } impl StepMaker for path::Selector { fn connect(&self, step: Node) -> Result { self.0.connect(step) } } impl StepMaker for Vec { fn connect(&self, mut step: Node) -> Result { for s in self.iter().rev() { step = s.connect(step)?; } Ok(step) } } impl StepMaker for path::Step { fn connect(&self, step: Node) -> Result { match self { path::Step::Axis(b) => (&**b).connect(step), path::Step::Filter(b) => (&**b).connect(step), } } } impl StepMaker for path::Axis { fn connect(&self, step: Node) -> Result { 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, 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 { 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 { 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 { 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 { self.connect(VecCollector::new()) } pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Result, CompilationError> { Ok(self.compile()?.exec(ctxt, value)) } }