preserves_path/
step.rs

1// Selectors operate on IOValues because the AST includes keys of IOValue type.
2// If we could make Schemas produce generics...
3
4use crate::context::Context;
5use crate::predicate::CompiledPredicate;
6use crate::predicate::Predicate;
7use crate::schemas::path;
8use crate::CompilationError;
9
10use num::bigint::BigInt;
11use num::traits::cast::FromPrimitive;
12use num::traits::cast::ToPrimitive;
13
14use preserves::value::AtomClass;
15use preserves::value::CompoundClass;
16use preserves::value::IOValue;
17use preserves::value::NestedValue;
18use preserves::value::Value;
19use preserves::value::ValueClass;
20
21use preserves_schema::support::interpret;
22
23use std::cell::RefCell;
24use std::iter::Iterator;
25use std::rc::Rc;
26
27pub trait StepMaker {
28    fn connect(&self, step: Node) -> Result<Node, CompilationError>;
29}
30
31pub trait Step: std::fmt::Debug {
32    fn accept(&mut self, ctxt: &mut Context, value: &IOValue);
33    fn finish(&mut self);
34    fn reset(&mut self) -> Vec<IOValue>;
35}
36
37macro_rules! delegate_finish_and_reset {
38    ($self:ident, $target:expr) => {
39        fn finish(&mut $self) { $target.finish() }
40        fn reset(&mut $self) -> Vec<IOValue> { $target.reset() }
41    }
42}
43
44#[derive(Clone, Debug)]
45pub struct Node(pub Rc<RefCell<dyn Step>>);
46
47#[derive(Debug)]
48struct AxisStep {
49    step: Node,
50    axis: path::Axis,
51}
52
53#[derive(Debug)]
54struct CompareStep {
55    op: path::Comparison,
56    literal: IOValue,
57    step: Node,
58}
59
60#[derive(Debug)]
61struct RegexStep {
62    regex: regex::Regex,
63    step: Node,
64}
65
66#[derive(Debug)]
67struct TestStep {
68    pred: CompiledPredicate,
69    step: Node,
70}
71
72#[derive(Debug)]
73struct RealStep {
74    step: Node,
75}
76
77#[derive(Debug)]
78struct IntStep {
79    step: Node,
80}
81
82#[derive(Debug)]
83struct VecCollector {
84    accumulator: Vec<IOValue>,
85}
86
87#[derive(Debug)]
88pub struct BoolCollector {
89    seen_value: bool,
90}
91
92#[derive(Debug)]
93struct KindStep {
94    kind: ValueClass,
95    step: Node,
96}
97
98#[derive(Debug)]
99pub struct CountCollector {
100    count: usize,
101}
102
103#[derive(Debug)]
104struct CountStep {
105    step: Node,
106    counter: Node,
107}
108
109impl Node {
110    fn new<S: Step + 'static>(s: S) -> Self {
111        Node(Rc::new(RefCell::new(s)))
112    }
113
114    pub fn test(&self, ctxt: &mut Context, value: &IOValue) -> bool {
115        !self.exec(ctxt, value).is_empty()
116    }
117
118    pub fn accept(&self, ctxt: &mut Context, value: &IOValue) {
119        self.0.borrow_mut().accept(ctxt, value)
120    }
121
122    pub fn finish(&self) {
123        self.0.borrow_mut().finish()
124    }
125
126    pub fn reset(&self) -> Vec<IOValue> {
127        self.0.borrow_mut().reset()
128    }
129
130    pub fn exec(&self, ctxt: &mut Context, value: &IOValue) -> Vec<IOValue> {
131        self.accept(ctxt, value);
132        self.finish();
133        self.reset()
134    }
135}
136
137impl StepMaker for path::Selector {
138    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
139        self.0.connect(step)
140    }
141}
142
143impl<S: StepMaker> StepMaker for Vec<S> {
144    fn connect(&self, mut step: Node) -> Result<Node, CompilationError> {
145        for s in self.iter().rev() {
146            step = s.connect(step)?;
147        }
148        Ok(step)
149    }
150}
151
152impl StepMaker for path::Step {
153    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
154        match self {
155            path::Step::Axis(b) => (&**b).connect(step),
156            path::Step::Filter(b) => (&**b).connect(step),
157            path::Step::Function(b) => (&**b).connect(step),
158        }
159    }
160}
161
162impl StepMaker for path::Axis {
163    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
164        Ok(Node::new(AxisStep {
165            step,
166            axis: self.clone(),
167        }))
168    }
169}
170
171fn descendants(ctxt: &mut Context, step: &mut Node, v: &IOValue) {
172    step.accept(ctxt, v);
173    for c in v.value().children() {
174        ctxt.with_path_step(&c, |ctxt| descendants(ctxt, step, &c));
175    }
176}
177
178impl Step for AxisStep {
179    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
180        ctxt.with_path_step(value, |ctxt| match &self.axis {
181            path::Axis::Values => {
182                for c in value.value().children() {
183                    self.step.accept(ctxt, &c)
184                }
185            }
186            path::Axis::Descendants => descendants(ctxt, &mut self.step, value),
187            path::Axis::At { key } => match value.value() {
188                Value::String(s) | Value::Symbol(s) => step_index(
189                    ctxt,
190                    s.chars(),
191                    &key,
192                    |c| IOValue::new(String::from(c)),
193                    &mut self.step,
194                ),
195                Value::Record(r) => {
196                    step_index(ctxt, r.fields().iter(), &key, |v| v.clone(), &mut self.step)
197                }
198                Value::Sequence(vs) => {
199                    step_index(ctxt, vs.iter(), &key, |v| v.clone(), &mut self.step)
200                }
201                Value::Dictionary(d) => {
202                    if let Some(v) = d.get(&key) {
203                        self.step.accept(ctxt, v)
204                    }
205                }
206                _ => (),
207            },
208            path::Axis::Label => {
209                if let Some(r) = value.value().as_record(None) {
210                    self.step.accept(ctxt, r.label())
211                }
212            }
213            path::Axis::Keys => match value.value() {
214                Value::String(s) | Value::Symbol(s) => step_keys(ctxt, s.len(), &mut self.step),
215                Value::ByteString(bs) => step_keys(ctxt, bs.len(), &mut self.step),
216                Value::Record(r) => step_keys(ctxt, r.arity(), &mut self.step),
217                Value::Sequence(vs) => step_keys(ctxt, vs.len(), &mut self.step),
218                Value::Dictionary(d) => {
219                    for k in d.keys() {
220                        self.step.accept(ctxt, k)
221                    }
222                }
223                _ => (),
224            },
225            path::Axis::Length => match value.value() {
226                Value::String(s) | Value::Symbol(s) => {
227                    self.step.accept(ctxt, &IOValue::new(s.len()))
228                }
229                Value::ByteString(bs) => self.step.accept(ctxt, &IOValue::new(bs.len())),
230                Value::Record(r) => self.step.accept(ctxt, &IOValue::new(r.arity())),
231                Value::Sequence(vs) => self.step.accept(ctxt, &IOValue::new(vs.len())),
232                Value::Dictionary(d) => self.step.accept(ctxt, &IOValue::new(d.len())),
233                _ => self.step.accept(ctxt, &IOValue::new(0)),
234            },
235            path::Axis::Annotations => {
236                for c in value.annotations().slice() {
237                    self.step.accept(ctxt, &c)
238                }
239            }
240            path::Axis::Embedded => {
241                if let Some(d) = value.value().as_embedded() {
242                    self.step.accept(ctxt, d)
243                }
244            }
245            path::Axis::Parse { module, name } => {
246                if let Some(p) =
247                    interpret::Context::new(&ctxt.env.0).dynamic_parse(module, name, value)
248                {
249                    self.step.accept(ctxt, &p)
250                }
251            }
252            path::Axis::Unparse { module, name } => {
253                if let Some(p) =
254                    interpret::Context::new(&ctxt.env.0).dynamic_unparse(module, name, value)
255                {
256                    self.step.accept(ctxt, &p)
257                }
258            }
259        })
260    }
261
262    delegate_finish_and_reset!(self, self.step);
263}
264
265fn step_index<T, Ts: Iterator<Item = T>, F: FnOnce(T) -> IOValue>(
266    ctxt: &mut Context,
267    mut vs: Ts,
268    key: &IOValue,
269    f: F,
270    step: &mut Node,
271) {
272    if let Some(i) = key.value().as_usize() {
273        match vs.nth(i) {
274            None => (),
275            Some(v) => step.accept(ctxt, &f(v)),
276        }
277    }
278}
279
280fn step_keys(ctxt: &mut Context, count: usize, step: &mut Node) {
281    for i in 0..count {
282        step.accept(ctxt, &IOValue::new(i))
283    }
284}
285
286impl StepMaker for path::Filter {
287    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
288        match self {
289            path::Filter::Nop => Ok(step),
290            path::Filter::Compare { op, literal } => Ok(Node::new(CompareStep {
291                op: (**op).clone(),
292                literal: literal.clone(),
293                step,
294            })),
295            path::Filter::Regex { regex } => Ok(Node::new(RegexStep {
296                regex: regex::Regex::new(regex)?,
297                step,
298            })),
299            path::Filter::Test { pred } => Ok(Node::new(TestStep {
300                pred: (&**pred).compile()?,
301                step,
302            })),
303            path::Filter::Real => Ok(Node::new(RealStep { step })),
304            path::Filter::Int => Ok(Node::new(IntStep { step })),
305            path::Filter::Kind { kind } => Ok(Node::new(KindStep {
306                kind: match &**kind {
307                    path::ValueKind::Boolean => ValueClass::Atomic(AtomClass::Boolean),
308                    path::ValueKind::Double => ValueClass::Atomic(AtomClass::Double),
309                    path::ValueKind::SignedInteger => ValueClass::Atomic(AtomClass::SignedInteger),
310                    path::ValueKind::String => ValueClass::Atomic(AtomClass::String),
311                    path::ValueKind::ByteString => ValueClass::Atomic(AtomClass::ByteString),
312                    path::ValueKind::Symbol => ValueClass::Atomic(AtomClass::Symbol),
313                    path::ValueKind::Record => ValueClass::Compound(CompoundClass::Record),
314                    path::ValueKind::Sequence => ValueClass::Compound(CompoundClass::Sequence),
315                    path::ValueKind::Set => ValueClass::Compound(CompoundClass::Set),
316                    path::ValueKind::Dictionary => ValueClass::Compound(CompoundClass::Dictionary),
317                    path::ValueKind::Embedded => ValueClass::Embedded,
318                },
319                step,
320            })),
321        }
322    }
323}
324
325impl Step for CompareStep {
326    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
327        if match self.op {
328            path::Comparison::Eq => value == &self.literal,
329            path::Comparison::Ne => value != &self.literal,
330            path::Comparison::Lt => value < &self.literal,
331            path::Comparison::Ge => value >= &self.literal,
332            path::Comparison::Gt => value > &self.literal,
333            path::Comparison::Le => value <= &self.literal,
334        } {
335            self.step.accept(ctxt, value)
336        }
337    }
338
339    delegate_finish_and_reset!(self, self.step);
340}
341
342impl Step for RegexStep {
343    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
344        match value.value() {
345            Value::String(s) | Value::Symbol(s) => {
346                if self.regex.is_match(s) {
347                    self.step.accept(ctxt, value)
348                }
349            }
350            _ => (),
351        }
352    }
353
354    delegate_finish_and_reset!(self, self.step);
355}
356
357impl Step for TestStep {
358    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
359        if self.pred.test(ctxt, value) {
360            self.step.accept(ctxt, value)
361        }
362    }
363
364    delegate_finish_and_reset!(self, self.step);
365}
366
367impl Step for RealStep {
368    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
369        match value.value() {
370            Value::SignedInteger(i) => {
371                if let Some(r) = BigInt::from(i).to_f64() {
372                    self.step.accept(ctxt, &IOValue::new(r))
373                }
374            }
375            Value::Double(_) => self.step.accept(ctxt, value),
376            _ => (),
377        }
378    }
379
380    delegate_finish_and_reset!(self, self.step);
381}
382
383impl Step for IntStep {
384    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
385        match value.value() {
386            Value::SignedInteger(_) => self.step.accept(ctxt, value),
387            Value::Double(d) => {
388                if let Some(i) = BigInt::from_f64(f64::from(*d)) {
389                    self.step.accept(ctxt, &IOValue::new(i))
390                }
391            }
392            _ => (),
393        }
394    }
395
396    delegate_finish_and_reset!(self, self.step);
397}
398
399impl VecCollector {
400    fn new() -> Node {
401        Node::new(VecCollector {
402            accumulator: Vec::new(),
403        })
404    }
405}
406
407impl Step for VecCollector {
408    fn accept(&mut self, _ctxt: &mut Context, value: &IOValue) {
409        self.accumulator.push(value.clone())
410    }
411
412    fn finish(&mut self) {}
413
414    fn reset(&mut self) -> Vec<IOValue> {
415        std::mem::take(&mut self.accumulator)
416    }
417}
418
419impl BoolCollector {
420    pub fn new() -> Node {
421        Node::new(BoolCollector { seen_value: false })
422    }
423}
424
425impl Step for BoolCollector {
426    fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
427        self.seen_value = true
428    }
429
430    fn finish(&mut self) {}
431
432    fn reset(&mut self) -> Vec<IOValue> {
433        let result = if self.seen_value {
434            vec![IOValue::new(true)]
435        } else {
436            vec![]
437        };
438        self.seen_value = false;
439        result
440    }
441}
442
443impl Step for KindStep {
444    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
445        if value.value_class() == self.kind {
446            self.step.accept(ctxt, value)
447        }
448    }
449
450    delegate_finish_and_reset!(self, self.step);
451}
452
453impl path::Selector {
454    pub fn compile(&self) -> Result<Node, CompilationError> {
455        self.connect(VecCollector::new())
456    }
457
458    pub fn exec(
459        &self,
460        ctxt: &mut Context,
461        value: &IOValue,
462    ) -> Result<Vec<IOValue>, CompilationError> {
463        Ok(self.compile()?.exec(ctxt, value))
464    }
465}
466
467impl StepMaker for path::Function {
468    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
469        // For now, there's just one function: `count`.
470        Ok(Node::new(CountStep {
471            step,
472            counter: self.selector.connect(CountCollector::new())?,
473        }))
474    }
475}
476
477impl CountCollector {
478    pub fn new() -> Node {
479        Node::new(CountCollector { count: 0 })
480    }
481}
482
483impl Step for CountCollector {
484    fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
485        self.count += 1
486    }
487
488    fn finish(&mut self) {}
489
490    fn reset(&mut self) -> Vec<IOValue> {
491        let result = vec![IOValue::new(self.count)];
492        self.count = 0;
493        result
494    }
495}
496
497impl Step for CountStep {
498    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
499        let count = &self.counter.exec(ctxt, value)[0];
500        self.step.accept(ctxt, count)
501    }
502
503    delegate_finish_and_reset!(self, self.step);
504}