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::AtomClass;
15use preserves::CompoundClass;
16use preserves::IOValue;
17use preserves::SignedInteger;
18use preserves::ValueClass;
19use preserves::ValueImpl;
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.children() {
174        ctxt.with_path_step(c.as_ref(), |ctxt| descendants(ctxt, step, c.as_ref()));
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.as_ref())
184                }
185            }
186            path::Axis::Descendants => descendants(ctxt, &mut self.step, value),
187            path::Axis::At { key } => match value.value_class() {
188                ValueClass::Atomic(AtomClass::String) =>
189                    step_index(ctxt,
190                               value.as_string().unwrap().chars(),
191                               key.into(),
192                               |c| IOValue::new(String::from(c)),
193                               &mut self.step),
194                ValueClass::Atomic(AtomClass::Symbol) =>
195                    step_index(ctxt,
196                               value.as_symbol().unwrap().chars(),
197                               key.into(),
198                               |c| IOValue::new(String::from(c)),
199                               &mut self.step),
200                ValueClass::Compound(CompoundClass::Record) |
201                ValueClass::Compound(CompoundClass::Sequence) =>
202                    step_index(ctxt, value.iter(), key.into(), |v| v.into(), &mut self.step),
203                ValueClass::Compound(CompoundClass::Dictionary) => {
204                    if let Some(v) = value.get(&key) {
205                        self.step.accept(ctxt, &v.into())
206                    }
207                }
208                _ => (),
209            },
210            path::Axis::Label => {
211                if value.is_record() {
212                    self.step.accept(ctxt, value.label().as_ref())
213                }
214            }
215            path::Axis::Keys => match value.value_class() {
216                ValueClass::Atomic(AtomClass::String) =>
217                    step_keys(ctxt, value.as_string().unwrap().len(), &mut self.step),
218                ValueClass::Atomic(AtomClass::Symbol) =>
219                    step_keys(ctxt, value.as_symbol().unwrap().len(), &mut self.step),
220                ValueClass::Atomic(AtomClass::ByteString) =>
221                    step_keys(ctxt, value.as_bytestring().unwrap().len(), &mut self.step),
222                ValueClass::Compound(CompoundClass::Record) |
223                ValueClass::Compound(CompoundClass::Sequence) =>
224                    step_keys(ctxt, value.len(), &mut self.step),
225                ValueClass::Compound(CompoundClass::Dictionary) => {
226                    for k in value.keys() {
227                        self.step.accept(ctxt, k.as_ref())
228                    }
229                }
230                _ => (),
231            },
232            path::Axis::Length => match value.value_class() {
233                ValueClass::Atomic(AtomClass::String) =>
234                    self.step.accept(ctxt, &IOValue::new(value.as_string().unwrap().len())),
235                ValueClass::Atomic(AtomClass::Symbol) =>
236                    self.step.accept(ctxt, &IOValue::new(value.as_symbol().unwrap().len())),
237                ValueClass::Atomic(AtomClass::ByteString) =>
238                    self.step.accept(ctxt, &IOValue::new(value.as_bytestring().unwrap().len())),
239                ValueClass::Compound(CompoundClass::Record) |
240                ValueClass::Compound(CompoundClass::Sequence) |
241                ValueClass::Compound(CompoundClass::Dictionary) =>
242                    self.step.accept(ctxt, &IOValue::new(value.len())),
243                _ => self.step.accept(ctxt, &IOValue::new(0)),
244            },
245            path::Axis::Annotations => {
246                if let Some(cs) = value.annotations() {
247                    for c in cs.iter() {
248                        self.step.accept(ctxt, c)
249                    }
250                }
251            }
252            path::Axis::Embedded => {
253                if let Some(d) = value.as_embedded() {
254                    self.step.accept(ctxt, &d)
255                }
256            }
257            path::Axis::Parse { module, name } => {
258                if let Some(p) =
259                    interpret::Context::new(&ctxt.env.0).dynamic_parse(module, name, value.into())
260                {
261                    self.step.accept(ctxt, p.as_ref())
262                }
263            }
264            path::Axis::Unparse { module, name } => {
265                if let Some(p) =
266                    interpret::Context::new(&ctxt.env.0).dynamic_unparse(module, name, value.into())
267                {
268                    self.step.accept(ctxt, p.as_ref())
269                }
270            }
271        })
272    }
273
274    delegate_finish_and_reset!(self, self.step);
275}
276
277fn step_index<T, Ts: Iterator<Item = T>, F: FnOnce(T) -> IOValue>(
278    ctxt: &mut Context,
279    mut vs: Ts,
280    key: &IOValue,
281    f: F,
282    step: &mut Node,
283) {
284    if let Some(Ok(i)) = key.value().as_usize() {
285        match vs.nth(i) {
286            None => (),
287            Some(v) => step.accept(ctxt, &f(v)),
288        }
289    }
290}
291
292fn step_keys(ctxt: &mut Context, count: usize, step: &mut Node) {
293    for i in 0..count {
294        step.accept(ctxt, &IOValue::new(i))
295    }
296}
297
298impl StepMaker for path::Filter {
299    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
300        match self {
301            path::Filter::Nop => Ok(step),
302            path::Filter::Compare { op, literal } => Ok(Node::new(CompareStep {
303                op: op.clone(),
304                literal: literal.clone().into(),
305                step,
306            })),
307            path::Filter::Regex { regex } => Ok(Node::new(RegexStep {
308                regex: regex::Regex::new(regex)?,
309                step,
310            })),
311            path::Filter::Test { pred } => Ok(Node::new(TestStep {
312                pred: pred.compile()?,
313                step,
314            })),
315            path::Filter::Real => Ok(Node::new(RealStep { step })),
316            path::Filter::Int => Ok(Node::new(IntStep { step })),
317            path::Filter::Kind { kind } => Ok(Node::new(KindStep {
318                kind: match kind {
319                    path::ValueKind::Boolean => ValueClass::Atomic(AtomClass::Boolean),
320                    path::ValueKind::Double => ValueClass::Atomic(AtomClass::Double),
321                    path::ValueKind::SignedInteger => ValueClass::Atomic(AtomClass::SignedInteger),
322                    path::ValueKind::String => ValueClass::Atomic(AtomClass::String),
323                    path::ValueKind::ByteString => ValueClass::Atomic(AtomClass::ByteString),
324                    path::ValueKind::Symbol => ValueClass::Atomic(AtomClass::Symbol),
325                    path::ValueKind::Record => ValueClass::Compound(CompoundClass::Record),
326                    path::ValueKind::Sequence => ValueClass::Compound(CompoundClass::Sequence),
327                    path::ValueKind::Set => ValueClass::Compound(CompoundClass::Set),
328                    path::ValueKind::Dictionary => ValueClass::Compound(CompoundClass::Dictionary),
329                    path::ValueKind::Embedded => ValueClass::Embedded,
330                },
331                step,
332            })),
333        }
334    }
335}
336
337impl Step for CompareStep {
338    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
339        if match self.op {
340            path::Comparison::Eq => value == &self.literal,
341            path::Comparison::Ne => value != &self.literal,
342            path::Comparison::Lt => value < &self.literal,
343            path::Comparison::Ge => value >= &self.literal,
344            path::Comparison::Gt => value > &self.literal,
345            path::Comparison::Le => value <= &self.literal,
346        } {
347            self.step.accept(ctxt, value)
348        }
349    }
350
351    delegate_finish_and_reset!(self, self.step);
352}
353
354impl Step for RegexStep {
355    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
356        if let Some(s) = value.as_string().or_else(|| value.as_symbol()) {
357            if self.regex.is_match(&s) {
358                self.step.accept(ctxt, value)
359            }
360        }
361    }
362
363    delegate_finish_and_reset!(self, self.step);
364}
365
366impl Step for TestStep {
367    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
368        if self.pred.test(ctxt, value) {
369            self.step.accept(ctxt, value)
370        }
371    }
372
373    delegate_finish_and_reset!(self, self.step);
374}
375
376impl Step for RealStep {
377    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
378        if let Some(i) = value.as_signed_integer() {
379            if let Some(r) = BigInt::from(i.as_ref()).to_f64() {
380                self.step.accept(ctxt, &IOValue::new(r))
381            }
382        } else if let Some(_) = value.as_double() {
383            self.step.accept(ctxt, value)
384        }
385    }
386
387    delegate_finish_and_reset!(self, self.step);
388}
389
390impl Step for IntStep {
391    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
392        if let Some(_) = value.as_signed_integer() {
393            self.step.accept(ctxt, value)
394        } else if let Some(d) = value.as_double() {
395            if let Some(i) = BigInt::from_f64(f64::from(d)) {
396                self.step.accept(ctxt, &IOValue::new(SignedInteger::from(i)))
397            }
398        }
399    }
400
401    delegate_finish_and_reset!(self, self.step);
402}
403
404impl VecCollector {
405    fn new() -> Node {
406        Node::new(VecCollector {
407            accumulator: Vec::new(),
408        })
409    }
410}
411
412impl Step for VecCollector {
413    fn accept(&mut self, _ctxt: &mut Context, value: &IOValue) {
414        self.accumulator.push(value.clone())
415    }
416
417    fn finish(&mut self) {}
418
419    fn reset(&mut self) -> Vec<IOValue> {
420        std::mem::take(&mut self.accumulator)
421    }
422}
423
424impl BoolCollector {
425    pub fn new() -> Node {
426        Node::new(BoolCollector { seen_value: false })
427    }
428}
429
430impl Step for BoolCollector {
431    fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
432        self.seen_value = true
433    }
434
435    fn finish(&mut self) {}
436
437    fn reset(&mut self) -> Vec<IOValue> {
438        let result = if self.seen_value {
439            vec![IOValue::new(true)]
440        } else {
441            vec![]
442        };
443        self.seen_value = false;
444        result
445    }
446}
447
448impl Step for KindStep {
449    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
450        if value.value_class() == self.kind {
451            self.step.accept(ctxt, value)
452        }
453    }
454
455    delegate_finish_and_reset!(self, self.step);
456}
457
458impl path::Selector {
459    pub fn compile(&self) -> Result<Node, CompilationError> {
460        self.connect(VecCollector::new())
461    }
462
463    pub fn exec(
464        &self,
465        ctxt: &mut Context,
466        value: &IOValue,
467    ) -> Result<Vec<IOValue>, CompilationError> {
468        Ok(self.compile()?.exec(ctxt, value))
469    }
470}
471
472impl StepMaker for path::Function {
473    fn connect(&self, step: Node) -> Result<Node, CompilationError> {
474        // For now, there's just one function: `count`.
475        Ok(Node::new(CountStep {
476            step,
477            counter: self.selector.connect(CountCollector::new())?,
478        }))
479    }
480}
481
482impl CountCollector {
483    pub fn new() -> Node {
484        Node::new(CountCollector { count: 0 })
485    }
486}
487
488impl Step for CountCollector {
489    fn accept(&mut self, _ctxt: &mut Context, _value: &IOValue) {
490        self.count += 1
491    }
492
493    fn finish(&mut self) {}
494
495    fn reset(&mut self) -> Vec<IOValue> {
496        let result = vec![IOValue::new(self.count)];
497        self.count = 0;
498        result
499    }
500}
501
502impl Step for CountStep {
503    fn accept(&mut self, ctxt: &mut Context, value: &IOValue) {
504        let count = &self.counter.exec(ctxt, value)[0];
505        self.step.accept(ctxt, count)
506    }
507
508    delegate_finish_and_reset!(self, self.step);
509}