libunseemly/util/
mbe.rs

1#![macro_use]
2
3// March By Example: a user-friendly way to handle named subterms under Kleene stars,
4//  expressed through a special kind of environment.
5// This is intended to organize the subterms of an `Ast` node.
6// Using this as the evaluation environment of a program is probably interesting,
7//  but not necessarily in a good way.
8//
9//
10// The principle, when applied to pattern-based macro definitions, is as follows:
11//  Kleene stars in a macro grammar
12//    (e.g. `[f=Identifier [arg=Identifier ":" arg_t=Type]*]` )
13//   correspond to lists in an AST.
14//  The original syntactic structure is irrelevant.
15//   but there's only one name (e.g. `arg_t`) for the entire list of matched syntax.
16//
17// This whole thing nicely generalizes to nesting: we use variable-arity trees instead of lists,
18//  resulting in an `EnvMBE` (a March By Example Enviornment)
19//
20// For getting information *out* of an `EnvMBE`,
21//  we provide an operation ("march") that, given a set of names
22//    ("driving names", presumably the names "under the `*`")
23//   produces `n` environments, in which each of those names has a tree
24//    that is shorter by one level.
25//
26// One problem: what if two of the "driving names" repeat a different numbers of times?
27// Traditionally, this is a runtime error,
28//  but we'd like it to be a parser error:
29//   after all, it's the author of the syntax
30//    who has control over how many repetions there are of each thing.
31// So, we will let grammars specify when different Kleene stars
32//  must repeat the same number of times.
33// Violations of this rule are a parse error,
34//  and it's only legal to "march" with driving names
35//   that were matched (at the current level)
36//    (a) under the same `*`, or
37//    (b) under `*`s that must repeat the same number of times.
38// On the other hand, if the user wants "cross product" behavior,
39//  there's no reason that they can't get it.
40// We may add a facility to take syntax matched `a`, `b`, `c`... times,
41//  and produce `a × b × c` different environments.
42//
43//
44// This is based on Macro By Example, but this implementation isn't strictly about macros,
45//  which is why I changed the name!
46// The original MBE paper is
47//  "Macro-by-example: Deriving syntactic transformations from their specifications"
48//   by Kohlbecker and Wand
49//   ftp://www.cs.indiana.edu/pub/techreports/TR206.pdf
50//
51// Many interesting macros can be defined simply
52//  by specifying a grammar and a piece of quoted syntax,
53//  if the syntax transcription supports MBE.
54//  (This corresponds to Scheme's `syntax-rules` and Rust's `macro-rules`.)
55
56use crate::{name::*, util::assoc::Assoc};
57use std::{fmt, rc::Rc};
58
59// How on earth can one data structure need so many variations on `map`?
60// There's got to be a better way!
61
62/// `EnvMBE` is like an environment,
63///  except that some of its contents are "repeats",
64///   which represent _n_ different values
65///    (or repeats of repeats, etc.).
66/// Non-repeated values may be retrieved by `get_leaf`.
67/// To access repeated values, one must `march` them,
68///  which produces _n_ different environments,
69///   in which the marched values are not repeated (or one layer less repeated).
70/// Marching multiple repeated values at once
71///  is only permitted if they were constructed to repeat the same number of times.
72#[derive(Eq, Clone, Default)]
73// `Clone` needs to traverse the whole `Vec` ):
74pub struct EnvMBE<T: Clone> {
75    /// Non-repeated values
76    leaves: Assoc<Name, T>,
77
78    /// Outer vec holds distinct repetitions
79    ///  (i.e. differently-named, or entirely unnamed repetitions)
80    /// Note that some of the entries may be obsolete;
81    ///  deletions are marked by putting `None` in the `Assoc`s
82    ///   that index into this.
83    repeats: Vec<Rc<Vec<EnvMBE<T>>>>,
84
85    /// Where in `repeats` to look, if we want to traverse for a particular leaf.
86    /// We use `.unwrap_or(None)` when looking up into this
87    ///  so we can delete by storing `None`.
88    leaf_locations: Assoc<Name, Option<usize>>,
89
90    /// The location in `repeats` that represents a specific repetition name.
91    named_repeats: Assoc<Name, Option<usize>>,
92}
93
94// `custom_derive!` (or maybe `Reifiable!`) can't handle type bounds, so we need to do this manually
95impl<T: Clone + crate::runtime::reify::Reifiable> crate::runtime::reify::Reifiable for EnvMBE<T> {
96    fn ty_name() -> Name { n("EnvMBE") }
97    fn concrete_arguments() -> Option<Vec<crate::ast::Ast>> { Some(vec![T::ty_invocation()]) }
98    fn reify(&self) -> crate::runtime::eval::Value {
99        crate::runtime::eval::Value::Sequence(vec![
100            Rc::new(self.leaves.reify()),
101            Rc::new(self.repeats.reify()),
102            Rc::new(self.leaf_locations.reify()),
103            Rc::new(self.named_repeats.reify()),
104        ])
105    }
106    fn reflect(v: &crate::runtime::eval::Value) -> Self {
107        extract!((v) crate::runtime::eval::Value::Sequence = (ref parts) => {
108            EnvMBE {
109               leaves: <Assoc<Name, T>>::reflect(&*parts[0]),
110               repeats: <Vec<Rc<Vec<EnvMBE<T>>>>>::reflect(&*parts[1]),
111               leaf_locations: <Assoc<Name, Option<usize>>>::reflect(&*parts[2]),
112               named_repeats: <Assoc<Name, Option<usize>>>::reflect(&*parts[3])
113            }
114        })
115    }
116}
117
118impl<T: PartialEq + Clone> PartialEq for EnvMBE<T> {
119    fn eq(&self, other: &EnvMBE<T>) -> bool {
120        fn assoc_eq_modulo_none<K: Eq + std::hash::Hash + Clone, V: PartialEq + Clone>(
121            lhs: &Assoc<K, Option<V>>,
122            rhs: &Assoc<K, Option<V>>,
123        ) -> bool {
124            for (k, v_maybe) in lhs.iter_pairs() {
125                if let Some(ref v) = *v_maybe {
126                    if let Some(&Some(ref other_v)) = rhs.find(k) {
127                        if !(v == other_v) {
128                            return false;
129                        }
130                    } else {
131                        return false;
132                    }
133                }
134            }
135
136            for (other_k, other_v_maybe) in rhs.iter_pairs() {
137                if let Some(ref other_v) = *other_v_maybe {
138                    if let Some(&Some(ref v)) = rhs.find(other_k) {
139                        if !(v == other_v) {
140                            return false;
141                        }
142                    } else {
143                        return false;
144                    }
145                }
146            }
147
148            true
149        }
150
151        // This ought to handle permutations of `repeats`
152        // (matched with permutations of the indices in the assocs)
153        // but that's hard.
154
155        self.leaves == other.leaves
156            && self.repeats == other.repeats
157            && assoc_eq_modulo_none(&self.leaf_locations, &other.leaf_locations)
158            && assoc_eq_modulo_none(&self.named_repeats, &other.named_repeats)
159    }
160}
161
162impl<T: Clone + fmt::Debug> fmt::Debug for EnvMBE<T> {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        if self.leaves.empty() && self.repeats.is_empty() {
165            write!(f, "mbe∅")
166        } else {
167            write!(f, "{{ 🍂 {:#?}, ✶", self.leaves)?;
168            let mut first = true;
169            for (i, rep) in self.repeats.iter().enumerate() {
170                if !first {
171                    write!(f, ", ")?;
172                }
173                first = false;
174
175                // is it a named repeat?
176                for (name, idx_maybe) in self.named_repeats.iter_pairs() {
177                    if let Some(idx) = *idx_maybe {
178                        if idx == i {
179                            write!(f, "⋯({:#?})⋯ ", name)?;
180                        }
181                    }
182                }
183                write!(f, "{:#?}", rep)?;
184            }
185            write!(f, "}}")
186        }
187    }
188}
189
190impl<T: Clone + fmt::Display> fmt::Display for EnvMBE<T> {
191    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192        if self.leaves.empty() && self.repeats.is_empty() {
193            write!(f, "∅")
194        } else {
195            write!(f, "{{MBE {}, ✶", self.leaves)?;
196            let mut first = true;
197            for (i, rep) in self.repeats.iter().enumerate() {
198                if !first {
199                    write!(f, ", ")?;
200                }
201                first = false;
202
203                // is it a named repeat?
204                for (name, idx_maybe) in self.named_repeats.iter_pairs() {
205                    if let Some(idx) = *idx_maybe {
206                        if idx == i {
207                            write!(f, "⋯({})⋯ ", name)?;
208                        }
209                    }
210                }
211                for mbe in &**rep {
212                    write!(f, "{} ", mbe)?;
213                }
214            }
215            write!(f, "}}")
216        }
217    }
218}
219
220impl<T: Clone> EnvMBE<T> {
221    pub fn new() -> EnvMBE<T> {
222        EnvMBE {
223            leaves: Assoc::new(),
224            repeats: vec![],
225            leaf_locations: Assoc::new(),
226            named_repeats: Assoc::new(),
227        }
228    }
229
230    /// Creates an `EnvMBE` without any repetition
231    pub fn new_from_leaves(l: Assoc<Name, T>) -> EnvMBE<T> {
232        EnvMBE {
233            leaves: l,
234            repeats: vec![],
235            leaf_locations: Assoc::new(),
236            named_repeats: Assoc::new(),
237        }
238    }
239
240    /// Creates an `EnvMBE` containing a single anonymous repeat
241    pub fn new_from_anon_repeat(r: Vec<EnvMBE<T>>) -> EnvMBE<T> {
242        let mut res = EnvMBE::new();
243        res.add_anon_repeat(r);
244        res
245    }
246
247    /// Creates an `EnvMBE` containing a single named repeat
248    pub fn new_from_named_repeat(n: Name, r: Vec<EnvMBE<T>>) -> EnvMBE<T> {
249        let mut res = EnvMBE::new();
250        res.add_named_repeat(n, r);
251        res
252    }
253
254    /// Combine two `EnvMBE`s whose names (both environment names and repeat names) are disjoint,
255    /// or just overwrite the contents of the previous one.
256    /// This should maybe not be `pub` if we can avoid it.
257    /// Note: ideally, the larger one should be on the LHS.
258    pub fn combine_overriding(&self, rhs: &EnvMBE<T>) -> EnvMBE<T> {
259        let adjust_rhs_by = self.repeats.len();
260
261        let mut new_repeats = self.repeats.clone();
262        new_repeats.append(&mut rhs.repeats.clone());
263
264        EnvMBE {
265            leaves: self.leaves.set_assoc(&rhs.leaves),
266            repeats: new_repeats,
267            leaf_locations: self.leaf_locations.set_assoc(
268                &rhs.leaf_locations.map(|idx_opt| idx_opt.map(|idx| idx + adjust_rhs_by)),
269            ),
270            named_repeats: self.named_repeats.set_assoc(
271                &rhs.named_repeats.map(|idx_opt| idx_opt.map(|idx| idx + adjust_rhs_by)),
272            ),
273        }
274    }
275
276    /// Combine two `EnvMBE`s whose leaves should be disjoint, but which can contain
277    /// named repeats with the same name. This should make sense for combining the results of
278    /// matching two different chunks of a patern.
279    pub fn merge(&self, rhs: &EnvMBE<T>) -> EnvMBE<T> {
280        let mut res = self.clone();
281
282        let mut rhs_idx_is_named: Vec<bool> = rhs.repeats.iter().map(|_| false).collect();
283
284        // This could be made more efficient by just reusing the `Rc`s instead of cloning the
285        // arrays, but that would require reworking the interface.
286
287        for (n, rep_idx) in rhs.named_repeats.iter_pairs() {
288            if let Some(rep_idx) = *rep_idx {
289                res.add_named_repeat(*n, (*rhs.repeats[rep_idx]).clone());
290                rhs_idx_is_named[rep_idx] = true;
291            }
292        }
293
294        for (idx, rep) in rhs.repeats.iter().enumerate() {
295            if !rhs_idx_is_named[idx] {
296                res.add_anon_repeat((**rep).clone());
297            }
298        }
299
300        res.leaves = res.leaves.set_assoc(&rhs.leaves);
301
302        res
303    }
304
305    /// Given `driving_names`, marches the whole set of names that can march with them.
306    /// (Adding an additional name to `driving_names` will result in the same behavior,
307    ///  or a panic, in the case that the new name can't be marched with the existing ones.)
308    ///
309    /// This takes a `Vec` of `Name` instead of just one because a particular name might
310    /// not be transcribed at all here, and thus can't tell us how to repeat.
311    pub fn march_all(&self, driving_names: &[Name]) -> Vec<EnvMBE<T>> {
312        let mut march_loc: Option<(usize, Name)> = None;
313
314        for &n in driving_names {
315            match (march_loc, self.leaf_locations.find(&n).unwrap_or(&None)) {
316                (_, &None) => {}
317                (None, &Some(loc)) => march_loc = Some((loc, n)),
318                (Some((old_loc, old_name)), &Some(new_loc)) => {
319                    if old_loc != new_loc {
320                        panic!(
321                            "{:#?} and {:#?} cannot march together; they weren't matched to have \
322                             the same number of repeats",
323                            old_name, n
324                        );
325                    }
326                }
327            }
328        }
329
330        let march_loc = match march_loc {
331            None => {
332                return vec![];
333            } // FOOTGUN: assume that it is repeated zero times
334            Some((loc, _)) => loc,
335        };
336
337        let mut result = vec![];
338        for marched_out in self.repeats[march_loc].iter() {
339            // TODO: should we allow cross-product marching by keeping around unused repeats?
340            // Don't lose the current leaves:
341            result
342                .push(EnvMBE::new_from_leaves(self.leaves.clone()).combine_overriding(marched_out));
343        }
344
345        result
346    }
347
348    /// Get a non-repeated thing in the enviornment
349    pub fn get_leaf(&self, n: Name) -> Option<&T> { self.leaves.find(&n) }
350
351    pub fn get_rep_leaf(&self, n: Name) -> Option<Vec<&T>> {
352        // FOOTGUN: can't distinguish wrong leaf names from 0-repeated leaves
353        // TODO: remove get_rep_leaf_or_panic, as this never returns `None`
354
355        let mut res = vec![];
356        let leaf_loc = match self.leaf_locations.find(&n) {
357            Some(&Some(ll)) => ll,
358            _ => {
359                return Some(vec![]);
360            }
361        };
362
363        for r in &*self.repeats[leaf_loc] {
364            match r.get_leaf(n) {
365                Some(leaf) => res.push(leaf),
366                None => {
367                    return Some(vec![]);
368                } // `march` can leave us with dead leaf_locations
369            }
370        }
371        Some(res)
372    }
373
374    /// Extend with a non-repeated thing
375    pub fn add_leaf(&mut self, n: Name, v: T) { self.leaves = self.leaves.set(n, v); }
376
377    pub fn add_named_repeat(&mut self, n: Name, sub: Vec<EnvMBE<T>>) {
378        if sub.is_empty() {
379            return;
380        } // no-op-ish, but keep the repeats clean (good for `eq`)
381
382        match *self.named_repeats.find(&n).unwrap_or(&None) {
383            None => {
384                let new_index = self.repeats.len();
385                self.update_leaf_locs(new_index, &sub);
386
387                self.repeats.push(Rc::new(sub));
388                self.named_repeats = self.named_repeats.set(n, Some(new_index));
389            }
390            Some(idx) => {
391                if self.repeats[idx].len() != sub.len() {
392                    panic!(
393                        "Named repetition {:#?} is repeated {:#?} times in one place, {:#?} times \
394                         in another.",
395                        n,
396                        self.repeats[idx].len(),
397                        sub.len()
398                    )
399                }
400
401                self.update_leaf_locs(idx, &sub);
402
403                let mut new_repeats_at_idx = vec![];
404                for pairs in self.repeats[idx].iter().zip(sub.iter()) {
405                    new_repeats_at_idx.push(pairs.0.combine_overriding(pairs.1));
406                }
407                self.repeats[idx] = Rc::new(new_repeats_at_idx);
408            }
409        }
410    }
411
412    pub fn add_anon_repeat(&mut self, sub: Vec<EnvMBE<T>>) {
413        if sub.is_empty() {
414            return;
415        } // no-op-ish, but keep the repeats clean (good for `eq`)
416
417        let new_index = self.repeats.len();
418        self.update_leaf_locs(new_index, &sub);
419
420        self.repeats.push(Rc::new(sub));
421    }
422
423    pub fn anonimize_repeat(&mut self, n: Name) {
424        // Now you can't find me!
425        self.named_repeats = self.named_repeats.set(n, None);
426    }
427
428    pub fn map<NewT: Clone, F>(&self, f: &mut F) -> EnvMBE<NewT>
429    where F: FnMut(&T) -> NewT {
430        self.named_map(&mut |_n, elt| f(elt))
431    }
432
433    /// Map, but march the `ctxt` along with the structure of `self`
434    pub fn map_marched_against<NewT: Clone, Mode: crate::walk_mode::WalkMode, F>(
435        &self,
436        f: &mut F,
437        ctxt: &crate::ast_walk::LazyWalkReses<Mode>,
438    ) -> EnvMBE<NewT>
439    where
440        F: FnMut(&T, &crate::ast_walk::LazyWalkReses<Mode>) -> NewT,
441    {
442        EnvMBE {
443            leaves: self.leaves.map_borrow_f(&mut |t: &T| f(t, ctxt)),
444            repeats: self
445                .repeats
446                .iter()
447                .enumerate()
448                .map(|(rpt_idx, rc_vec_mbe): (usize, &Rc<Vec<EnvMBE<T>>>)| {
449                    let marched_ctxts = match self.leaf_locations.find_value(&Some(rpt_idx)) {
450                        Some(this_rpt_name) => ctxt.march_all(&[*this_rpt_name]),
451                        None => {
452                            // This repeat has no leaves.
453                            let mut res = vec![];
454                            res.resize(rc_vec_mbe.len(), ctxt.clone());
455                            res
456                        }
457                    };
458
459                    Rc::new(
460                        rc_vec_mbe
461                            .iter()
462                            .zip(marched_ctxts)
463                            .map(
464                                |(mbe, marched_ctxt): (
465                                    &EnvMBE<T>,
466                                    crate::ast_walk::LazyWalkReses<Mode>,
467                                )| {
468                                    mbe.map_marched_against(f, &marched_ctxt)
469                                },
470                            )
471                            .collect(),
472                    )
473                })
474                .collect(),
475            leaf_locations: self.leaf_locations.clone(),
476            named_repeats: self.named_repeats.clone(),
477        }
478    }
479
480    pub fn named_map<NewT: Clone, F>(&self, f: &mut F) -> EnvMBE<NewT>
481    where F: FnMut(&Name, &T) -> NewT {
482        EnvMBE {
483            leaves: self.leaves.keyed_map_borrow_f(f),
484            repeats: self
485                .repeats
486                .iter()
487                .map(|rc_vec_mbe: &Rc<Vec<EnvMBE<T>>>| {
488                    Rc::new(rc_vec_mbe.iter().map(|mbe: &EnvMBE<T>| mbe.named_map(f)).collect())
489                })
490                .collect(),
491            leaf_locations: self.leaf_locations.clone(),
492            named_repeats: self.named_repeats.clone(),
493        }
494    }
495
496    pub fn map_reduce<NewT: Clone>(
497        &self,
498        f: &dyn Fn(&T) -> NewT,
499        red: &dyn Fn(&NewT, &NewT) -> NewT,
500        base: NewT,
501    ) -> NewT {
502        let reduced: NewT = self.leaves.map(f).reduce(&|_k, v, res| red(v, &res), base);
503
504        self.repeats.iter().fold(reduced, |base: NewT, rc_vec_mbe: &Rc<Vec<EnvMBE<T>>>| {
505            rc_vec_mbe.iter().fold(base, |base: NewT, mbe: &EnvMBE<T>| mbe.map_reduce(f, red, base))
506        })
507    }
508
509    /// Provide the map function with the name of the current leaf,
510    /// and the appropriately-marched context element
511    pub fn marched_map<NewT: Clone, F>(&self, f: &mut F) -> EnvMBE<NewT>
512    where F: FnMut(Name, &EnvMBE<T>, &T) -> NewT {
513        self.marched_map_rec(self, f)
514    }
515
516    fn marched_map_rec<NewT: Clone, F>(&self, outer: &EnvMBE<T>, f: &mut F) -> EnvMBE<NewT>
517    where F: FnMut(Name, &EnvMBE<T>, &T) -> NewT {
518        let local_mbe = outer.combine_overriding(self);
519
520        let new_leaves =
521            self.leaves.keyed_map_borrow_f(&mut |n: &Name, elt: &T| f(*n, &local_mbe, elt));
522        EnvMBE {
523            leaves: new_leaves,
524            repeats: self
525                .repeats
526                .iter()
527                .map(|rc_vec_mbe: &Rc<Vec<EnvMBE<T>>>| {
528                    Rc::new(
529                        rc_vec_mbe
530                            .iter()
531                            .map(|marched_out: &EnvMBE<T>| marched_out.marched_map_rec(outer, f))
532                            .collect(),
533                    )
534                })
535                .collect(),
536            leaf_locations: self.leaf_locations.clone(),
537            named_repeats: self.named_repeats.clone(),
538        }
539    }
540
541    // TODO: we should just have the relevant functions return None...
542    pub fn can_map_with(&self, o: &EnvMBE<T>) -> bool {
543        let mut lhs_keys = std::collections::HashSet::<Name>::new();
544        for (k, _) in self.leaves.iter_pairs() {
545            lhs_keys.insert(*k);
546        }
547        let mut rhs_keys = std::collections::HashSet::<Name>::new();
548        for (k, _) in o.leaves.iter_pairs() {
549            rhs_keys.insert(*k);
550        }
551
552        if lhs_keys != rhs_keys {
553            return false;
554        }
555
556        if self.repeats.len() != o.repeats.len() {
557            return false;
558        }
559        for (subs, o_subs) in self.repeats.iter().zip(o.repeats.iter()) {
560            if subs.len() != o_subs.len() {
561                return false;
562            }
563            for (mbe, o_mbe) in subs.iter().zip(o_subs.iter()) {
564                if !mbe.can_map_with(o_mbe) {
565                    return false;
566                }
567            }
568        }
569
570        true
571    }
572
573    pub fn map_with<S: Clone, NewT: Clone>(
574        &self,
575        o: &EnvMBE<S>,
576        f: &dyn Fn(&T, &S) -> NewT,
577    ) -> EnvMBE<NewT> {
578        self.named_map_with(o, &|_name, l, r| f(l, r))
579    }
580
581    pub fn named_map_with<S: Clone, NewT: Clone>(
582        &self,
583        o: &EnvMBE<S>,
584        f: &dyn Fn(&Name, &T, &S) -> NewT,
585    ) -> EnvMBE<NewT> {
586        EnvMBE {
587            leaves: self.leaves.keyed_map_with(&o.leaves, f),
588
589            // This assumes that "equivalent" repeats have the same indices... ) :
590            repeats: self
591                .repeats
592                .iter()
593                .zip(o.repeats.iter())
594                .map(&|(rc_vec_mbe, o_rc_vec_mbe): (&Rc<Vec<EnvMBE<T>>>, &Rc<Vec<EnvMBE<S>>>)| {
595                    Rc::new(
596                        rc_vec_mbe
597                            .iter()
598                            .zip(o_rc_vec_mbe.iter())
599                            .map(|(mbe, o_mbe)| mbe.named_map_with(o_mbe, f))
600                            .collect(),
601                    )
602                })
603                .collect(),
604            leaf_locations: self.leaf_locations.clone(),
605            named_repeats: self.named_repeats.clone(),
606        }
607    }
608
609    pub fn map_reduce_with<S: Clone, NewT: Clone>(
610        &self,
611        other: &EnvMBE<S>,
612        f: &dyn Fn(&T, &S) -> NewT,
613        red: &dyn Fn(NewT, NewT) -> NewT,
614        base: NewT,
615    ) -> NewT {
616        // TODO #15: this panics all over the place if anything goes wrong
617        let mut reduced: NewT =
618            self.leaves.map_with(&other.leaves, f).reduce(&|_k, v, res| red(v.clone(), res), base);
619
620        let mut already_processed: Vec<bool> = self.repeats.iter().map(|_| false).collect();
621
622        for (leaf_name, self_idx) in self.leaf_locations.iter_pairs() {
623            let self_idx = match *self_idx {
624                Some(si) => si,
625                None => {
626                    continue;
627                }
628            };
629            if already_processed[self_idx] {
630                continue;
631            }
632            already_processed[self_idx] = true;
633
634            let other_idx = other.leaf_locations.find_or_panic(leaf_name).unwrap();
635
636            for (self_elt, other_elt) in
637                self.repeats[self_idx].iter().zip(other.repeats[other_idx].iter())
638            {
639                reduced = self_elt.map_reduce_with(other_elt, f, &red, reduced);
640            }
641        }
642
643        reduced
644    }
645
646    fn update_leaf_locs(&mut self, idx: usize, sub: &[EnvMBE<T>]) {
647        let mut already_placed_leaves = std::collections::HashSet::<Name>::new();
648        let mut already_placed_repeats = std::collections::HashSet::<Name>::new();
649
650        for sub_mbe in sub {
651            for leaf_name in sub_mbe.leaf_locations.iter_keys().chain(sub_mbe.leaves.iter_keys()) {
652                if !already_placed_leaves.contains(leaf_name) {
653                    self.leaf_locations = self.leaf_locations.set(*leaf_name, Some(idx));
654                    already_placed_leaves.insert(*leaf_name);
655                }
656            }
657            for repeat_name in sub_mbe.named_repeats.iter_keys() {
658                if !already_placed_repeats.contains(repeat_name) {
659                    self.named_repeats = self.named_repeats.set(*repeat_name, Some(idx));
660                    already_placed_repeats.insert(*repeat_name);
661                }
662            }
663        }
664    }
665
666    // If `f` turns a leaf into a `Vec`, splice those results in
667    pub fn heal_splices<E>(
668        &mut self,
669        f: &dyn Fn(&T) -> Result<Option<Vec<T>>, E>,
670    ) -> Result<(), E> {
671        for repeat in &mut self.repeats {
672            let mut cur_repeat: Vec<EnvMBE<T>> = (**repeat).clone();
673            let mut i = 0;
674            while i < cur_repeat.len() {
675                cur_repeat[i].heal_splices(f)?;
676
677                let mut splices = vec![];
678                {
679                    let n_and_vals = cur_repeat[i].leaves.iter_pairs();
680                    for (n, val) in n_and_vals {
681                        if let Some(splice) = f(val)? {
682                            splices.push((*n, splice));
683                        }
684                    }
685                }
686
687                if !splices.is_empty() {
688                    let mut template = cur_repeat.remove(i);
689
690                    // TODO: each of the splices better be the same length.
691                    // I don't know what has to go wrong to violate that rule.
692                    for rep in 0..splices[0].1.len() {
693                        for splice in &splices {
694                            template.add_leaf(splice.0, splice.1[rep].clone());
695                        }
696                        cur_repeat.insert(i + rep, template.clone())
697                    }
698                    i += splices[0].1.len();
699                } else {
700                    i += 1;
701                }
702            }
703            *repeat = Rc::new(cur_repeat)
704        }
705        Ok(())
706    }
707
708    // TODO: this should return a usable error
709    pub fn heal_splices__with<E, S: Clone>(
710        &mut self,
711        other: &EnvMBE<S>,
712        f: &dyn Fn(&T, &dyn Fn() -> Vec<S>) -> Result<Option<Vec<T>>, E>,
713    ) -> Result<(), E>
714    where
715        T: std::fmt::Debug,
716    {
717        for repeat in &mut self.repeats {
718            // Find the same repeat in `other`:
719            let mut names_needed = vec![];
720            for (name, _) in self.leaf_locations.iter_pairs() {
721                names_needed.push(name);
722            }
723            let other__rep_loc = match other.leaf_locations.find(names_needed[0]) {
724                Some(Some(l)) => *l,
725                _ => {
726                    return Ok(()); // Should become a mismatch error elsewhere (TODO: make an `E`)
727                }
728            };
729
730            let other__cur_repeat: &Vec<EnvMBE<S>> = &*other.repeats[other__rep_loc];
731            let mut cur_repeat: Vec<EnvMBE<T>> = (**repeat).clone();
732
733            // If an item splices, how wide does the other side need to be
734            //  in order to make everything line up?
735            let splice_length =
736                (other__cur_repeat.len() + 1).checked_sub(cur_repeat.len()).unwrap();
737
738            let mut i = 0;
739            let mut other_i = 0;
740            while i < cur_repeat.len() && other_i < other__cur_repeat.len() {
741                cur_repeat[i].heal_splices__with(&other__cur_repeat[other_i], f)?;
742
743                let mut splices = vec![];
744                {
745                    let n_and_vals = cur_repeat[i].leaves.iter_pairs();
746                    for (n, val) in n_and_vals {
747                        let concrete_splice__thunk = || {
748                            let mut result = vec![];
749                            for other_i in other__cur_repeat.iter().skip(i).take(splice_length) {
750                                result.push(other_i.leaves.find_or_panic(n).clone())
751                            }
752                            result
753                        };
754
755                        if let Some(splice) = f(val, &concrete_splice__thunk)? {
756                            splices.push((*n, splice));
757                        }
758                    }
759                }
760
761                if !splices.is_empty() {
762                    let mut template = cur_repeat.remove(i);
763
764                    // TODO: each of the splices better be the same length.
765                    // I don't know what has to go wrong to violate that rule.
766                    for rep in 0..splices[0].1.len() {
767                        for splice in &splices {
768                            template.add_leaf(splice.0, splice.1[rep].clone());
769                        }
770                        cur_repeat.insert(i + rep, template.clone())
771                    }
772                    i += splice_length;
773                    other_i += splice_length;
774                } else {
775                    i += 1;
776                    other_i += 1;
777                }
778            }
779            // The lengths might not line up, but that doesn't mean matching will fail!
780            // struct {a : Int b : Nat}  <:  struct {a : Int b : Nat c : Float}
781
782            *repeat = Rc::new(cur_repeat)
783        }
784        Ok(())
785    }
786}
787
788impl<T: Clone, E: Clone> EnvMBE<Result<T, E>> {
789    // Is `lift` the right term?
790    pub fn lift_result(&self) -> Result<EnvMBE<T>, E> {
791        // There's probably a nice and elegant way to do this with Result::from_iter, but not today
792        let mut leaves: Assoc<Name, T> = Assoc::new();
793        for (k, v) in self.leaves.iter_pairs() {
794            leaves = leaves.set(*k, (*v).clone()?);
795        }
796
797        let mut repeats = vec![];
798        for rep in &self.repeats {
799            let mut items = vec![];
800            for item in &**rep {
801                items.push(item.lift_result()?);
802            }
803            repeats.push(Rc::new(items));
804        }
805
806        Ok(EnvMBE {
807            leaves: leaves,
808            repeats: repeats,
809            leaf_locations: self.leaf_locations.clone(),
810            named_repeats: self.named_repeats.clone(),
811        })
812    }
813}
814
815impl<T: Clone + fmt::Debug> EnvMBE<T> {
816    // TODO: this should just take `Name`, not `&Name`
817    pub fn get_leaf_or_panic(&self, n: &Name) -> &T {
818        match self.leaves.find(n) {
819            Some(v) => v,
820            None => panic!(" {:#?} not found in {:#?} (perhaps it is still repeated?)", n, self),
821        }
822    }
823
824    pub fn get_rep_leaf_or_panic(&self, n: Name) -> Vec<&T> { self.get_rep_leaf(n).unwrap() }
825
826    pub fn map_flatten_rep_leaf_or_panic<S>(
827        &self,
828        n: Name,
829        depth: u8,
830        m: &dyn Fn(&T) -> S,
831        f: &dyn Fn(Vec<S>) -> S,
832    ) -> S {
833        if depth == 0 {
834            return m(self.get_leaf_or_panic(&n));
835        }
836        let leaf_loc = match self.leaf_locations.find(&n) {
837            Some(&Some(ll)) => ll,
838            _ => panic!("Leaf {} not found", n),
839        };
840
841        f(self.repeats[leaf_loc]
842            .iter()
843            .map(|mbe| mbe.map_flatten_rep_leaf_or_panic(n, depth - 1, m, f))
844            .collect())
845    }
846}
847
848#[test]
849fn basic_mbe() {
850    let mut mbe = EnvMBE::new();
851    mbe.add_leaf(n("eight"), 8 as i32);
852    mbe.add_leaf(n("nine"), 9);
853
854    assert!(mbe != EnvMBE::new());
855    assert!(EnvMBE::new() != mbe);
856
857    let teens_mbe = vec![
858        EnvMBE::new_from_leaves(assoc_n!("t" => 11)),
859        EnvMBE::new_from_leaves(assoc_n!("t" => 12)),
860        EnvMBE::new_from_leaves(assoc_n!("t" => 13)),
861    ];
862
863    mbe.add_named_repeat(n("low_two_digits"), teens_mbe.clone());
864
865    let big_mbe = vec![
866        EnvMBE::new_from_leaves(assoc_n!("y" => 9001)),
867        EnvMBE::new_from_leaves(assoc_n!("y" => 9002)),
868    ];
869
870    mbe.add_anon_repeat(big_mbe);
871
872    for (sub_mbe, teen) in mbe.march_all(&vec![n("t"), n("eight")]).iter().zip(vec![11, 12, 13]) {
873        assert_eq!(sub_mbe.get_leaf(n("eight")), Some(&8));
874        assert_eq!(sub_mbe.get_leaf(n("nine")), Some(&9));
875        assert_eq!(sub_mbe.get_leaf(n("t")), Some(&teen));
876        assert_eq!(sub_mbe.get_leaf(n("y")), None);
877
878        for (sub_sub_mbe, big) in
879            sub_mbe.march_all(&vec![n("y"), n("eight")]).iter().zip(vec![9001, 9002])
880        {
881            assert_eq!(sub_sub_mbe.get_leaf(n("eight")), Some(&8));
882            assert_eq!(sub_sub_mbe.get_leaf(n("nine")), Some(&9));
883            assert_eq!(sub_sub_mbe.get_leaf(n("t")), Some(&teen));
884            assert_eq!(sub_sub_mbe.get_leaf(n("y")), Some(&big));
885        }
886    }
887
888    let neg_teens_mbe = vec![
889        EnvMBE::new_from_leaves(assoc_n!("nt" => -11)),
890        EnvMBE::new_from_leaves(assoc_n!("nt" => -12)),
891        EnvMBE::new_from_leaves(assoc_n!("nt" => -13)),
892    ];
893
894    mbe.add_named_repeat(n("low_two_digits"), neg_teens_mbe);
895
896    for (sub_mbe, teen) in
897        mbe.march_all(&vec![n("t"), n("nt"), n("eight")]).iter().zip(vec![11, 12, 13])
898    {
899        assert_eq!(sub_mbe.get_leaf(n("eight")), Some(&8));
900        assert_eq!(sub_mbe.get_leaf(n("nine")), Some(&9));
901        assert_eq!(sub_mbe.get_leaf(n("t")), Some(&teen));
902        assert_eq!(sub_mbe.get_leaf(n("nt")), Some(&-teen));
903
904        for (sub_sub_mbe, big) in
905            sub_mbe.march_all(&vec![n("y"), n("eight")]).iter().zip(vec![9001, 9002])
906        {
907            assert_eq!(sub_sub_mbe.get_leaf(n("eight")), Some(&8));
908            assert_eq!(sub_sub_mbe.get_leaf(n("nine")), Some(&9));
909            assert_eq!(sub_sub_mbe.get_leaf(n("t")), Some(&teen));
910            assert_eq!(sub_sub_mbe.get_leaf(n("nt")), Some(&-teen));
911            assert_eq!(sub_sub_mbe.get_leaf(n("y")), Some(&big));
912        }
913    }
914
915    let all_zeroes = mbe.map_with(&mbe, &|a, b| a - b);
916    for sub_mbe in all_zeroes.march_all(&vec![n("t"), n("nt"), n("eight")]) {
917        assert_eq!(sub_mbe.get_leaf(n("eight")), Some(&0));
918        assert_eq!(sub_mbe.get_leaf(n("nine")), Some(&0));
919        assert_eq!(sub_mbe.get_leaf(n("t")), Some(&0));
920        assert_eq!(sub_mbe.get_leaf(n("nt")), Some(&0));
921
922        for (sub_sub_mbe, _) in
923            sub_mbe.march_all(&vec![n("y"), n("eight")]).iter().zip(vec![9001, 9002])
924        {
925            assert_eq!(sub_sub_mbe.get_leaf(n("eight")), Some(&0));
926            assert_eq!(sub_sub_mbe.get_leaf(n("nine")), Some(&0));
927            assert_eq!(sub_sub_mbe.get_leaf(n("t")), Some(&0));
928            assert_eq!(sub_sub_mbe.get_leaf(n("nt")), Some(&0));
929            assert_eq!(sub_sub_mbe.get_leaf(n("y")), Some(&0));
930        }
931    }
932
933    assert_eq!(mbe, mbe);
934    assert!(mbe != mbe.map(&mut |x| x - 1));
935    assert_eq!(mbe, mbe.map(&mut |x| x - 0));
936    assert!(mbe != EnvMBE::new());
937    assert!(EnvMBE::new() != mbe);
938
939    assert_eq!(mbe, mbe.map_with(&all_zeroes, &|a, b| a + b));
940    assert_eq!(mbe, all_zeroes.map_with(&mbe, &|a, b| a + b));
941
942    assert_eq!(
943        mbe.map_reduce_with(&all_zeroes, &|a, b| if *a < *b { *a } else { *b }, &|a, b| a + b, 0),
944        -11 + -12 + -13
945    );
946
947    assert_eq!(
948        Err(()),
949        mbe.clone().map(&mut |x: &i32| if *x == 12 { Err(()) } else { Ok(*x) }).lift_result()
950    );
951    assert_eq!(
952        Ok(mbe.clone()),
953        mbe.clone().map(&mut |x: &i32| if *x == 121212 { Err(()) } else { Ok(*x) }).lift_result()
954    );
955
956    let mapped_mbe = mbe.map(&mut |x: &i32| (*x, *x - 9000));
957
958    let first_sub_mbe = &mapped_mbe.march_all(&vec![n("y")])[0];
959
960    assert_eq!(first_sub_mbe.get_leaf(n("y")), Some(&(9001, 1)));
961    assert_eq!(first_sub_mbe.get_leaf(n("eight")), Some(&(8, (8 - 9000))));
962    assert_eq!(first_sub_mbe.get_leaf(n("x")), None);
963
964    // test that phantoms from the previous level don't cause us trouble when repeats are empty
965
966    let mut teens_with_outer = EnvMBE::new_from_anon_repeat(teens_mbe);
967    teens_with_outer.add_leaf(n("outer"), 0);
968    let mut nothing_with_other = EnvMBE::new_from_anon_repeat(vec![]);
969    nothing_with_other.add_leaf(n("outer"), 1);
970
971    let teens_and_nothing =
972        EnvMBE::new_from_anon_repeat(vec![teens_with_outer, nothing_with_other]);
973
974    let mut output = vec![];
975    for outer in teens_and_nothing.march_all(&vec![n("outer")]) {
976        for inner in outer.march_all(&vec![n("t")]) {
977            output.push((
978                inner.get_leaf(n("outer")).map(|x| x.clone()),
979                inner.get_leaf(n("t")).map(|x| x.clone()),
980            ));
981        }
982    }
983    assert_eq!(output, vec![(Some(0), Some(11)), (Some(0), Some(12)), (Some(0), Some(13))]);
984}
985
986#[test]
987fn splice_healing() {
988    use crate::ast::Ast;
989
990    let orig = mbe!(
991        "rator" => (vr "add"), "rand" => [(vr "a"), (vr "b"), (vr "c"), (vr "d")]
992    );
993    let mut noop = orig.clone();
994    noop.heal_splices::<()>(&|_| Ok(None)).unwrap();
995    assert_eq!(noop, orig);
996
997    let mut b_to_xxx = orig.clone();
998    b_to_xxx
999        .heal_splices::<()>(&|a| {
1000            if a == &ast!((vr "b")) {
1001                Ok(Some(vec![ast!((vr "x")), ast!((vr "xx"))]))
1002            } else {
1003                Ok(None)
1004            }
1005        })
1006        .unwrap();
1007    assert_eq!(
1008        b_to_xxx,
1009        mbe!(
1010            "rator" => (vr "add"), "rand" => [(vr "a"), (vr "x"), (vr "xx"), (vr "c"), (vr "d")]
1011        )
1012    );
1013
1014    let steal_from_other =
1015        |a: &Ast, other__a_vec__thunk: &dyn Fn() -> Vec<Ast>| -> Result<Option<Vec<Ast>>, ()> {
1016            if a == &ast!((vr "c")) {
1017                Ok(Some(other__a_vec__thunk()))
1018            } else {
1019                Ok(None)
1020            }
1021        };
1022
1023    let other_short = mbe!(
1024        "rator" => (vr "---"), "rand" => [(vr "1"), (vr "2"), (vr "3")]);
1025
1026    let mut with_short = orig.clone();
1027    assert_eq!(with_short.heal_splices__with::<(), Ast>(&other_short, &steal_from_other), Ok(()));
1028    assert_eq!(with_short, mbe!("rator" => (vr "add"), "rand" => [(vr "a"), (vr "b"), (vr "d")]));
1029
1030    let other_long = mbe!(
1031        "rator" => (vr "---"),
1032        "rand" => [(vr "1"), (vr "2"), (vr "3"), (vr "4"), (vr "5"), (vr "6")]);
1033
1034    let mut with_long = orig.clone();
1035    assert_eq!(with_long.heal_splices__with::<(), Ast>(&other_long, &steal_from_other), Ok(()));
1036    assert_eq!(
1037        with_long,
1038        mbe!("rator" => (vr "add"),
1039        "rand" => [(vr "a"), (vr "b"), (vr "3"), (vr "4"), (vr "5"), (vr "d")])
1040    );
1041
1042    // TODO: require the existence of a constructor like `E::mismatch_error()`
1043    // let other__too_short = mbe!(
1044    // "rator" => (vr "---"),
1045    // "rand" => [(vr "1"), (vr "2")]);
1046    //
1047    // let mut with__too_short = orig.clone();
1048    //
1049    // assert_eq!(with__too_short.heal_splices__with(&other__too_short, &steal_from_other), ???);
1050
1051    // TODO: test this more!
1052}