summary refs log tree commit diff stats
path: root/src/vm/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/mod.rs')
-rw-r--r--src/vm/mod.rs24
1 files changed, 17 insertions, 7 deletions
diff --git a/src/vm/mod.rs b/src/vm/mod.rs
index 2e9d796..9f76ec5 100644
--- a/src/vm/mod.rs
+++ b/src/vm/mod.rs
@@ -353,8 +353,9 @@ pub struct Pack<'pat, 'de> {
 }
 
 impl<'pat, 'de> Pack<'pat, 'de> {
-    /// Merges two packs, with elements from `other` coming after `self`.
-    fn merge_from(&mut self, mut other: Self) {
+    /// Merges two packs, with elements from `other` coming after `self`, as if
+    /// parts of the same iteration.
+    fn merge_breadth(&mut self, mut other: Self) {
         match (self.subpacks.len(), other.subpacks.len()) {
             (0, _) => {
                 *self = other;
@@ -365,14 +366,23 @@ impl<'pat, 'de> Pack<'pat, 'de> {
                     l.extend(r)
                 }
             },
-            _ => unreachable!("merge_from unbalanced iterations"),
+            _ => unreachable!("merge_breadth unbalanced iterations"),
         }
     }
 
-    /// Same as `merge_from` but borrows `other` instead of `self`.
-    fn merge_into(mut self, other: &mut Self) {
-        std::mem::swap(&mut self, other);
-        other.merge_from(self);
+    /// Merges two packs, with elements from `other` coming inside the last
+    /// element of `self` recursively, if any.
+    fn merge_depth(&mut self, mut other: Self) {
+        // note that we can't actually recurse deeper than the VM
+        // actually does itself, so we don't need to worry about
+        // blowing the stack.
+        if let Some(into) = self.subpacks.iter_mut().rev().filter(|map| {
+            !map.is_empty()
+        }).next() {
+            into.last_mut().unwrap().1.0.merge_depth(other);
+        } else {
+            *self = other;
+        }
     }
 }