summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/pattern.rs7
-rw-r--r--src/vm/de.rs187
-rw-r--r--src/vm/mod.rs66
3 files changed, 175 insertions, 85 deletions
diff --git a/src/pattern.rs b/src/pattern.rs
index 6795481..2f7166a 100644
--- a/src/pattern.rs
+++ b/src/pattern.rs
@@ -50,9 +50,14 @@ impl<O: Serialize> Pattern<O> {
             &mut frames,
             //&mut output,
         );
-        let (pack, obj) = vm::Packer::new(interp, MAX_CALLS).deserialize(der)?;
+        let (mut packs, obj) = vm::Packer::new(
+            interp,
+            MAX_CALLS,
+        ).deserialize(der)?;
         // this should always be None
         debug_assert!(obj.is_none());
+        debug_assert!(packs.len() == 1);
+        let pack = packs.pop().unwrap();
         let de = De::deserialize(vm::Unpacker::new(pack, MAX_CALLS));
         todo!()
     }
diff --git a/src/vm/de.rs b/src/vm/de.rs
index 3290ab0..9583962 100644
--- a/src/vm/de.rs
+++ b/src/vm/de.rs
@@ -52,47 +52,9 @@ impl<'packer, 'pat> FramesMut<'packer, 'pat> {
 
     fn iter_active_mut<'a>(&'a mut self) -> impl Iterator<Item=&'a mut Frame<'pat>> where 'packer: 'a {
         self.iter_mut().filter(|frame| {
-            frame.matches()
+            frame.active()
         })
     }
-
-    /// Steps the VM into the next operation.
-    fn step_in(&mut self) {
-        self.iter_mut().for_each(|frame| {
-            if let Some(ref mut overstep) = frame.overstep {
-                *overstep += 1;
-            } else {
-                if !frame.next() {
-                    frame.overstep = Some(1);
-                } else if matches!(
-                    frame.op(),
-                    PatternElement::ValueSubtree { .. },
-                ) {
-                    todo!()
-                }
-            }
-        });
-    }
-
-    fn step_out<'de>(&mut self, pack: Pack<'pat, 'de>) -> Pack<'pat, 'de> {
-        self.iter_mut().for_each(|frame| {
-            if let Some(ref mut overstep) = frame.overstep {
-                if *overstep > 0 {
-                    *overstep -= 1;
-                }
-            } else {
-                if let Some(0) = frame.overstep {
-                    frame.overstep = None;
-                }
-                if frame.overstep.is_none() {
-                    if frame.prev() {
-                        todo!();
-                    }
-                }
-            }
-        });
-        pack
-    }
 }
 
 impl<'packer, 'pat> Frames<'packer, 'pat> {
@@ -102,7 +64,7 @@ impl<'packer, 'pat> Frames<'packer, 'pat> {
 
     fn iter_active<'a>(&'a self) -> impl Iterator<Item=&'a Frame<'pat>> where 'packer: 'a {
         self.iter().filter(|frame| {
-            frame.matches()
+            frame.active()
         })
     }
 }
@@ -131,33 +93,118 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> {
             frames: &*self.interp.frames,
         }
     }
-}
 
-// what steps do we have to take?
-//
-//  1. figure out what type we need to deserialize (and ask the deserializer
-//      for it).
-//  2. visit value. figure out whether we need to store it or not?
-//  3. if we need to store it how do we figure out *where* to store it?
-//  4. if we *don't* need to store it, what do we do?
-//  5. how do we tell if we do or don't need to store it? how do we propagate
-//      those requirements deeper into the Deserialize's and how do we bring
-//      the values back out (recursively?) to parent Deserialize's, without
-//      wasting time storing things we don't actually care about?
-//      5.a. just have a flag in the DeserializeSeed for whether to capture the
-//          values. propagation is more or less trivial from there.
-//  6. how do you handle value subtrees?
-//      6.a. you don't. for now.
-//  7. how do you handle errors?
-//      7.a. put them into a "state" and raise a D::Error::custom. then
-//          override it in the relevant Pattern call.
+    /// Steps the VM into the next operation.
+    fn step_in(&mut self) {
+        // iterate up to the *live* length (i.e. the loop is allowed to modify
+        // the length).
+        // NOTE: we need to use while-let so as to not borrow anything in an
+        // iterator. filtering happens on the *result* of the iterator.
+        let mut index_iter = 0..;
+        while let Some(index) = index_iter.next().filter(|&i| {
+            i < self.interp.frames.len()
+        }) {
+            let frame = &mut self.interp.frames[index];
+            if frame.overstep > 0 || !frame.matches {
+                // overstepped and non-matching frames
+                frame.overstep += 1;
+            } else {
+                if !frame.next() {
+                    // empty/end-of frames
+                    // 1 layer of step-in.
+                    // step-out will undo this.
+                    // this is correct because this branch implies overstep = 0
+                    frame.overstep = 1;
+                } else if matches!(
+                    frame.op(),
+                    PatternElement::SubtreeMarker,
+                ) {
+                    // subtrees!
+                    // these are tricky, because the current frame can be moved
+                    // in memory. so we have to use indexing every time.
+                    // tho first we set it as overstep because it has special
+                    // handling.
+                    frame.overstep = 1;
+                    let mut at = index + 1;
+                    while self.interp.frames[index].next() {
+                        let op = self.interp.frames[index].op();
+                        if let PatternElement::ValueSubtree {
+                            index: subtree, ..
+                        } = op {
+                            let new_frame = Frame {
+                                ops: &self.interp.pat.protos[subtree][..],
+                                iar: None,
+                                overstep: 0,
+                                matches: true,
+                            };
+                            // we want the "newest" frame last, so it is
+                            // easier to unwind back.
+                            self.interp.frames.insert(at, new_frame);
+                            at += 1;
+                        } else {
+                            unreachable!()
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /// Steps the VM back into the previous operation.
+    fn step_out(
+        &mut self,
+        mut packs: Vec<Pack<'pat, 'de>>,
+    ) -> Vec<Pack<'pat, 'de>> {
+        let mut index_iter = 0..;
+        while let Some(index) = index_iter.next().filter(|&i| {
+            i < self.interp.frames.len()
+        }) {
+            // iterate backwards
+            let index = self.interp.frames.len() - index - 1;
+            let frame = &mut self.interp.frames[index];
+            if frame.overstep > 0 {
+                // handle overstep
+                frame.overstep -= 1;
+            } else {
+                // unwind frame
+                if frame.prev() {
+                    // successfully unwound. do nothing.
+                } else {
+                    // find parent frame.
+                    let mut count = 1;
+                    let mut target = index;
+                    while count > 0 && target > 0 {
+                        target -= 1;
+                        match self.interp.frames[target].num_subtrees() {
+                            Some(num) if num <= count => {
+                                count -= num;
+                            },
+                            Some(num) => {
+                                count = 0;
+                            },
+                            None => {
+                                count += 1;
+                            },
+                        }
+                    }
+                    if count == 0 {
+                        // has parent frame
+                        let pack = packs.remove(index);
+                        todo!("merge packs")
+                    }
+                }
+            }
+        }
+        packs
+    }
+}
 
 impl<'pat, 'state, 'de, O> serde::de::DeserializeSeed<'de>
 for &mut Packer<'pat, 'state, O>
 where
     O: Serialize,
 {
-    type Value = (Pack<'pat, 'de>, Option<SerdeObject<'de>>);
+    type Value = (Vec<Pack<'pat, 'de>>, Option<SerdeObject<'de>>);
     fn deserialize<D>(
         mut self,
         deserializer: D,
@@ -165,7 +212,7 @@ where
     where
         D: serde::Deserializer<'de>
     {
-        self.frames_mut().step_in();
+        self.step_in();
         let pat = self.interp.pat;
         let target_type = self.frames().iter_active().fold(
             Type::IgnoredAny,
@@ -248,7 +295,7 @@ where
             Type::Enum { name, variants } => {
                 deserializer.deserialize_enum(name, variants, &mut *self)
             },
-        }.map(|(pack, obj)| (self.frames_mut().step_out(pack), obj))
+        }.map(|(packs, obj)| (self.step_out(packs), obj))
     }
 }
 
@@ -265,16 +312,18 @@ macro_rules! vs {
             if self.collecting {
                 obj = Some(SerdeObject::$obj(v));
             }
-            let mut pack = Pack::default();
+            let mut packs = Vec::new();
             self.frames_mut().iter_active_mut().try_for_each(|frame| {
+                let mut pack = Pack::default();
                 let mut map = IndexMap::new();
                 if let Some(name) = frame.get_name(pat) {
                     map.insert(name, (Pack::default(), SerdeObject::$obj(v)));
                 }
                 pack.subpacks.push(map);
+                packs.push(pack);
                 Ok(())
             })?;
-            Ok((pack, obj))
+            Ok((packs, obj))
         }
     }
 }
@@ -284,7 +333,7 @@ for &mut Packer<'pat, 'state, O>
 where
     O: Serialize,
 {
-    type Value = (Pack<'pat, 'de>, Option<SerdeObject<'de>>);
+    type Value = (Vec<Pack<'pat, 'de>>, Option<SerdeObject<'de>>);
     fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "unsure")
     }
@@ -390,6 +439,7 @@ where
     {
         // FIXME subtrees
         let mut obj = None;
+        let mut packs = Vec::new();
         let mut pack = Pack::default();
         if self.collecting {
             obj = Some(SerdeObject::Unit);
@@ -399,7 +449,8 @@ where
         //    map.insert(name, (Default::default(), SerdeObject::Unit));
         //}
         pack.subpacks.push(map);
-        Ok((pack, obj))
+        packs.push(pack);
+        Ok((packs, obj))
     }
     fn visit_newtype_struct<D>(
         self,
@@ -633,9 +684,9 @@ mod tests {
         let mut frames = Default::default();
         let interp = Interpreter::new(&consts, &mut err, &mut frames);
         let packed = Packer::new(interp, MAX_CALLS).deserialize(&mut der);
-        let (pack, obj) = packed.unwrap();
+        let (packs, obj) = packed.unwrap();
         assert!(obj.is_none());
-        assert_eq!(pack.subpacks[0]["hello"].1, SerdeObject::U64(3));
+        assert_eq!(packs[0].subpacks[0]["hello"].1, SerdeObject::U64(3));
     }
 }
 
diff --git a/src/vm/mod.rs b/src/vm/mod.rs
index 8122778..dca15a9 100644
--- a/src/vm/mod.rs
+++ b/src/vm/mod.rs
@@ -95,6 +95,8 @@ pub(crate) enum PatternElement {
         /// expected value of this entry.
         name_and_value: These<usize, Value>,
     },
+    /// Marks the end of pattern iteration and the start of subtrees (if any).
+    SubtreeMarker,
     /// A value subtree is a subtree for values.
     ///
     /// It is applied *after* tags, and thus any value subtrees come last in
@@ -102,10 +104,10 @@ pub(crate) enum PatternElement {
     ValueSubtree {
         /// The proto index of the subtree.
         index: usize,
-        /// Whether to allow this value subtree to produce no results.
+        /// Whether to allow this value subtree to match nothing.
         ///
         /// By default, a datafu pattern only matches a tree if every branch of
-        /// the tree produces results. This enables opting out of that.
+        /// the tree matches something. This enables opting out of that.
         optional: bool,
     },
 }
@@ -292,15 +294,16 @@ pub(crate) enum SerdeObject<'de> {
 }
 
 impl<'de> SerdeObject<'de> {
-    fn check<E: serde::de::Error>(self, ty: Option<Type>) -> Result<Self, E> {
+    /// Checks the type of this object.
+    fn check<E: serde::de::Error>(&self, ty: Option<Type>) -> Result<(), E> {
         let ty = match ty {
-            None => return Ok(self),
+            None => return Ok(()),
             Some(ty) => ty,
         };
         match (ty, self) {
             | (Type::Any, v)
             | (Type::IgnoredAny, v)
-            => Ok(v),
+            => Ok(()),
             | (Type::Bool, v @ SerdeObject::Bool(_))
             | (Type::I8, v @ SerdeObject::I8(_))
             | (Type::I16, v @ SerdeObject::I16(_))
@@ -324,7 +327,7 @@ impl<'de> SerdeObject<'de> {
             | (Type::Unit, v @ SerdeObject::Unit)
             | (Type::Seq, v @ SerdeObject::Seq(_))
             | (Type::Map, v @ SerdeObject::Map(_))
-            => Ok(v),
+            => Ok(()),
             _ => todo!(),
         }
     }
@@ -358,8 +361,6 @@ pub(crate) struct Interpreter<'pat, 'state, O: Serialize> {
     error: &'state mut Option<crate::errors::MatchError>,
     /// The current interpreter frames.
     frames: &'state mut Vec<Frame<'pat>>,
-    ///// The final output.
-    //output: &'state Cell<Pack<'pat, 'de>>,
 }
 
 pub(crate) struct Frame<'pat> {
@@ -367,10 +368,12 @@ pub(crate) struct Frame<'pat> {
     ops: &'pat [PatternElement],
     /// The instruction index being processed.
     iar: Option<usize>,
-    /// How many steps this frame has failed to match.
-    overstep: Option<usize>,
-    ///// Elements collected while processing this frame?
-    //path: Pack<'pat, 'de>,
+    /// How many steps this frame has not actually advanced for.
+    ///
+    /// This is used at end of frame and on match failure.
+    overstep: usize,
+    /// Whether this frame matches the data so far.
+    matches: bool,
 }
 
 impl<'pat, 'state, O: Serialize> Interpreter<'pat, 'state, O> {
@@ -384,7 +387,8 @@ impl<'pat, 'state, O: Serialize> Interpreter<'pat, 'state, O> {
         frames.push(Frame {
             ops: &pat.protos[0],
             iar: None,
-            overstep: None,
+            overstep: 0,
+            matches: true,
             //path: Default::default(),
         });
         Self {
@@ -461,12 +465,42 @@ impl<'pat> Frame<'pat> {
     ///
     /// Panics if called on a non-matching frame or if iteration hasn't begun.
     fn op(&self) -> PatternElement {
-        assert!(self.matches(), "op() called on non-matching frame");
+        assert!(self.active(), "op() called on inactive frame");
+        self.ops[self.iar.expect("ops[iar]")]
+    }
+
+    /// Counts the number of *active* subtrees, if any.
+    ///
+    /// # Panics
+    ///
+    /// Panics if iteration hasn't begun.
+    fn num_subtrees(&self) -> Option<usize> {
+        let iar = self.iar.expect("iar");
+        // check if there are any subtrees
+        matches!(
+            self.ops[iar],
+            | PatternElement::ValueSubtree { .. }
+            | PatternElement::SubtreeMarker
+        ).then(|| {
+            // count the number of subtrees
+            self.ops[0..=iar].iter().rev().take_while(|x| {
+                matches!(x, PatternElement::ValueSubtree { .. })
+            }).count()
+        })
+    }
+
+    /// Returns the raw instruction.
+    ///
+    /// # Panics
+    ///
+    /// Panics if iteration hasn't begun.
+    fn raw_op(&self) -> PatternElement {
         self.ops[self.iar.expect("ops[iar]")]
     }
 
-    fn matches(&self) -> bool {
-        self.overstep.is_none()
+    /// Returns whether this frame is active (not overstepped).
+    fn active(&self) -> bool {
+        self.overstep == 0
     }
 
     /// Rewinds the instruction address register.